17
\$\begingroup\$

Multiplication between 2 integers can be reduced into a series of addition like so

3 * 5 = 3 + 3 + 3 + 3 + 3 = 5 + 5 + 5

Exponentiation (raising a to the power b) can also be reduced into a series of multiplications:

5 ^ 3 = 5 * 5 * 5

Therefore, exponentiation can be reduced into a series of additions, by creating a multiplication expression, then into a series of additions. For example, 5 ^ 3 (5 cubed) can be rewritten as

5 ^ 3 = 5 * 5 * 5
      = (5 + 5 + 5 + 5 + 5) * 5
      = (5 + 5 + 5 + 5 + 5) + (5 + 5 + 5 + 5 + 5) + (5 + 5 + 5 + 5 + 5) + (5 + 5 + 5 + 5 + 5) + (5 + 5 + 5 + 5 + 5)
      = 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5

Your task is, given expressions added together consisting of exponentiation, multiplication and addition, reduce it to the shortest series of additions. The "shortest" expression is defined as the expression with the fewest number of + symbols, still using only one of the two numbers in the original expression. For example, the shortest expression of 10 * 2 is 10 + 10.

The numbers involved in the input will all be positive integers, and the expression will consist of only + (addition), * (multiplication) and ^ (exponentiation), along with integers and brackets (()) to indicate precedence.

The output should consist of positive integers and + symbols only. You shouldn't output the individual steps of the reductions, just the final output. The output may not consist of any numbers that don't appear in the input. However, you may use any 3 distinct symbols instead of +*^, but please say what symbols they are

The spaces separating inputs and outputs may or may not be used in your programs, i.e. 3 * 5 can be outputted as either 5 + 5 + 5 or 5+5+5.

Note that in most cases, addition is not actually performed. The only case where addition is to be performed is when you have something like 5 ^ (1 + 2), in which case, addition is necessary to continue -> 5 ^ 3 -> 5 * 5 * 5 -> .... See test case #4.

Your code does not need to handle inputs that arrive at an ambiguous expression. For example, (2 + 2) * (4 + 1). Because of the rules set forth so far, the goal is not to calculate the answer, the goal is to simplify to additions. So the result could be different depending on the order that expressions are resolved or commuted (which additions to simplify, which to leave?). Another invalid example: ((3 + 2) ^ 2) ^ 3 -> ((3 + 2) * (3 + 2)) ^ 3 -> ???.

This is so shortest code wins

Test cases

Input => output

5 ^ 3 + 4 * 1 ^ 5 => 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 4
2 ^ 1 * 2 + 3 + 9 => 2 + 2 + 3 + 9
2 ^ 1 * (2 + 3) + 9 => 2 + 3 + 2 + 3 + 9
2 ^ (1 * (2 + 3)) + 9 => 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 9
10 + 3 * 2 + 33 ^ 2 => 10 + 3 + 3 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33 + 33
100 * 3 => 100 + 100 + 100
2 ^ 1 + 2 ^ 1 + 2 ^ 2 + 8 ^ 1 => 2 + 2 + 2 + 2 + 8
(1 + 2 + 5 * 8 + 2 ^ 4) * 2 => 1 + 2 + 8 + 8 + 8 + 8 + 8 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + 2 + 8 + 8 + 8 + 8 + 8 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2
\$\endgroup\$
  • \$\begingroup\$ May we use ** instead of ^? \$\endgroup\$ – Erik the Outgolfer Oct 4 '17 at 17:36
  • \$\begingroup\$ @EriktheOutgolfer yeah, that seems fair. \$\endgroup\$ – caird coinheringaahing Oct 4 '17 at 17:38
  • \$\begingroup\$ Related. \$\endgroup\$ – Martin Ender Oct 5 '17 at 8:31
  • 1
    \$\begingroup\$ I'm still confused as to what constitutes valid output. In the question you say using only one of the two numbers in the original expression. but the original expression can have more than two numbers. I don't get why 8 + 8 is not a valid output for 2 ^ 1 + 2 ^ 1 + 2 ^ 2 + 8 ^ 1. This question is still pretty unclear to me. \$\endgroup\$ – Sriotchilism O'Zaic Oct 10 '17 at 3:20
6
\$\begingroup\$

Retina, 302 bytes

I'm sure this can be golfed, but at this point, I'm just glad it works. The exponentiation and multiplication sections are both very similar, but since order of operations is important, I don't know how to combine them.

y - Exponentiation
x - Multiplication
p - Addition

\d+
$*
{1`(\(\w+\)|1+)y(\(\w+\)|1+)
>$0<
(?<=>(\(\w+\)|1+)y1*)1
$1x
>(\(\w+\)|1+)y
(
x<
)
\((1+(x1+)*)\)(?!y)
$1
(?<!1)(1+)x(\(\w+\)|1+\1)(?!1)
$2x$1
1`(\(\w+\)|1+)x1+
>$0<
(?<=>(\(\w+\)|1+)x1*)1
$1p
>(\(\w+\)|1+)x
(
p<
)
(?<!x|y)\((1+(p1+)*)\)(?!x|y)
$1
y\((1+)p([1p]*\))
y($1$2
}`y\((1+)\)
y$1
1+
$.0

Try it online - all test cases

Test case converter

Explanation

\d+                             Convert to unary
$*
{1`(\(\w+\)|1+)y(\(\w+\)|1+)    Begin loop: Delimit current exponentiation group
>$0<
(?<=>(\(\w+\)|1+)y1*)1          Replace exponentiation with multiplication
$1x
>(\(\w+\)|1+)y                  Replace garbage with parentheses
(
x<
)
\((1+(x1+)*)\)(?!y)             Remove unnecessary parentheses around multiplication
$1
(?<!1)(1+)x(\(\w+\)|1+\1)(?!1)  Maybe swap order of multiplicands
$2x$1
1`(\(\w+\)|1+)x1+               Delimit current multiplication group
>$0<
(?<=>(\(\w+\)|1+)x1*)1          Replace multiplication with addition
$1p
>(\(\w+\)|1+)x                  Replace garbage with parentheses
(
p<
)
(?<!x|y)\((1+(p1+)*)\)(?!x|y)   Remove unnecessary parentheses around addition
$1
y\((1+)p([1p]*\))               Handle the 4th test case by adding if necessary
y($1$2
}`y\((1+)\)                     End of loop
y$1
1+                              Convert unary back to decimal
$.0

You may also notice that the most commonly used group is (\(\w+\)|1+). This matches an inner expression with parentheses, or an integer. I chose to use the symbols I did so that I could use \w rather than a character class. I'm not sure if it would be better to use non-word symbols and replace some lookarounds with word borders (\b).

\$\endgroup\$
5
\$\begingroup\$

Mathematica, 250 218 183 170 bytes

f~(s=SetAttributes)~HoldAll;{a,t}~s~Flat;f@n_:=Infix[Hold@n//.{a_~Power~b_:>t@@Hold@a~Table~b,Times->t,Plus->a,Hold->Dot}/.t->(a@@Table[#,1##2]&@@Reverse@Sort@{##}&),"+"]

It works! Finally!

Defines the function in f.

The input is a plain math expression. (i.e. 1 + 2 not "1 + 2").

Try it Online!

Note that the TIO link has a slightly different code, as TIO (which, I presume, uses Mathematica kernel) doesn't like Infix. I used Riffle instead to get the same appearance as Mathematica REPL.

Ungolfed

f~(s = SetAttributes)~HoldAll;  (* make f not evaluate its inputs *)

{a, t}~s~Flat;  (* make a and t flat, so that a[a[1,a[3]]] == a[1,3] *)

f@n_ :=  (* define f, input n *)

 Infix[

  Hold@n  (* hold the evaluation of n for replacement *)

    //. {  (* expand exponents *)

     (* change a^b to t[a,a,...,a] (with b a's) *)
     a_~Power~b_ :> t @@ Hold@a~Table~b,

     (* Replace Times and Plus with t and a, respectively *)
     Times -> t, 
     Plus -> a, 

     (* Replace the Hold function with the identity, since we don't need
         to hold anymore (Times and Plus are replaced) *)
     Hold -> Dot 

     } /.  (* Replace; expand all t (= `Times`) to a (= `Plus`) *)

        (* Take an expression wrapped in t. *)
        (* First, sort the arguments in reverse. This puts the term
            wrapped in `a` (if none, the largest number) in the front *)
        (* Next, repeat the term found above by <product of rest
            of the arguments> times *)
        (* Finally, wrap the entire thing in `a` *)
        (* This will throw errors when there are multiple elements wrapped
           in `a` (i.e. multiplying two parenthesized elements) *)
        t -> (a @@ Table[#, 1 ##2] & @@
               Reverse@Sort@{##} &),

  "+"]  (* place "+" between each term *)
\$\endgroup\$
  • 6
    \$\begingroup\$ Ok, I'm happy I created a challenge that Mathematica doesn't have a built in for :P \$\endgroup\$ – caird coinheringaahing Oct 4 '17 at 20:11
3
\$\begingroup\$

Mathematica, 405 406 bytes

f~SetAttributes~HoldAll;p=(v=Inactive)@Plus;t=v@Times;w=v@Power;f@x_:=First@MinimalBy[Inactivate@{x}//.{w[a___,b_List,c___]:>(w[a,#,c]&/@b),t[a___,b_List,c___]:>(t[a,#,c]&/@b),p[a___,b_List,c___]:>(p[a,#,c]&/@b),p[a_]:>a,w[a_,b_]:>t@@Table[a,{Activate@b}],t[a___,t[b__],c___]:>t[a,b,c],p[a___,p[b__],c___]:>p[a,b,c],{a___,{b__},c___}:>{a,b,c},t[a__]:>Table[p@@Table[i,{Activate[t@a/i]}],{i,{a}}]},Length];f

Ungolfed and explained

SetAttributes[f, HoldAll]
p = Inactive[Plus]; t = Inactive[Times]; w = Inactive[Power];
f[x_] := First@MinimalBy[
   Inactivate[{x}] //. {
     w[a___, b_List, c___] :> (w[a, #, c] & /@ b),
     t[a___, b_List, c___] :> (t[a, #, c] & /@ b),
     p[a___, b_List, c___] :> (p[a, #, c] & /@ b),
     (* distribute lists of potential expansions over all operations *)
     p[a_] :> a,
     (* addition of a single term is just that term *)
     w[a_, b_] :> t @@ Table[a, {Activate@b}],
     (* a^b simplifies to a*a*...*a b times no matter what b is *)
     t[a___, t[b__], c___] :> t[a, b, c],
     p[a___, p[b__], c___] :> p[a, b, c],
     {a___, {b__}, c___} :> {a, b, c},
     (* operations are associative *)
     t[a__] :> Table[p @@ Table[i, {Activate[t@a/i]}], {i, {a}}]
     (* for a product, generate a list of potential expansions *)}
   , Length]
f

I went to a great deal of trouble to get the following effect: this function takes as input a standard Mathematica expression, with the usual +, *, and ^ operations (and parentheses) in it, and outputs what looks like a standard Mathematica expression (but with "deactivated" plus signs) as the answer.

The function above begins by deactivating all operations in the input. Then, it applies expansion rules repeatedly until nothing can be simplified anymore. Whenever it encounters a product such as 2 * 3 * 4, which can be expanded in multiple ways, it makes a list of possible expansions, and keeps going. At the end, we get a list of possible final answers, and the shortest is picked.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.