# Avoid creation of OwnValues when inserting transformation rules into ExperimentalOptimizeExpression

I have a large list of transformation rules that I want to simplify.

I find ExperimentalOptimizeExpression works as it gets me the answers.

My question is:

I can only get this to work when I convert my list of rules into a list of assignments - which is obviously what i want to avoid doing - by using

list1 /.Rule -> Set


How can I avoid making the assignments and still useExperimentalOptimizeExpression?

I have a solution that gives me the outcome, I want to avoid the side effect of the assignments. Whilst alternative solutions are appreciated, the real issue I have is the side effect that assigns values to the symbols in the rule sets!

I apologise for my incompetence making this clear.

For example

list1 = {a -> b + c, d -> b + c};
list2 = {b -> 1, c -> 1};
ExperimentalOptimizeExpression[{list1 /. Rule -> Set, list2 /. Rule -> Set}];
%[[1, 2]]

(* Out= {{2, 2}, {1, 1}} *)


This does indeed simplify my list of transformation rules, however the assignment has some drawbacks as my rules are now evaluating, which I clearly do not want. I am creating OwnValues for each individual transformation rule, effectively disabling the transformation rules.

list1
list2
(* Out= {2 -> 2, 2 -> 2} *)
(* Out= {1 -> 1, 1 -> 1} *)


PLEASE NOTE THE DESIRED RESULT SHOULD BE

(* Out= {a -> b + c, d -> b + c} *)
(* Out= {b -> 1, c -> 1}; *)


I can clear the assignments, and then all works fine, but there must be a more elegant solution.

Clear[a, b, c, d]
list1
list2

(* Out= {a -> b + c, d -> b + c} *)
(* Out= {b -> 1, c -> 1} *)


Now there have kindly been several alternative solutions for the above example provided and I have tried a lot myself as well, however I cannot get any of them to work with the full set of lists which is more complex (and imported from another application so it looks a bit messy):

lists = {v -> v, v -> v, v -> v, v -> v*v,
v -> v, v -> v, v -> v, v -> v + v - v,
v -> v, v -> v, v -> 0.25, v -> 14, v -> 100000000,
v -> 5, v -> 2000000000000, v -> 1, v -> 400000000000,
v -> 200000000000, v -> 0.5, v -> 0.7, v -> -1, v -> 0.03,
v -> 0.05, v -> 333, v -> 222, v -> 0.3, v -> 0.01,
v -> 1000, v -> 0.0175, v -> 0, v -> 0, v -> 0, v -> 0,
v -> 0, v -> 0, v -> 0, v -> 1, v -> 0, v -> 3,
v -> 0.4, v -> 0.0625, v -> 0.4, v -> 0.25, v -> 0.25,
v -> 2.5, v -> 0.5, v -> 2.5, v -> 4, v -> 0.0625,
v -> v/v + v + v + v + (-v + v)/v,
v -> v*v, v -> v*v*v, v -> v*v*v,
v -> v + (1 - v)*v + v*v - v,
v -> (v*v)/(v^(-1) + v), v -> ((1 - v)*v)/v,
v -> v v, v -> (v - v)/v, v -> v + v,
v -> v + v, v -> v,
v -> v[
34]/((v/v)^(v/v) ((v*v)/(v*v))^v^(-1)),
v -> (v + v)/v,
v -> -(v/v) + (1 - v)*v + v*v,
v -> v - v + ((-v + v)*v)/(v v),
v -> (v/v)^v (v/v)^(1 - v)*v,
v -> (v - v)/(v*v),
v -> -(v/v) - v - v + (1 - v)*v +
v v - (-v + v)/v, v -> v (1 + v v),
v -> (v + v) (1 - v) +
v*((1 - v)*v + v*v) v,
v -> ((-v + v/(1 - v)) (1 - v))/v,
v -> (-(v/v) + v)/v, v -> (v*v)/(v^(-1) + v),
v -> (v*v)/v, v -> ((1 - v)*v)/v};


Daniel Lichtblau's suggestion was:

polys = lists /. Rule -> Subtract;
vars = Cases[lists, _Symbol, Infinity] // Union;
gb = GroebnerBasis[polys, vars];
reds = PolynomialReduce[vars, gb, vars][[All, 2]];


(* Out = {v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., v -> 0., ...*)

I am most likely missing the point (Groebnerbasis[] are not something I am familiar with) but this is not the desired result.

Te compare with an approach using ExperimentalOptimizeExpression, this provides the expected outcome, but I assign values to symbols to make it work (undesirable):

blocks = lists;
Block[{blocks2 = blocks /. Rule -> Set},
res=ExperimentalOptimizeExpression[blocks2]];
res[]


(* Out = {2000000000000, 4.92958*10^12, 100000000, 6.*10^11, 0.05, 2000000000000, 400000000000, 1.6*10^12, 1, 2000000000000, 0.25, 14, 100000000, 5, 2000000000000, ...} *)

And the illustration how the assignments make the symbols in the original rules evaluate, thereby making the transformation list useless:

Thread[vars->res[]]


(* Out = {2000000000000 -> 2000000000000, 4.92958*10^12 -> 4.92958*10^12, 100000000 -> 100000000, 6.*10^11 -> 6.*10^11, 0.05 -> 0.05...} *)

Without having to resort to assigning via /.Rule->Set I would have gotten the correct answer:

(* Out = {v -> 2000000000000, v -> 4.92958*10^12, v -> 100000000, v -> 6.*10^11, v -> 0.05, v -> 2000000000000, v -> 400000000000, v -> 1.6*10^12, v -> 1, ...} *)

• I tried scoping (Block and Module) as well as several nonstandard evaluation tricks but I am missing something obvious (or less likely, ran into something nontrivial). – Sander Aug 14 '14 at 8:35
• You wrote I convert these into equations, this is not true. An equation in Mathematica is something like lhs==rhs but you use Set (=, only one =) which is the assignment operator. I'm pretty sure that you don't want this in the first place. – halirutan Aug 14 '14 at 10:06
• Thanks, I guess this is my struggle: how to avoid making an assignment and still use ExperimentalOptimizeExpression to simplify a list of rules. – Sander Aug 14 '14 at 10:08
• I'm sorry, but this question still doesn't make any sense. You still have not shown real input or described the output that you want. ExperimentalOptimizeExpression does not require "a list of assignments" even if that is what your code produced, which as halirutan explains it does not. Give an example of the simplified rules that you expect as output or this question cannot be answered. – Mr.Wizard Aug 14 '14 at 10:35
• @Mr.Wizard Thanks for explaining that ExperimentalOptimizeExpression does not require assignments per se. Trying to inject assignments caused the problems in the first place, so if this is not required, the problem will go away.. – Sander Aug 14 '14 at 12:18

## Update

Following the new examples you gave I believe this does what you want:

Thread[lists[[All, 1]] -> (lists[[All, 2]] //. lists)]


Or somewhat more cleanly:

MapAt[# //. lists &, lists, {All, 2}]


Or tersely:

# -> (#2 //. lists) & @@@ lists


Output:

{v -> 2000000000000, v -> 4.92958*10^12, v -> 100000000, v -> 6.*10^11,
v -> 0.05, v -> 2000000000000, v -> 400000000000, v -> 1.6*10^12,
v -> 1, v -> 2000000000000, v -> 0.25, v -> 14, v -> 100000000,
v -> 5, v -> 2000000000000, v -> 1, v -> 400000000000,
v -> 200000000000, v -> 0.5, v -> 0.7, v -> -1, v -> 0.03,
v -> 0.05, v -> 333, v -> 222, v -> 0.3, v -> 0.01, v -> 1000,
v -> 0.0175, v -> 0, v -> 0, v -> 0, v -> 0, v -> 0, v -> 0,
v -> 0, v -> 1, v -> 0, v -> 3, v -> 0.4, v -> 0.0625,
v -> 0.4, v -> 0.25, v -> 0.25, v -> 2.5, v -> 0.5, v -> 2.5,
v -> 4, v -> 0.0625, v -> 2.*10^12, v -> 1.24789*10^12, v -> 0,
v -> 0, v -> 1.6*10^12, v -> 4.92958*10^12, v -> 1.*10^8,
v -> 6.*10^11, v -> 0., v -> 400000000000, v -> 200000000000,
v -> 0.05, v -> 0.03, v -> 3/10, v -> 1.64789*10^12,
v -> -1.38778*10^-17, v -> 2.*10^12, v -> 0., v -> 0.000244141,
v -> 400000000000, v -> 6.*10^11, v -> 0.05, v -> 0.77993,
v -> 4.92958*10^12, v -> 400000000000, v -> 15000.}


The left-hand sides of the rules do not match but the values (right-hand sides) do with only a couple of exceptions and with small variance. I believe this is correct and your example output is in error. If however the order of your rules is truly what you want you will need to sort the left-hand-sides separately:

Thread[Sort @ lists[[All, 1]] -> (lists[[All, 2]] //. lists)]


Output:

{v -> 2000000000000, v -> 4.92958*10^12, v -> 100000000, v -> 6.*10^11,
v -> 0.05, v -> 2000000000000, v -> 400000000000, v -> 1.6*10^12, v -> 1,
v -> 2000000000000, v -> 0.25, v -> 14, v -> 100000000, v -> 5,
v -> 2000000000000, v -> 1, v -> 400000000000, v -> 200000000000,
v -> 0.5, v -> 0.7, v -> -1, v -> 0.03, v -> 0.05, v -> 333,
v -> 222, v -> 0.3, v -> 0.01, v -> 1000, v -> 0.0175, v -> 0,
v -> 0, v -> 0, v -> 0, v -> 0, v -> 0, v -> 0, v -> 1,
v -> 0, v -> 3, v -> 0.4, v -> 0.0625, v -> 0.4, v -> 0.25,
v -> 0.25, v -> 2.5, v -> 0.5, v -> 2.5, v -> 4, v -> 0.0625,
v -> 2.*10^12, v -> 1.24789*10^12, v -> 0, v -> 0, v -> 1.6*10^12,
v -> 4.92958*10^12, v -> 1.*10^8, v -> 6.*10^11, v -> 0.,
v -> 400000000000, v -> 200000000000, v -> 0.05, v -> 0.03,
v -> 3/10, v -> 1.64789*10^12, v -> -1.38778*10^-17, v -> 2.*10^12,
v -> 0., v -> 0.000244141, v -> 400000000000, v -> 6.*10^11,
v -> 0.05, v -> 0.77993, v -> 4.92958*10^12, v -> 400000000000,
v -> 15000.}


I don't know what you mean when you write: "Exactly what I am looking for ..." as I don't know what output you expect from your operation. If you merely want {{2, 2}, {1, 1}} as the output then:

list1 = {a -> b + c, d -> b + c};
list2 = {b -> 1, c -> 1};

{list1, list2} /. list2 // Values

{{2, 2}, {1, 1}}


Can you give a different example where OptimizeExpression is necessary?

• Thanks for looking into this and apologies for stating the problem not clear enough. I am trying to avoid the creation of OwnValues as these create a side effect when I want to use the transformation list after the optimization. (a->b+c evaluates to 2->2). That is the problem I am experiencing. The example in itself is less relevant as it works well (which is what I mean with "exactly what I am looking for"), even with the 1000 odd rules I am simplifying with it. – Sander Aug 14 '14 at 9:45
• @Sander I still need to see an example of the actual input and output that you desire. As it is written I can't tell what isn't the undesirable side effect. What is your desired output? – Mr.Wizard Aug 14 '14 at 9:53
• Desired output is for OwnValues@a to be undefined as it is before I call the Optimization. (* in= OwnValues@a Out= {HoldPattern[a] :> b + c} *). The same for OwnValues of b to d as they change my list1 and list2 of symbols into expressions that evaluate. – Sander Aug 14 '14 at 9:59
• Seems my question can be posed much simpler. Will update now. – Sander Aug 14 '14 at 10:05
• Thanks; amazing how I got bogged down resolving the assignment side effects when there was a much more elegant solution. – Sander Aug 15 '14 at 4:13

As others have noted, it's not entirely clear what you want. A possibility is you want to "simplify" the rules so that, on application, all four variables would give numbers. I'll show a way to obtain that and possibly you can modify to suit the actual need.

We'll start with the lists of rules and create defining polynomials and also extract the variables (trivial here but one would want this automated for large problems).

list1 = {a -> b + c, d -> b + c};
list2 = {b -> 1, c -> 1};
polys = Flatten[{list1, list2} /. Rule -> Subtract]
vars = Variables[polys]

(* Out= {a - b - c, -b - c + d, -1 + b, -1 + c}

Out= {a, b, c, d} *)


Now create a Groebner bases and use it to reduce all the variables.

gb = GroebnerBasis[polys, vars];
reds = PolynomialReduce[vars, gb, vars][[All, 2]]

(* {a - b - c, -b - c + d, -1 + b, -1 + c}

{2, 1, 1, 2} *)


Now we create new rules for all variables, with their reduced values on the right hand sides.

newrules = Thread[vars -> reds]
(* {a -> 2, b -> 1, c -> 1, d -> 2} *)


Hope that gives a start in the right direction, whatever that direction might be.

--- edit ---

Prompted in comments, I'll add a bigger example. It's random but it's indicative of the type of issues one can get into when faced with rules that might have interdependencies.

First we create a random set of rules that involve replacements amongst themselves and also numbers. This is a fairly trivial case insofar as it can be redone using linear algebra.

vars = {a, b, c, d, e, f, g, h};
n = Length[vars];
randomRHS = RandomInteger[{-5, 5}, {n, n + 1}].Prepend[vars, 1];

(* Out= {a -> -4 - 5 a + 2 c + 3 d - 3 f - g - 3 h,
b -> 2 + 5 a + 4 b - 3 c - 2 d + 3 e - 5 f + 4 g - 3 h,
c -> 1 + 3 a + b - 4 c - 5 d - 5 e + 5 g + h,
d -> 1 - 2 a - 2 b + 4 c + d - 4 e - 4 f - 3 g + 3 h,
e -> -5 + 3 a + c - 3 d - 4 e - 4 g,
f -> 1 + 3 a - 2 b + 2 c + 3 d + 5 e - 3 f + 4 g - 4 h,
g -> -4 - 2 a + b + 5 c + 5 d + 3 e + 3 f + 4 g - 2 h,
h -> -2 + 4 a - 3 b + 5 c + 3 e - 3 g - h} *)


Now recast as "simpler" rules.

polys = rules /. Rule -> Subtract;
gb = GroebnerBasis[polys, vars];
reds = PolynomialReduce[vars, gb, vars][[All, 2]];

(* Out= {a -> 23497/1518406, b -> 294955/759203, c -> 313959/759203,
d -> 216021/1518406, e -> -(598498/759203), f -> 691035/1518406,
g -> -(194588/759203), h -> -(999106/759203)} *)


Is this any improvement over just using linear algebra? Not really. But it might be preferred in cases where the rules involve nonlinear dependencies.

--- end edit ---

--- edit #2 ---

Here is how to handle that full example. it is slightly more work than I had anticipated because the original rule set is no longer "polynomial" (some variables now appear in exponents). it can still be resolved algebraically.

I will repeat the full definition so this example will be self-contained.

lists = {v -> v, v -> v, v -> v,
v -> v*v, v -> v, v -> v,
v -> v, v -> v + v - v, v -> v,
v -> v, v -> 0.25, v -> 14, v -> 100000000,
v -> 5, v -> 2000000000000, v -> 1,
v -> 400000000000, v -> 200000000000, v -> 0.5,
v -> 0.7, v -> -1, v -> 0.03, v -> 0.05,
v -> 333, v -> 222, v -> 0.3, v -> 0.01,
v -> 1000, v -> 0.0175, v -> 0, v -> 0, v -> 0,
v -> 0, v -> 0, v -> 0, v -> 0, v -> 1,
v -> 0, v -> 3, v -> 0.4, v -> 0.0625,
v -> 0.4, v -> 0.25, v -> 0.25, v -> 2.5,
v -> 0.5, v -> 2.5, v -> 4, v -> 0.0625,
v -> v/v + v + v + v + (-v + v)/v,
v -> v*v, v -> v*v*v,
v -> v*v*v,
v -> v + (1 - v)*v + v*v - v,
v -> (v*v)/(v^(-1) + v),
v -> ((1 - v)*v)/v, v -> v v,
v -> (v - v)/v, v -> v + v,
v -> v + v, v -> v,
v ->
v/((v/v)^(v/v) ((v*v)/(v*v))^
v^(-1)), v -> (v + v)/v,
v -> -(v/v) + (1 - v)*v + v*v,
v -> v - v + ((-v + v)*v)/(v v),
v -> (v/v)^v (v/v)^(1 - v)*v,
v -> (v - v)/(v*v),
v -> -(v/v) - v - v + (1 - v)*v +
v v - (-v + v)/v,
v -> v (1 + v v),
v -> (v + v) (1 - v) +
v*((1 - v)*v + v*v) v,
v -> ((-v + v/(1 - v)) (1 - v))/v,
v -> (-(v/v) + v)/v,
v -> (v*v)/(v^(-1) + v),
v -> (v*v)/v, v -> ((1 - v)*v)/v};


Now create "polynomials" and extract all proper" variables. The Cases is to remove "variables" that are symbolic powers.

polys = Numerator[Together[Rationalize[lists] /. Rule -> Subtract]];
vars = Cases[Variables[polys], v[_]];


Proceed as above.

gb = GroebnerBasis[polys, vars];
reds = PolynomialReduce[vars, gb, vars][[All, 2]];


This gets us most of the way, except a few variables of interest are not unraveled. By substituting the values we have we can then get numerical values for the stragglers.

morerules = Solve[(polys /. newrules) == 0]

(* Out= {{v -> 443/568, v -> 3/100, v -> 0,
v -> 600000000000}} *)


Now put these into the incomplete reducta and reform the rules.

allrules = With[{newreds = reds /. First[morerules]},

(* Out= {v -> 2000000000000, v -> 1/4, v -> 14,
v -> 2000000000000, v -> 443/568, v -> 350000000000000/71,
v -> 88600000000000/71, v -> 0, v -> 0,
v -> 1600000000000, v -> 350000000000000/71,
v -> 100000000, v -> 600000000000, v -> 0,
v -> 100000000, v -> 350000000000000/71, v -> 100000000,
v -> 400000000000, v -> 200000000000, v -> 5,
v -> 400000000000, v -> 2000000000000, v -> 1,
v -> 1/2, v -> 400000000000, v -> 200000000000,
v -> 7/10, v -> 1/20, v -> -1, v -> 3/100,
v -> 600000000000, v -> 1/20, v -> 2000000000000,
v -> 3/100, v -> 400000000000, v -> 1/20, v -> 333,
v -> 222, v -> 3/10, v -> 3/10, v -> 1600000000000,
v -> 117000000000000/71, v -> 0, v -> 2000000000000,
v -> 1, v -> 1/100, v -> 1000, v -> 0, v -> 0,
v -> 15000, v -> 2000000000000, v -> 7/400, v -> 0,
v -> 0, v -> 0, v -> 0, v -> 0, v -> 0,
v -> 0, v -> 1, v -> 0, v -> 400000000000,
v -> 600000000000, v -> 3, v -> 2/5, v -> 2/5,
v -> 1/16, v -> 1/4, v -> 1/4, v -> 5/2,
v -> 5/2, v -> 4, v -> 1/2, v -> 1/16, v -> 1/20} *)


--- end edit #2 ---

• Join[list1 /. list2, list2] seems a bit cleaner in this case. :o) (i.e. we still need better examples; if not from the OP, from you.) – Mr.Wizard Aug 14 '14 at 17:15
• The problems with applying the rule lists to one another are in detecting dependencies and handling of large lists of lists. Also in handling circularities, if one were to use //. instead of /.. – Daniel Lichtblau Aug 14 '14 at 17:19
• I think I actually understand that but without better examples your method appears to be performing a trivial operation. – Mr.Wizard Aug 14 '14 at 17:20
• Trivial, yes. But with such surgical precision. – Daniel Lichtblau Aug 14 '14 at 17:21
• Are you going to make me beg? – Mr.Wizard Aug 14 '14 at 17:22

Expanding on Mr.Wizard's answer, the side effects can be eliminated simply be doing the work inside a function rather than at top-level.

list1 = {a -> b + c, d -> b + c};
list2 = {b -> 1, c -> 1};
f[list1_, list2_] := {list1, list2} /. list2 // Values
f[list1, list2]

{{2, 2}, {1, 1}}

 Column@{{a, b, c, d}, list1, list2} • Thank you, however I want to use ExperimentalOptimizeExpression because the rules I need to have simplified are much more complex. Please note, ExperimentalOptimizeExpression provides the right output for very complex situations, for this reason I am using trivial rules; the problem I have is that the assignment I make to pass the parameters into the function has the undesired side effect of assigning values to symbols I want to keep symbolic. – Sander Aug 14 '14 at 15:11
• To indicate the issue, expanding on your solution but using ExperimentalOptimizeExpression; please note how the outcome is correct, but the transformation lists changes if the function is f[list1_, list2_] := ExperimentalOptimizeExpression[{list1 /. Rule -> Set, list2 /. Rule -> Set}] – Sander Aug 14 '14 at 15:33
• @Sander. Your problem has nothing to do with ExperimentalOptimizeExpression. That is a complete irrelevancy. It has to do with the way you use Set. You would get the same results with f[list1_, list2_] := {list1 /. Rule -> Set, list2 /. Rule -> Set} – m_goldberg Aug 14 '14 at 15:42
• @Sander. You should use replacement rules inside a scoping construct to get what you want. Mr.Wizard did not use Set. I did not use Set. You should not use Set. – m_goldberg Aug 14 '14 at 15:48
• @Sander. ExperimentalOptimizeExpression is doing nothing for you. It is intended to optimize code for compilation. I see nothing about compilation in your question. Forget about ExperimentalOptimizeExpression. I mean this sincerely and in your best interests. – m_goldberg Aug 14 '14 at 15:55