solving an exponential equation in Raku
Asked Answered
P

2

8

exponential equation

I'm trying to solve this exponential equation like this:

my ($l,$r);

for (1 .. 100) -> $x {
    $l = $x * e ** $x;
    $r = 5 * (e ** $x - 1);
    say $x if $l == $r;
    }

But it doesn't work. How to solve it in a straightforward and comprehensive fashion?

Prevot answered 5/4, 2020 at 21:34 Comment(11)
Differentiate this equation and then solve the quadratic equation. I am not sure, if Raku can help you directly with it. Would you expect Raku to analyze this algebraic expression or give you a numerical solution? Are you looking for existing libraries or want to program something yourself? Only for this specific equation?Arnuad
Try Math::Symbolic. Looks like .new and .isolate might do the trick.Enteritis
@Arnuad I was wondering if there's a neat and concise solution to it.Prevot
I think currently there is no general solution to any exponential equation in Raku. Math::Symbolic has logarithms marked as NYI (not yet implemented). If you were asking not just for interest, but needing the solution to this or a group of similar equations, one could do the first step by hand, and let Raku do the rest, that would be possible. Then you should state, what could change, e.g. which coefficients are variable. If you just need to solve this specific equation, then you could also do it outside Raku (e.g. Wolfram Alpha).Arnuad
The basic idea for this kind of equations is to differentiate both sides once (product rule, chain rule). Afterwards each term has e^x as factor. Factor this out and you get (quadratic equation) times e^x = 0; e^x never is 0. So you just have to solve the quadratic equation. Raku could help with parsing the equation in the first place, analyzing it, whether differentiation is the correct step, transforming it and calculating the result.Arnuad
Hi @Sebastian. Thanks for checking out the pure raku Math::Symbolic and noting it doesn't do logarithms, I didn't pay enough attention. Given that the OP equation is a polynomial, perhaps Math::Libgsl::Polynomial is appropriate? I'm out of my depth -- I just know how to search, I don't know how to use symbolic math systems -- but I think, if someone can confirm it works well enough to solve this equation, it would be nice if that was posted as an answer (regardless of whether or not anyone views it "a neat and concise solution").Enteritis
Do you seek an algebraic or a numeric solution?Arnuad
@Arnuad Back to using libs... And/or maybe use Math::Polynomial:from<Perl5> would work well? At first glance this perl module looks notably mature and well maintained. It's essentially a 23 year old codebase, with two lead authors, continual commits, the latest commit a couple months ago, and "no known unresolved issues". The raku module Math::Libgsl::Polynomial is a brand new wrapper of a C library of about the same vintage. I think of this as a really nice contrast/compare situation; there's scope here for a definitive SO on this topic.Enteritis
Let us continue this discussion in chat.Enteritis
This equation was posted on a foreign board and the OP was asking how to solve it in Python. This sort of problems are usually solved in Python, Matlab, Scilab, etc. I just wondered if there was a good way of solving such kind of math problems in Raku. Doesn't matter if it's algebraic or numeric. The only matter is that it be neat and comprehensive.Prevot
@LarsMalmsteen The problem with the code is, you only check for integer solutions, and they would have to be absolutely exact. Calculations as the exp() often have rounding errors (Raku supports rational numbers, but this formula has no rational solution). See new answer at the end for a solution.Arnuad
A
5

Sorry for the double-answering.
But here is a totally different much simpler approach solved in Raku.
(It probably can be formulated more elegant.)

#!/usr/bin/env raku

sub solver ($equ, $acc, $lower0, $upper0) {
    my Real $lower = $lower0;
    my Real $upper = $upper0;
    my Real $middle = ($lower + $upper) / 2;

    # zero must be in between
    sign($equ($lower)) != sign($equ($upper)) || die 'Bad interval!';

    for ^$acc {                                          # accuracy steps
        if sign($equ($lower)) != sign($equ($middle))
            { $upper = $middle }
        else
            { $lower = $middle }
        $middle = ($upper + $lower) / 2;
    }
    return $middle;
}

my $equ = -> $x { $x * e ** $x  -  5 * (e ** $x - 1) };  # left side - right side
my $acc = 64;                                            # 64 bit accuracy
my Real $lower = 1;                                      # start search here
my Real $upper = 100;                                    # end search here

my $solution = solver $equ, $acc, $lower, $upper;

say 'result is ', $solution;
say 'Inserted in equation calculates to ', $equ($solution), ' (hopefully nearly zero)'
Arnuad answered 8/4, 2020 at 17:44 Comment(0)
A
2

For Perl 5 there is Math::GSL::Roots - Find roots of arbitrary 1-D functions

https://metacpan.org/pod/Math::GSL::Roots

Raku has support for using Perl 5 code or can access the GSL C library directly, can't it?

$fspec = sub {
       my ( $x ) = shift;

       # here the function has to be inserted in the format 
       # return leftside - rightside;

       return  ($x + $x**2) - 4;


     };

gsl_root_fsolver_alloc($T); # where T is the solver algorithm, see link for the 6 type constants, e.g. $$gsl_root_fsolver_brent
gsl_root_fsolver_set( $s, $fspec, $x_lower, $x_upper ); # [$x_lower; $x_upper] is search interval
gsl_root_fsolver_iterate($s);
gsl_root_fsolver_iterate($s);
gsl_root_fsolver_iterate($s);
gsl_root_fsolver_iterate($s);
gsl_root_fsolver_iterate($s);
my $result = gsl_root_fsolver_root($s);
gsl_root_fsolver_free (s);

There are enhanced algorithms available (gsl_root_fdfsolver_*), if the derivative of a function is available.

See also https://www.gnu.org/software/gsl/doc/html/roots.html#examples for general usage

Arnuad answered 6/4, 2020 at 12:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.