I'm attempting to use Algorithm::CurveFit to fit some numbers. I have an unusual installation, as I had problems installing Algorithm::CurveFit: CPAN fails to install Algorithm::CurveFit so my installation looks different than the standard by necessity.
the code looks like:
sub curvefit {
my ($args) = @_;
my @undef_args = grep { !defined $args->{$_}} ('formula', 'parameters', 'x', 'y');
if (scalar @undef_args > 0) {
p @undef_args;
die 'the above args are necessary, but were not defined.';
}
foreach my $key ('x', 'y') {
if (scalar @{ $args->{$key} } == 0) {
return 'no valid points'
}
}
if ($args->{formula} !~ m/x/) {
die "$args->{formula} must contain \"x\" in order to be interpreted."
}
$args->{max_iter} = $args->{max_iter} // 100; # maximum iterations
my $square_residual = CurveFit->curve_fit( # "Algorithm::CurveFit" for users who could install the module
formula => $args->{formula}, # may be a Math::Symbolic tree instead
params => $args->{parameters},
variable => 'x',
xdata => $args->{x},
ydata => $args->{y},
maximum_iterations => $args->{max_iter},
);
my %fit;
$fit{function} = $args->{formula};
foreach my $var (@{ $args->{parameters} }) {
$fit{$var->[0]}{best} = $var->[1];
$fit{$var->[0]}{error} = $var->[2];
$fit{function} =~ s/$var->[0]/$var->[1]/;
}
$fit{square_residual} = $square_residual;
return \%fit
}
my @x = (1,2,3); # ensuring that 0 won't be fed to log to produce negative infinity
my @y = (10, 19, 33);
my $log_fit = curvefit({
formula => 'a * log(x) b',
parameters => [
# name, guess, sufficient accuracy
['a', 0, 0.01],
['b', 1, 0.01],
],
'x' => \@x,
'y' => \@y
});
and produces the error in the Math::Symbolic
package:
Can't call method "term_type" on an undefined value at /home/con/perl5/perlbrew/perls/perl-5.34.0/lib/site_perl/5.34.0/Math/Symbolic/Operator.pm line 595.
Math::Symbolic::Operator::simplify(Math::Symbolic::Operator=HASH(0x564d6cebb830), 1) called at /home/con/perl5/perlbrew/perls/perl-5.34.0/lib/site_perl/5.34.0/Math/Symbolic/Operator.pm line 589
Math::Symbolic::Operator::simplify(Math::Symbolic::Operator=HASH(0x564d6cebc470), 1) called at /home/con/perl5/perlbrew/perls/perl-5.34.0/lib/site_perl/5.34.0/Math/Symbolic/Operator.pm line 589
Math::Symbolic::Operator::simplify(Math::Symbolic::Operator=HASH(0x564d6cebeed8), 1) called at /home/con/perl5/perlbrew/perls/perl-5.34.0/lib/site_perl/5.34.0/Math/Symbolic/Operator.pm line 589
Math::Symbolic::Operator::simplify(Math::Symbolic::Operator=HASH(0x564d6bd209d8)) called at /home/con/perl5/perlbrew/perls/perl-5.34.0/lib/site_perl/5.34.0/x86_64-linux/CurveFit.pm line 123
CurveFit::curve_fit("CurveFit", "formula", "a * log(x) b", "params", ARRAY(0x564d6bcb2650), "variable", "x", "xdata", ...) called at 5.all.valid.pl line 33
main::curvefit(HASH(0x564d6bcb26c8)) called at 5.all.valid.pl line 48
Command exited with non-zero status 255
going to that line in Math::Symbolic
:
my $tt2 = $o2->term_type();
I don't see how that helps to debug the problem.
Furthermore, Math::Symbolic
seems to imply that I can use log
terms: https://metacpan.org/pod/Math::Symbolic
How can I use a logarithm in the CurveFit
subroutine?
CodePudding user response:
From Math::Symbolic::Operator,
Supported operator symbols: (number of operands and their function in parens)
... log => logarithm (2: base, function) ...
The correct usage for the natural log would therefore be log(2.7182818284590452, x)