3

Original: Is there any way to control Mathematica's inner simplification algorithm? I have seen several instances where FullSimplify does not yield the most optimal solution but instead gets stuck in a local minimum. I can provide with some examples if needed.

Edit: Here are some details of the most recent place I stumbled into this:

So I am defining a derivative operator, myD, such that:

myD[x_?NumericQ*y_] := x myD[y];
myD[x_?NumericQ] := 0;

i.e. If myD acts on a scalar*something he will take the scalar outside, and if myD acts on a scalar, the output will be 0. Then, to impose linearity I impose the two following transformation functions:

myDSumTransform[x_?(MatchQ[#, myD[a_]] &)] := 
    (x /. (myD[HoldPattern[Plus[y__]]] :> Plus @@ (myD /@ List[y])));

myDSumTransformInverse[x_?(MatchQ[#,Optional[a_?NumericQ] myD[b_] + Optional[c_?NumericQ] myD[d_]] &)] := (x /. Optional[e_?NumericQ, 1] myD[f_] + Optional[g_?NumericQ, 1] myD[h_] :> myD[e f + g h]);

The first transformation equation takes myD[a+b+c+...] and maps it into myD[a] + myD[b] +... The second transformation takes a myD[b] + c myD[d] and maps it into myD[a b + c d].

Now I define myFullSimplify based on FullSimplify, using TransformationFunctions, such that:

$transfFunctions ={};
addToTransfFunctions[rules__]:=AppendTo[$transfFunctions, #]&/@List[rules];
myFullSimplify[expr_]:=FullSimplify[expr,TransformationFunctions->Flatten[{Automatic, $transfFunctions}]];

addToTransfFunctions[myDSumTransform, myDSumTransformInverse];

Alright, now comes the example. Take:

myD[a + b + c + 5]//myFullSimplify

The expected output would be

myD[a + b + c]

However what I get is


myD[a + b + c + 5]

My understanding is that the FullSimplify algorithm takes myD[a+b+5] applies myDSumTransform, arrives at myD[a] + myD[b] + myD[c], finds that the LeafCount is bigger, fiddles a bit with it to no avail and rejects the output. To get to the desired output, he would need to apply myDSumTransformInverse, two times and arriving at

myD[a + b + c]

If I try something a little less complex, e.g.

myD[a + b + 5 ] // myFullSimplify

I get myD[a+b] as expected.

So I guess what really need is to increase Mathematica's persistence setting, or to find a smarter way to write myDSumTransformInverse.

Sorry for the convoluted question, I understand it a complex example, but I am not sure if there is a systematic way to deal with these issues. Hence, it would be nice to have some guidance on how to proceed here.

Thanks in advance for all the help!

Filipe Miguel
  • 515
  • 2
  • 8
  • 2
    What is your example? – cvgmt Feb 04 '21 at 23:52
  • 2
    Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! – Michael E2 Feb 04 '21 at 23:55
  • 5
    Have you examined the options, TransformationFunctions and ComplexityFunction? – Michael E2 Feb 04 '21 at 23:56
  • 3
    A reasonable example how ComplexityFunction works can be found here FullSimplify does not work on this expression with no unknowns. – Artes Feb 05 '21 at 00:26
  • 2
    On the topic of aiding and guiding the expression simplification process, also see Advice for Mathematica as Mathematician's Aid – MarcoB Feb 05 '21 at 04:53
  • Hi all! I am using TransformationFunctions indeed and that is why I know I am getting stuck in a local minimum. I have quite a convoluted example, will try to get a working minimal example. – Filipe Miguel Feb 05 '21 at 11:01
  • @cvgmt I added a more concrete example – Filipe Miguel Feb 05 '21 at 11:49
  • @MichaelE2 I added a more concrete example – Filipe Miguel Feb 05 '21 at 11:50
  • 1
    Try myDSumTransformInverse[myDSumTransform[myD[a + b + c + 5]]] -- I don't think it's doing what you want. – Michael E2 Feb 05 '21 at 15:22
  • @MichaelE2, it outputs myDSumTransformInverse[myD[a] + myD[b] + myD[c]]. That is because I only know how to input 2 terms to myDSumTransformInverse. But Mathematica's FullSimplify should try to evaluate each Leaf of myD[a] + myD[b] + myD[c] against all the TransformFunctions, and hence he would eventually evaluate two at a time. Any clue how to write myDSumTransformInverse such that it may take more 3 or more terms as input? Thanks! – Filipe Miguel Feb 05 '21 at 15:33
  • 1
    I think myDSumTransformInverse = Thread[#, myD] & is what you want. I'm not sure FullSimplify tries to transform each subset of terms of a sum. I think unfortunately, you will have to add a transformation function like myDSumTransformInverse@*myDSumTransform to the mix to get it over the hump into a new minimum. – Michael E2 Feb 05 '21 at 15:39
  • @MichaelE2 that seems to point towards the way to go. Does not work if there are scalar coefficients, but I will try to work that out, thanks! – Filipe Miguel Feb 05 '21 at 15:54
  • Maybe this would be a replacement for myDSumTransformInverse: ClearAll[linearCombine]; Module[{f}, SetAttributes[f, NumericFunction]; constantQ = NumericQ[# /. s_Symbol /; MemberQ[Attributes[s], Constant] :> f[0]] & ]; linearCombine[ e_Plus, head_, constants_List : {} ] := Block[{head}, Block[constants, SetAttributes[#, Constant] & /@ constants; head@Replace[e, {c_?constantQ*head[a_] :> c*a, head[a_] :> a}, 1 ] /; MatchQ[e, _[((_?constantQ)*_myD | _myD) ..]] ]]; – Michael E2 Feb 05 '21 at 18:23
  • Then linearCombine[myD[a] + 2 Sqrt[2] myD[b] + 3 E myD[c], myD] – Michael E2 Feb 05 '21 at 18:24

1 Answers1

2

Here's a function linearCombine[] for un-distributing a linear operator that is a complement to linearExpand[] found in How to do algebra on unevaluated integrals? There is an optional argument to both to specify symbols that are to be treated as constants, which has no application in the present question.

ClearAll[linearCombine];
Module[{f},
  SetAttributes[f, NumericFunction];
  constantQ = NumericQ[# /.
      s_Symbol /; MemberQ[Attributes[s], Constant] :> f[0]] &
  ];
linearCombine[e_Plus, head_, constants_List : {}] := Block[constants,
   SetAttributes[#, Constant] & /@ constants;
   head@Replace[
      e,
      {c_?constantQ*head[a_] :> c*a,
       head[a_] :> a},
      1
      ] /; MatchQ[e, _[((_?constantQ)*_head | _head) ..]]
   ];

Example:

linearCombine[myD[a] + 2 Sqrt[2] myD[b] + 3 E myD[c], myD]
(*  myD[a + 2 Sqrt[2] b + 3 c E]  *)
Michael E2
  • 235,386
  • 17
  • 334
  • 747