Merge terms that contain Expression.Real factors


#1

Hello everyone,

I’m currently working on a project where I’d like to reduce/simplyfy mathematic expressions as far as possible.
On first look, MathNet.Symbolics seemed to provide everything that I need for this job.

However, I came across some problems for which I cannot figure out how to solve them by myself.

I want Expressions of the form
"x + 2 * x"
to be merged into
"3 * x"

This works as long as the factors are no double-Values (which I currently convert by using Expression.Real(value)).
Once they are incorporated, things get messy. Here is some Console Output for different Expressions.
Since I am a new user, I cannot upload the sample solution. Is there any other way that I can provide it to you?

Parsing Expression from string:
        Expression A: "x + 2 * (3/4)*x"...
        (5/2)*x
        Expression B: "x + 2 * (0.75)*x"...
        x + 1,5*x

Using MathNet.Symbolics.Expression:
        Expression C: x + 1r * x
        x + 1*x
        Expression D: 1r * x + 1r * x
        2*x
        Expression E: 0.7r * x + 0.3r * x is not merged:
        0,3*x + 0,7*x
        Expression F: 0.5r * x + 0.5r * x is merged:
        1*x
        Expression G: (1/4)r * x + (3/4)r * x is not merged:
        0,25*x + 0,75*x
        Expression H: (1/2)r * x + (2/4)r * x is merged:
        1*x
        Expression I: (1r/2r) * x + (2r/4r) * x is not:
        (1*x)/2 + (2*x)/4

Is there a way to reduce these Expressions to 2 * x (or simply x for the later ones)?
Ideally, I’d want all terms that contain the same symbol (e.g. “x”), to be merged into a single term.


(Christoph Rüegg) #2

This is partially by design, although that doesn’t mean we cannot improve it.

In essence, integers and rationals are exact expressions which can be manipulated algebraically in a consistent way. Floating point numbers, however, are not. Originally Symbolics did not even support them. Expression like “1.5” used to be parsed into “3/2” and then handled normally, with the usual expected simplifications.

This was changed lately with the introduction of arbitrary real constants. But note that they are still not considered as “numbers”, but as special kind of constant, with a few additional automatic simplification rules. Admittedly the behavior is now not entirely consistent nor that helpful in practice. Looking back I’m not sure this was a good decision. Maybe we should provide an option on the infix parser?

PS: you should be able to add attachments now - let me know if not


#3

MathNetExample.7z (3.4 KB)

Hello Christoph,

thanks for your reply. I attached a sample project (without nuget-files) to this post, that shows some of the working- and not working combinations of Int, Rationals and Reals.

Is it possible to add an option that makes MathNet interpret all numbers as Real, so that the respective Terms are merged?
Ideally, I’d prefer this to not only work with parsed Strings, but also with “general” MathNet-Epressions. I assume that it is much more efficient to not having to parse all Expressions from Strings.

Thanks
Jannick Lange


(Christoph Rüegg) #4

I finally spent so time today to improve our handling of real numbers; the behavior should now be much closer to your expectations (current master, not yet released).

There is also a new Approximation module to partially approximate expressions to real or complex numbers - but other than Evaluate does return an Expression so it can handle partial evaluation.

Examples:

  • (3Q + 2)*4/6
    => 10/3
  • (3Q + 2)*4/6 |> Approximate.approximate
    => 3.33333333333333
  • -x*y/3 |> Approximate.approximate
    => (-0.333333333333333)*x*y
  • (8*a*x + 6*a*x**2)/(4*x*a)
    => ((1/4)*(8*a*x + 6*a*x^2))/(a*x)
  • (8*a*x + 6*a*x**2)/(4*x*a) |> Rational.expand
    => 2 + (3/2)*x
  • 8*a*x + 6*a*x**2)/(4*x*a) |> Approximate.approximate
    => (0.25*(8*a*x + 6*a*x^2))/(a*x)
  • (8*a*x + 6*a*x**2)/(4*x*a) |> Approximate.approximateSubstitute (Map.ofList ["a", Real(0.5)])
    => (0.5*(4*x + 3*x^2))/x
  • (8*a*x + 6*a*x**2)/(4*x*a) |> Approximate.approximateSubstitute (Map.ofList ["a", Real(0.5)]) |> Rational.simplify x
    => 2 + 1.5*x
  • (8*a*x + 6*a*x**2)/(4*x*a) |> Rational.expand |> Approximate.approximate
    => 2 + 1.5*x
  • (8*a*x + 6*a*x**2)/(4*x*a) |> Approximate.approximateSubstitute (Map.ofList ["x", Real(2.2)])
    => 5.3

Symbolic Substitution
(Christoph Rüegg) #5

Released in v0.11.0.