2

I'm using MathNet Symbolics to handle the symbolic algebra portion of a program I'm working on. The general use is create a pair of symbolic formulas, and then divide those two formulas. This works quite well most of the time. However, sometimes, it does not want to do more complex simplification. For example:

                       (512*r*t*w + 2048*r*t^2*w)
-----------------------------------------------------------------------
(512*r*t*w + 512*r^2*t*w + 3072*r*t^2*w + 3072*r^2*t^2*w + 1024*r*t^3*w)

With some work, I've been able to have it eliminate w from the equation, as it is in all terms top and bottom:

                    (512*r*t + 2048*r*t^2)
--------------------------------------------------------------
(512*r*t + 512*r^2*t + 3072*r*t^2 + 3072*r^2*t^2 + 1024*r*t^3)

However, I cannot figure out how to make it find common terms:

         (512*r*t)*(1 + 4*t)
--------------------------------------
(512*r*t)(1 + r + 6*t + 6*r*t + 2*t^2)

And eliminate these terms:

         (1 + 4*t)
-----------------------------
(1 + r + 6*t + 6*r*t + 2*t^2)

I've been using Wolfram Alpha as my gold standard for checking my work. The code from LinqPad I've been working on most of the afternoon, that gets my the elimination of w:

var h1 = MathNet.Symbolics.Infix.ParseOrUndefined("(1/8)*r*t*w + (1/2)*r*t^2*w");
var h2 = MathNet.Symbolics.Infix.ParseOrUndefined("(1/8)*r*t*w + (1/8)*r^2*t*w + (3/4)*r*t^2*w + (3/4)*r^2*t^2*w + (1/4)*r*t^3*w");

Infix.Print(Rational.Expand(h1/h2)).Dump();  //Prints (512*r*t*w + 2048*r*t^2*w)/(512*r*t*w + 512*r^2*t*w + 3072*r*t^2*w + 3072*r^2*t^2*w + 1024*r*t^3*w)
var tot = Rational.Expand(h1 / h2);

var simplified = true;
do
{
    simplified=false;
    foreach (var v in Rational.Variables(tot))
    {
        var result = Polynomial.Divide(v, h1, h2);
        if (!result.Item1.Equals(MathNet.Symbolics.Expression.Zero))
        {
            simplified = true;
            tot = result.Item1;
            break;
        }
    }
}while(simplified);
tot = Rational.Expand(tot);

Infix.Print(tot).Dump();  //Prints (512*r*t + 2048*r*t^2)/(512*r*t + 512*r^2*t + 3072*r*t^2 + 3072*r^2*t^2 + 1024*r*t^3)

Can someone give me pointers to how to proceed with MathNet? I've tried various combinations of functions from Rational and Polynomial, and have not been able to move past this point.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Matt Sieker
  • 9,349
  • 2
  • 25
  • 43

1 Answers1

1

I've just published a new Math.NET Symbolics release v0.6.0 which includes a new Rational.Reduce routine that removes such common simple factors (also executed as part of Rational.Expand):

var h1 = Infix.ParseOrThrow("(1/8)*r*t*w + (1/2)*r*t^2*w");
var h2 = Infix.ParseOrThrow("(1/8)*r*t*w + (1/8)*r^2*t*w + (3/4)*r*t^2*w + (3/4)*r^2*t^2*w + (1/4)*r*t^3*w");

var q1 = h1/h2;
Infix.Print(q1);
// returns: ((1/8)*r*t*w + (1/2)*r*t^2*w)/((1/8)*r*t*w + (1/8)*r^2*t*w + (3/4)*r*t^2*w + (3/4)*r^2*t^2*w + (1/4)*r*t^3*w)

var q2 = Rational.Expand(q1);
Infix.Print(q2);
// returns: (1 + 4*t)/(1 + r + 6*t + 6*r*t + 2*t^2)

Unfortunately quite a few of the univariate polynomial and rational routines like the new square-free factorization do not have a multivariate counterpart yet. Univariate routines expect one symbol parameter, while multivariate ones expect a symbol set.

Christoph Rüegg
  • 4,626
  • 1
  • 20
  • 34
  • Excellent, thank you. Between this, and some work I did over the weekend (boiling down to repeated calls to `Rational.Simplify` for each variable, and then seeing if it reduced the operands), I now get much more natural results. I might have another question later today concerning dealing with rational numbers that might be better left as decimal (Example: 58916322729/2048000000000000000000000). Or at least being able to coerce the decimal form when `Print`ing the equation. – Matt Sieker Sep 30 '15 at 17:29
  • If we had such a variant, what would be the rules to decide when to evaluate and round? All rational numbers only? All terms including no symbols? Should functions be evaluated as well? – Christoph Rüegg Oct 01 '15 at 18:00
  • I've been pondering that. In my particular use case, it's only really needed in one condition. I would say either a variant on Print() that turns rationals into reals, or being able to include real numbers in the expression. I tried the variable route mentioned in the docs, but due to the large number of possible coefficients, this resulted in expressions with thousands of terms. If there's no easy solution on the library side, my plan was to just look for pairs of parens with just numbers and a / in them, then replace that with the decimal. – Matt Sieker Oct 01 '15 at 18:57
  • It might be feasible to introduce a new expression kind, let's call it `Constant`, that behaves like a symbol but has a value and some additional automatic simplification rules to evaluate arithmetic operations. The parser could then interpret decimal expressions as such a constant instead of an exact rational number. – Christoph Rüegg Oct 02 '15 at 04:54