Skip to content

Instantly share code, notes, and snippets.

@masak

masak/poly.p6 Secret

Forked from smls/01_polynomial_parse_differentiate.p6
Last active April 25, 2016 09:50
Show Gist options
  • Save masak/a4fa034eef9ee3c9e04a9f0b818c8ae6 to your computer and use it in GitHub Desktop.
Save masak/a4fa034eef9ee3c9e04a9f0b818c8ae6 to your computer and use it in GitHub Desktop.
grammar Polynomial {
rule TOP { <term>+ % (<[+ -]>) }
rule term { <factor>+ % (<[* /]>) }
proto rule factor { * }
rule factor:<num> { <num> <exp>? }
rule factor:<var> { <var> <exp>? }
rule exp { '^' <num> }
proto rule var { * }
rule var:<pos> { 'X' }
rule var:<neg> { '-' 'X' }
rule num { '-'? \d+ }
}
my $actions = role {
method TOP($/) {
make my %coeffs := MixHash.new;
%coeffs{ @<term>[0].ast[1] } = @<term>[0].ast[0];
for @<term>[1..*] Z @0 -> ($t, $op) {
my $sign = $op eq "+" ?? +1 !! -1;
%coeffs{ $t.ast[1] } += $sign * $t.ast[0];
}
}
method term($/) {
make @<factor>[0].ast;
for @<factor>[1..*] Z @0 -> ($f, $op) {
when $op eq "*" { make [$/.ast[0] * $f.ast[0], $/.ast[1] + $f.ast[1]] }
when $op eq "/" { make [$/.ast[0] / $f.ast[0], $/.ast[1] - $f.ast[1]] }
}
}
method factor:<num>($/) { make [$<num>.ast ** ($<exp><num>.ast // 1), 0] }
method factor:<var>($/) { make [$<var>.ast, $<exp><num>.ast // 1] }
method var:<pos>($/) { make +1 }
method var:<neg>($/) { make -1 }
method num($/) { make $/.Rat }
};
sub derive($polynomial) {
my %coeffs := Polynomial.parse($polynomial, :$actions).ast
or die "Couldn't parse '$polynomial'";
return "0" unless %coeffs;
%coeffs.keys.sort.reverse.map({
when 0 { next }
when 1 { %coeffs{$_} }
default { "{$_ * %coeffs{$_}} * X^{ $_ - 1 }" }
}).join(" + ").subst("+ -", "- ", :g);
}
#-----[ Usage ]-----
say "-X^2 + 1 / X * 4 - X^-4 - 3 * 5/6";
say derive("-X^2 + 1 / X * 4 - X^-4 - 3 * 5/6");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment