
/* code pertaining to creating the internal format for multivariate
   polynomials (the inverse of NormalForm

- MultiExpressionList(x) 
  extract all variable-like sub-expressions from the main expression,
  including functions, which can then get treated as if they were
  a variable.
- IsMultiExpression(x)
  determing whether 'x' can be a 'variable' for a multiNomial
- IsMulti(x)
  returns True if 'x' is a multivariate expression in internal format.
  Useful for transformation rules.
 */

MultiExpressionList(_expr) <-- VarList(expr,"IsMultiExpression");
10 # IsMultiExpression(_x + _y) <-- False;
10 # IsMultiExpression(_x - _y) <-- False;
10 # IsMultiExpression(   - _y) <-- False;
10 # IsMultiExpression(_x * _y) <-- False;
10 # IsMultiExpression(_x / _y) <-- False;
10 # IsMultiExpression(_x ^ y_IsPositiveInteger) <-- False;
11 # IsMultiExpression(_x ^ _y)_(IsPositiveInteger(Simplify(y))) <-- False;
//10 # IsMultiExpression(x_IsConstant) <-- False;
10 # IsMultiExpression(x_IsMultiConstant) <-- False;

//TODO: shouldn't this be more global? The problem right now is 
// that IsConstant/IsVariable take Pi to be a constant...
IsMultiConstant(_n) <-- (VarList(n,"IsVr")={});
10 # IsVr(n_IsNumber) <-- False;
10 # IsVr(n_IsFunction) <-- False;
10 # IsVr(n_IsString) <-- False;
20 # IsVr(_n) <-- True;
100 # IsMultiExpression(_x) <-- True;

10 # IsMulti(MultiNomial(vars_IsList,_terms)) <-- True;
20 # IsMulti(_anything) <-- False;



LocalSymbols(a,vars,pow)  [
  20 #  MultiSingleFactor(_vars,_a,_pow) <--
    [
      Local(term);
      term:={FillList(0,Length(vars)),1};
      term[1][Find(vars,a)] := pow;
      CreateTerm(vars,term);
    ];
];
LocalSymbols(x,y,vars)  [
10 #  MakeMultiNomial(x_IsMultiConstant,vars_IsList) <--
      CreateTerm(vars,{FillList(0,Length(vars)),x});
20 #  MakeMultiNomial(_x,vars_IsList)_(Contains(vars,x)) <-- MultiSingleFactor(vars,x,1);
30 #  MakeMultiNomial(_x + _y,vars_IsList) <--
      MakeMultiNomial(x,vars) + MakeMultiNomial(y,vars);
30 #  MakeMultiNomial(_x * _y,vars_IsList) <--
      MakeMultiNomial(x,vars) * MakeMultiNomial(y,vars);
30 #  MakeMultiNomial(- _x,vars_IsList) <-- -MakeMultiNomial(x,vars);
30 #  MakeMultiNomial(_x - _y,vars_IsList) <--
      MakeMultiNomial(x,vars) - MakeMultiNomial(y,vars);
30 #  MakeMultiNomial(MultiNomial(_vars,_terms),vars_IsList)
      <-- MultiNomial(vars,terms);

// This rule would accept almost all terms, assuming them to be const.
100 #  MakeMultiNomial(_x,vars_IsList) <--
      [
      CreateTerm(vars,{FillList(0,Length(vars)),x});
      ];

];

LocalSymbols(x,y,z,vars,gcd,a,a)  [
  20 #  MakeMultiNomial(_x / (_y / _z),vars_IsList)
     <-- MakeMultiNomial((x*z) / y,vars_IsList);
  20 #  MakeMultiNomial((_x / _y) / _z,vars_IsList)
     <-- MakeMultiNomial((x*z) / y,vars_IsList);
  25 #  MakeMultiNomial(_x / y_IsConstant,vars_IsList)
     <-- MakeMultiNomial(1/y,vars)*MakeMultiNomial(x,vars);
  30 #  MakeMultiNomial(_x / _y,vars_IsList) <--
        [
          Local(result);
//Echo("1...",x);
//Echo("2...",y);
          Set(result,MultiRemoveGcd(MakeMultiNomial(x,vars)/MakeMultiNomial(y,vars)));
//Echo("3...",result);
          result;
        ];
  ];


MultiNomial(_vars,_x) + MultiNomial(_vars,_y) <--
	   MultiNomialAdd(MultiNomial(vars,x), MultiNomial(vars,y));
MultiNomial(_vars,_x) * MultiNomial(_vars,_y) <--
           MultiNomialMultiply(MultiNomial(vars,x), MultiNomial(vars,y));
MultiNomial(_vars,_x) - MultiNomial(_vars,_y) <--
        MultiNomialAdd(MultiNomial(vars,x), MultiNomialNegate(MultiNomial(vars,y)));
                      - MultiNomial(_vars,_y) <--
        MultiNomialNegate(MultiNomial(vars,y));


LocalSymbols(x,n,vars)  [
30 #  MakeMultiNomial(_x ^ n_IsInteger,vars_IsList)_(Contains(vars,x)) <--
      MultiSingleFactor(vars,x,n);
40 #  MakeMultiNomial(_x ^ n_IsPositiveInteger,vars_IsList) <--
      [
        Local(mult,result);
        Set(mult,MakeMultiNomial(x,vars));
        Set(result,MakeMultiNomial(1,vars));
	While(n>0)
        [
          If(n&1 != 0, Set(result, MultiNomialMultiply(result,mult)));
          Set(n,n>>1);
          If(n!=0,Set(mult,MultiNomialMultiply(mult,mult)));
        ];
        result;
      ];

  15 #  MakeMultiNomial(_x ^ _n,vars_IsList)_(Not(IsInteger(n)) And IsInteger(Simplify(n))) <--
        MakeMultiNomial( x ^  Simplify(n),vars);

  50 #  MakeMultiNomial(_x ^ (_n),vars_IsList)_(Contains(vars,x)) <--
        [
          Set(n,Simplify(n));
          If(IsInteger(n),
            MultiSingleFactor(vars,x,n),
            MultiSingleFactor(vars,x^n,1)
  	    );
        ];
];


x_IsMulti + (y_IsMulti/z_IsMulti) <-- ((x*z+y)/z);
(y_IsMulti/z_IsMulti) + x_IsMulti <-- ((x*z+y)/z);
(y_IsMulti/z_IsMulti) + (x_IsMulti/w_IsMulti) <-- ((y*w+x*z)/(z*w));
(y_IsMulti/z_IsMulti) - (x_IsMulti/w_IsMulti) <-- ((y*w-x*z)/(z*w));
(y_IsMulti/z_IsMulti) * (x_IsMulti/w_IsMulti) <-- ((y*x)/(z*w));
(y_IsMulti/z_IsMulti) / (x_IsMulti/w_IsMulti) <-- ((y*w)/(z*x));
x_IsMulti - (y_IsMulti/z_IsMulti) <-- ((x*z-y)/z);
(y_IsMulti/z_IsMulti) - x_IsMulti <-- ((y-x*z)/z);
(a_IsMulti/(c_IsMulti/b_IsMulti))    <-- ((a*b)/c);
((a_IsMulti/c_IsMulti)/b_IsMulti)    <-- (a/(b*c));
((a_IsMulti/b_IsMulti) * c_IsMulti)  <-- ((a*c)/b);
(a_IsMulti * (c_IsMulti/b_IsMulti))  <-- ((a*c)/b);
- ((a_IsMulti)/(b_IsMulti))         <-- (-a)/b;


MultiNomialMultiply(
     MultiNomial(_vars,_terms1)/MultiNomial(_vars,_terms2),
     MultiNomial(_vars,_terms3)/MultiNomial(_vars,_terms4)) <--
[
  MultiNomialMultiply(MultiNomial(vars,terms1),MultiNomial(vars,terms3))/
  MultiNomialMultiply(MultiNomial(vars,terms2),MultiNomial(vars,terms4));
];
MultiNomialMultiply(
     MultiNomial(_vars,_terms1)/MultiNomial(_vars,_terms2),
     MultiNomial(_vars,_terms3)) <--
[
  MultiNomialMultiply(MultiNomial(vars,terms1),MultiNomial(vars,terms3))/
  MultiNomial(vars,terms2);
];
MultiNomialMultiply(
     MultiNomial(_vars,_terms3),
     MultiNomial(_vars,_terms1)/MultiNomial(_vars,_terms2)) <--
[
  MultiNomialMultiply(MultiNomial(vars,terms1),MultiNomial(vars,terms3))/
  MultiNomial(vars,terms2);
];

10 # MultiNomialMultiply(_a,_b) <--
[
  Echo({"ERROR!",a,b});
  Echo({"ERROR!",Type(a),Type(b)});
];





