vermaseren / form

The FORM project for symbolic manipulation of very big expressions
GNU General Public License v3.0
982 stars 118 forks source link

Expressions simplification #398

Open kikke88 opened 2 years ago

kikke88 commented 2 years ago

Dear FORM community,

I am trying to use FORM for coefficient simplification. The general case of the coefficient is shown below.

Where Poly_i are polynomials from a known set of symbols. After all simplifications, the result has the form of a fraction of the polynomials.

For example,

Is there a way to make such simplifications in FORM? I have not been able to achieve the desired result (maybe I misused PolyRatFun and #Optimize)

Thanks in advance.

tueda commented 2 years ago

The following program does more or less what you want, I think:

CF num,den,rat;
S x,y;

#procedure PolySimplify()
  .sort:PolySimplify-1;
* Enable PolyRatFun. Convert num and den into rat.
  PolyRatFun rat;
  id num(x?) = rat(x,1);
  id den(x?) = rat(1,x);
  .sort:PolySimplify-2;
* Disable PolyRatFun. Convert rat back to num and den and then factorise them.
  PolyRatFun;
  id rat(x?,y?) = num(x) * den(y);
  factarg num;
  factarg den;
  chainout num;
  chainout den;
#endprocedure

S x,y,z,d;

L F1 =
  + num(6 * x + 3) * den(2 * y) * num(11) * den(3 * z + 9)
;

L F2 =
  + num(3 / 2 * d)
  - num(3 / 2 * d^ 2) * den(d - 2)
  + num(6 * d) * den(d - 2)
  - num(6) * den(d - 2)
  - num(3)
;

#call PolySimplify()

P +s;
.end
   F1 =
       + num(11)*num(1 + 2*x)*den(2)*den(y)*den(3 + z)
      ;

   F2 = 0;

Here, the num and den functions are used for representing factors in the numerator and those in the denominator, respectively.

Note that if you simply give rational polynomials as, for example, 1 / (1 + x), i.e., something divided by a polynomial, then it is internally expressed with some functions but printed just as 1 / (1 + x), which may cause some confusion (and actually relatively buggy).

kikke88 commented 2 years ago

Thank you very much for your help. All that remains is to come up with a regex pattern to replace the original expression with an expression with num(...) and den(...) :)

jodavies commented 2 years ago

You can use Denominators to convert the /() notation into, say, den() and then go from there. You can move the symbols into the PolyRatFun with Identify statements, so you don't need to prepare the input with num and den functions already.

You can modify tueda's procedure to something like

#procedure PolySimplify()
  .sort:PolySimplify-1;
* Enable PolyRatFun. Convert num and den into rat.
  PolyRatFun rat;
  denominators den;
  id num(x?) = rat(x,1);
  id den(x?) = rat(1,x);
  id x? = rat(x,1);
  .sort:PolySimplify-2;
* Disable PolyRatFun. Convert rat back to num and den and then factorise them.
  PolyRatFun;
  id rat(x?,y?) = num(x) * den(y);
  factarg num;
  factarg den;
  chainout num;
  chainout den;
#endprocedure
tueda commented 2 years ago

@jodavies good catch! I think in general id many, x?^y? = rat(x^y,1); is needed to handle x * y and 1 / x.

So, here is a revised complete example:

CF num,den,rat;
S x,y;

#procedure PolySimplify()
  .sort:PolySimplify-1;
* Enable PolyRatFun. Convert num and den into rat.
  PolyRatFun rat;
  denominators den;
  id num(x?) = rat(x,1);
  id den(x?) = rat(1,x);
  id many,x?^y? = rat(x^y,1);
  .sort:PolySimplify-2;
* Disable PolyRatFun. Convert rat back to num and den and then factorise them.
  PolyRatFun;
  id rat(x?,y?) = num(x) * den(y);
  factarg num;
  factarg den;
  chainout num;
  chainout den;
#endprocedure

* Examples

S x,y,z,d;

L F1 =
  + (6 * x + 3) / (2 * y) * 11 / (3 * z + 9)
;

L F2 =
  + 3 / 2 * d
  - 3 / 2 * d^2 / (d - 2)
  + 6 * d / (d - 2)
  - 6 / (d - 2)
  - 3
;

L F3 =
  + (1 + x * y^3) / (z + x * y^3 * z)
  - 1 / z
;

#call PolySimplify()

P +s;
.end
   F1 =
       + num(11)*num(1 + 2*x)*den(2)*den(y)*den(3 + z)
      ;

   F2 = 0;

   F3 = 0;
kikke88 commented 2 years ago

The program you suggested does its job perfectly for the case of a simple fraction, but in the case of a complex fraction (see example), after replacing den with rat, an error occurs: "...polyratfuns must contain symbols only"

Сoefficient examples: -(-d*s+3*s)/(-1/(d-4)*d^2*s+6/(d-4)*d*s-9/(d-4)*s) ((3 * x + 2) / (4 * y)) / (21 / (2 * x + 8) + z / (2 * x + 8) + z^3)

vermaseren commented 2 years ago

Your problem is that you have denominators inside denominators. Because such denominators are functions you get that message. If d-4 is a symbol you should have no problem.

On 13 Nov 2021, at 17:47, Mokrov Kirill @.***> wrote:

The program you suggested does its job perfectly for the case of a simple fraction, but in the case of a complex fraction (see example), after replacing den with rat, an error occurs: "...polyratfuns must contain symbols only" https://camo.githubusercontent.com/2112f7aa5fd78c74fe2a9842e7b4e386a3d76e45bd780bc9134b10cf6d8d360b/68747470733a2f2f6c617465782e636f6465636f67732e636f6d2f7376672e696d6167653f25354366726163253742506f6c795f3125374425374225354366726163253742506f6c795f32253744253742506f6c795f33253744253744253230253543746f25323025354366726163253742506f6c795f3125374425374264656e2825354366726163253742506f6c795f3225374425374264656e28506f6c795f332925374429253744 Сoefficient examples: -(-ds+3s)/(-1/(d-4)d^2s+6/(d-4)ds-9/(d-4)s) ((3 x + 2) / (4 y)) / (21 / (2 x + 8) + z / (2 * x + 8) + z^3)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/vermaseren/form/issues/398#issuecomment-968097791, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABJPCESJWDS24N5WECGY2P3UL2JAPANCNFSM5HPQIEXQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

jodavies commented 2 years ago

You can use "ExtraSymbols" to represent the denominators inside the polyratfun. Once things have been simplified, you can insert their definitions:

PolyRatFun prf;                  
Denominators den;                

Argument den;                    
   ArgToExtraSymbol den;         
   Identify den(x?) = 1/x;       
EndArgument;                     

Identify den(x?) = prf(1,x);     
Identify,many x?^y? = prf(x^y,1);
.sort                            

Argument prf;                    
   FromPolynomial;               
EndArgument;                     

Probably this code doesn't do what you want if there are doubly-nested denominators...

Edit: it's a bit horrible, but this should work for a fixed maximum nesting:

#define DEPTH "3"

Symbol x,y,z;
CFunction prf,den;

Local test = ((3 * x + 2) / (4 * y)) / (21 / (2 * x + 8 / (1 + 2*y / (1 - 3*x))) + z / (2 * x + 8) + z^3);
.sort

PolyRatFun prf;
Denominators den;

#do i = 1,`DEPTH'
Argument den;
#enddo
#do i = 1,`DEPTH'
    ArgToExtraSymbol den;
    Identify den(x?) = 1/x;
EndArgument;
#enddo

Identify den(x?) = prf(1,x);
Identify,many x?^y? = prf(x^y,1);
.sort

#do i = 1,`DEPTH'
    Argument prf;
        FromPolynomial;
    EndArgument;
    .sort
#enddo

Print +s;
.end