NAME
Math::Symbolic::Custom::Collect - Collect up Math::Symbolic expressions
VERSION
Version 0.32
DESCRIPTION
Provides some methods for working with Math::Symbolic expressions through the Math::Symbolic module extension class.
EXAMPLES
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
my $t1 = "0.125";
print "Output: ", parse_from_string($t1)->to_collected()->to_string(), "\n";
# Output: 1 / 8
my $t2 = "25/100";
print "Output: ", parse_from_string($t2)->to_collected()->to_string(), "\n";
# Output: 1 / 4
my $t3 = "((1/4)+(1/2))*3*x";
print "Output: ", parse_from_string($t3)->to_collected()->to_string(), "\n";
# Output: (9 * x) / 4
my $t4 = "1/(1-(1/x))";
print "Output: ", parse_from_string($t4)->to_collected()->to_string(), "\n";
# Output: x / (x - 1)
my $t5 = "sin(x^2+y)*sin(y+x^2)";
print "Output: ", parse_from_string($t5)->to_collected()->to_string(), "\n";
# Output: (sin((x ^ 2) + y)) ^ 2
my $t6 = "x + x^2 + 3*x^3 + 2*x - x^2";
print "Output: ", parse_from_string($t6)->to_collected()->to_string(), "\n";
# Output: (3 * x) + (3 * (x ^ 3))
my $t7 = "((1/(3*a))-(1/(3*b)))/((a/b)-(b/a))";
print "Output: ", parse_from_string($t7)->to_collected()->to_string(), "\n";
# Output: (b - a) / ((3 * (a ^ 2)) - (3 * (b ^ 2)))
my $t8 = "(x+y+z)/2";
my @terms = parse_from_string($t8)->to_terms();
print "Terms: (", join("), (", @terms), ")\n";
# Terms: (x / 2), (y / 2), (z / 2)
$Math::Symbolic::Custom::Collect::COMPLEX_VAR = 'j'; # default is 'i'
my $t9 = "j*(3-7*j)*(2-j)";
print "Output: ", parse_from_string($t9)->to_collected()->to_string(), "\n";
# Output: 17 - j
my $t10 = "(3*x - 1)^2";
print "Output: ", parse_from_string($t10)->to_derivative()->to_string(), "\n";
# Output: (18 * x) - 6
my $t11 = "u*t + (1/2)*a*t^2";
print "Output: ", parse_from_string($t11)->to_derivative('t')->to_string(), "\n";
# Output: u + (a * t)
Method to_collected()
'to_collected' performs the following operations on the inputted Math::Symbolic tree:-
Folds constants
Converts decimal numbers to rational numbers
Combines fractions
Expands brackets
Collects like terms
Cancels down
The result is often a more concise expression. See EXAMPLES above.
Method to_terms()
'to_terms()' uses 'to_collected()' and returns the expression as a list of terms, that is a list of sub-expressions that can be summed to create an expression which is (numerically) equivalent to the original expression.
Called in a scalar context, returns the number of terms.
Method to_derivative()
This is a convenience method to differentiate the inputted Math::Symbolic expression. It calls to_collected() before passing the results through to Math::Symbolic::Derivative's partial_derivative().
Takes one parameter, the variable of differentiation. If not provided it will check if the expression and if there is only one variable it will use that.
Using to_collected() on an expression before differentiating it, often yields better results (because to_collected() reformats the expression, and preparing the expression is half the battle in calculus). For example, from Bug #55842 - Math-Symbolic: Simplification deficiency affects Algorithm::CurveFit:-
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Derivative qw(:all);
use Math::Symbolic::Custom::Collect;
# the expression from the bug report
my $f = parse_from_string('A*(x - x_0)^2 + y_0');
# try differentiating it directly, introduces a pole at x-x_0=0
my $f_d1 = partial_derivative($f, 'x_0');
print "$f_d1\n"; # A * ((2 * ((x - x_0) ^ 2)) * ((1 * (-1)) / (x - x_0)))
# try with to_derivative()
my $f_d2 = $f->to_derivative('x_0');
print "$f_d2\n"; # ((2 * A) * x_0) - ((2 * A) * x)
# i.e., no pole.
COMPLEX NUMBERS
From version 0.2, there is some support for complex numbers. The symbol in $Math::Symbolic::Custom::Collect::COMPLEX_VAR
(set to 'i' by default) is considered by the module to be the symbol for the imaginary unit and treated as such when collecting up the expression. It is a Math::Symbolic variable to permit easy conversion to Math::Complex numbers using the value() method, for example:
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
use Math::Complex;
my $t = "x+sqrt(-100)+y*i";
my $M_S = parse_from_string($t)->to_collected();
print "$M_S\n"; # ((10 * i) + x) + (i * y)
# we want some kind of actual number from this expression
my $M_C = $M_S->value(
'x' => 2,
'y' => 3,
'i' => i, # glue Math::Symbolic and Math::Complex
);
# $M_C is a Math::Complex number
print "$M_C\n"; # 2+13i
If you are not going to be using complex numbers and want the symbol i
available to use as a normal Math::Symbolic variable then you will have to override $Math::Symbolic::Custom::Collect::COMPLEX_VAR
to something else at the beginning of your program, e.g.:
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
$Math::Symbolic::Custom::Collect::COMPLEX_VAR = 'blahblahblah';
# note: remember not to use 'blahblahblah' as a Math::Symbolic variable name
my $coord = parse_from_string("5*i + 2*j + 6*k"); # 'i' is just a normal variable here
It is not a good idea to change the contents of $Math::Symbolic::Custom::Collect::COMPLEX_VAR
mid-program, for example if you define some expressions using 'i' and then want to start using 'j', the module is not going to remember that 'i' was also intended to be the imaginary unit. Best thing is to pick something at the beginning of the program and stick to it.
From version 0.3 there are some helper methods and routines for working with complex (number) expressions:-
symbolic_complex()
Pass in an expression for the real component and an expression for the imaginary component and symbolic_complex will return a Math::Symbolic expression with the imaginary parameter multiplied by the contents of $Math::Symbolic::Custom::Collect::COMPLEX_VAR
, and summed with the real parameter. For example:-
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
my $Re = 1;
my $Im = 2;
my $e = symbolic_complex($Re, $Im);
print "$e\n"; # 1 + (2 * i)
$e = symbolic_complex('exp(2)', 'sin(x)');
print "$e\n"; # (e ^ 2) + ((sin(x)) * i)
Method test_complex()
Returns the real and imaginary components of the expression as an array (the imaginary component has $Math::Symbolic::Custom::Collect::COMPLEX_VAR
removed). For example:-
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
my ($Re, $Im) = parse_from_string('1+i')->test_complex();
print "$Re\n"; # 1
print "$Im\n"; # 1
($Re, $Im) = parse_from_string('x^2 + sin(x) - sqrt(-49)')->test_complex();
print "$Re\n"; # (x ^ 2) + (sin(x))
print "$Im\n"; # -7
Method to_complex_conjugate()
Returns the complex conjugate of the expression, essentially by multiplying the imaginary component by -1.
use strict;
use Math::Symbolic qw(:all);
use Math::Symbolic::Custom::Collect;
my $cc = parse_from_string('1+i')->to_complex_conjugate();
print "$cc\n"; # 1 - i
$cc = parse_from_string('5*x+i*sin(y+z)')->to_complex_conjugate();
print "$cc\n"; # (5 * x) - ((sin(y + z)) * i)
SEE ALSO
AUTHOR
Matt Johnson, <mjohnson at cpan.org>
ACKNOWLEDGEMENTS
Steffen Mueller, author of Math::Symbolic
LICENSE AND COPYRIGHT
This software is copyright (c) 2024 by Matt Johnson.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.