Skip to content

Commit

Permalink
Merge pull request #97 from corywalker/corywalker
Browse files Browse the repository at this point in the history
Able to parse all of Rubi.
  • Loading branch information
corywalker committed Sep 4, 2017
2 parents 6462847 + e1af23f commit b563d68
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 31 deletions.
121 changes: 118 additions & 3 deletions examples/load_rubi.m
@@ -1,4 +1,119 @@
(* ::Package:: *)

(* ::Title:: *)
(*Rubi (Rule-Based Integrator) Package*)
(* Clone https://github.com/corywalker/rubi into the root dir of Expreduce. *)
Get["rubi/Integration Utility Functions.m"]
Get["rubi/9.1 Integrand simplification rules.m"]
Get["rubi/1.1.1 Linear binomial products.m"]



BeginPackage["Rubi`"]

Int::usage =
"Int[expn,var] returns the antiderivative (indefinite integral) of <expn> with respect to <var>.
Int[list,var] returns a list of the antiderivatives of the elements of <list> with respect to <var>.";


IntShowSteps::usage = "IntShowSteps[expn,var] shows all the rules and intermediate steps required to integrate <expn> with respect to <var>, and returns Null.";


Dist::usage = "Dist[expn1,expn2,var] distributes <expn1> over <expn2>.";
Subst::usage = "Subst[expn1,var,expn2] substitutes <expn2> for <var> in <expn1>.";


ShowSteps::usage = "If ShowSteps is True and the ShowSteps package has been loaded, integration steps are displayed.";
$StepCounter::usage = "If the ShowSteps package has been loaded and $StepCounter is an integer, it is incremented each time an integration rule is applied.";


$RuleColor::usage = "$RuleColor is the color used to display rules when showing integration steps. The default rule color is red."
$ConditionColor::usage = "$ConditionColor is the color used to display application conditions when showing integration steps. The default condition color is blue."


sin::usage = "Inert sine function";
cos::usage = "Inert cosine function";
tan::usage = "Inert tangent function";
cot::usage = "Inert cotangent function";
sec::usage = "Inert secant function";
csc::usage = "Inert cosecant function";


Begin["`Private`"]

(*LoadRules[filename_String] :=
Module[{object},
object=PrintTemporary["Loading "<>filename<>".m..."];
Get[NotebookDirectory[]<>filename<>".m"];
NotebookDelete[object];
Null]*)

LoadRules[filename_String] := (
Print["Loading "<>filename<>".m..."];
Get["rubi/"<>filename<>".m"];
)


Unprotect[Int]; Clear[Int];


SetAttributes [Int, {Listable}];


ShowSteps = Global`$LoadShowSteps===True;


(*LoadRules["ShowStep routines"];*)
LoadRules["Integration utility functions"];
LoadRules["9.1 Integrand simplification rules"];


LoadRules["1.1.1 Linear binomial products"];
LoadRules["1.1.3 General binomial products"];

LoadRules["1.2.1 Quadratic trinomial products"];
LoadRules["1.2.2 Quartic trinomial products"];
LoadRules["1.2.3 General trinomial products"];
LoadRules["1.2.4 Improper trinomial products"];

LoadRules["1.1.4 Improper binomial products"];
LoadRules["1.3 Miscellaneous algebraic functions"];


LoadRules["9.3 Piecewise linear functions"];
LoadRules["2 Exponentials"];
LoadRules["3 Logarithms"];
LoadRules["4.1 Sine"];
LoadRules["4.2 Tangent"];
LoadRules["4.3 Secant"];
LoadRules["4.4 Miscellaneous trig functions"];
LoadRules["5 Inverse trig functions"];
LoadRules["6 Hyperbolic functions"];
LoadRules["7 Inverse hyperbolic functions"];
LoadRules["8 Special functions"];
LoadRules["9.2 Derivative integration rules"];
LoadRules["9.4 Miscellaneous integration rules"];


(*FixIntRules[];*)


(*If[Global`$LoadShowSteps===True, StepFunction[Int]];*)


Protect[Int];


End [];
EndPackage [];

(*Helper debug functions in global context.*)

printDownValues[args_, sym_] :=
Print /@ Map[{#, MatchQ[args, #]} &,
Map[List @@ (#[[1]][[1]]) &, DownValues[sym]]];
isPartialMatch[args_, dv_] := MatchQ[args, List @@ (dv[[1]][[1]])];
isFullMatch[args_, dv_, sym_] :=
Replace[args, dv /. sym -> List] =!= args;
printPartitalMatchingDownValues[args_, sym_, n_] :=
Select[DownValues[sym], isPartialMatch[args, #] &, n];
printMatchingDownValues[args_, sym_, n_] :=
Select[DownValues[sym], isFullMatch[args, #, sym] &, n];

10 changes: 6 additions & 4 deletions examples/test_rubi.m
Expand Up @@ -9,13 +9,15 @@
res = Int[testp[[1]], testp[[2]]];
(*Print[res];*)
(*Print[res === testp[[4]]];*)
If[res === testp[[4]], Print[thei]];
(*If[res === testp[[4]], Print[thei]];*)
If[res =!= testp[[4]], Print[thei]];
);

While[testi <= Length[testproblems],
(*Print["hi ", testi]*)
If[(testi>34&&testi<47)||MemberQ[{50, 52, 53, 54, 55, 56, 57, 58, 59, 211, 214, 215, 216, 218, 222, 223, 224, 225, 228, 229, 231, 232, 233}, testi] || (testi>=160&&testi<=166), Null,
Print["Testing ", testi, " ", testproblems[[testi]]]
(*If[(testi>34&&testi<47)||MemberQ[{50, 52, 53, 54, 55, 56, 57, 58, 59, 211, 214, 215, 216, 218, 222, 223, 224, 225, 228, 229, 231, 232, 233}, testi] || (testi>=160&&testi<=166), Null,
runRubiTest[testi];
];
];*)
runRubiTest[testi];
testi = testi+1;
];
14 changes: 11 additions & 3 deletions expreduce/builtin_system.go
Expand Up @@ -182,7 +182,15 @@ func applyModuleFn(this *Expression, es *EvalState) (Ex, bool) {
rhs = rhs.Eval(es)
}
es.defined[pl.uniqueName] = Def{
downvalues: []Expression{*NewExpression([]Ex{&Symbol{"System`Rule"}, &Symbol{pl.uniqueName}, rhs})},
downvalues: []DownValue{
DownValue{
rule: *NewExpression([]Ex{
&Symbol{"System`Rule"},
&Symbol{pl.uniqueName},
rhs,
}),
},
},
}
} else {
es.defined[pl.uniqueName] = Def{}
Expand Down Expand Up @@ -341,9 +349,9 @@ func GetSystemDefinitions() (defs []Definition) {
&Symbol{"System`RuleDelayed"},
NewExpression([]Ex{
&Symbol{"System`HoldPattern"},
dv.Parts[1],
dv.rule.Parts[1],
}),
dv.Parts[2],
dv.rule.Parts[2],
}))
}
return res
Expand Down
23 changes: 16 additions & 7 deletions expreduce/definition.go
Expand Up @@ -2,8 +2,13 @@ package expreduce

import "bytes"

type DownValue struct {
rule Expression
specificity int
}

type Def struct {
downvalues []Expression
downvalues []DownValue
attributes Attributes
defaultExpr Ex

Expand All @@ -15,8 +20,12 @@ func CopyDefs(in map[string]Def) map[string]Def {
out := make(map[string]Def)
for k, v := range in {
newDef := Def{}
for _, rule := range v.downvalues {
newDef.downvalues = append(newDef.downvalues, *rule.DeepCopy().(*Expression))
for _, dv := range v.downvalues {
newDv := DownValue{
rule: *dv.rule.DeepCopy().(*Expression),
specificity: dv.specificity,
}
newDef.downvalues = append(newDef.downvalues, newDv)
}
out[k] = newDef
}
Expand All @@ -26,8 +35,8 @@ func CopyDefs(in map[string]Def) map[string]Def {
func (this *Def) String() string {
var buffer bytes.Buffer
buffer.WriteString("{")
for i, e := range this.downvalues {
buffer.WriteString(e.String())
for i, dv := range this.downvalues {
buffer.WriteString(dv.rule.String())
if i != len(this.downvalues)-1 {
buffer.WriteString("\n")
}
Expand All @@ -39,8 +48,8 @@ func (this *Def) String() string {
func (def *Def) StringForm(form string, context *String, contextPath *Expression) string {
var buffer bytes.Buffer
buffer.WriteString("{")
for i, e := range def.downvalues {
buffer.WriteString(e.StringForm(form, context, contextPath))
for i, dv := range def.downvalues {
buffer.WriteString(dv.rule.StringForm(form, context, contextPath))
if i != len(def.downvalues)-1 {
buffer.WriteString("\n")
}
Expand Down
40 changes: 26 additions & 14 deletions expreduce/evalstate.go
Expand Up @@ -209,7 +209,7 @@ func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) {
}
this.Debugf("Inside GetDef(\"%s\",%s)", name, lhs)
for i := range this.defined[name].downvalues {
def := this.defined[name].downvalues[i]
def := this.defined[name].downvalues[i].rule

defStr, lhsDefStr := "", ""
started := int64(0)
Expand Down Expand Up @@ -268,7 +268,7 @@ func (this *EvalState) DefineAttrs(sym *Symbol, rhs Ex) {
func (this *EvalState) MarkSeen(name string) {
if !this.IsDef(name) {
newDef := Def{
downvalues: []Expression{},
downvalues: []DownValue{},
}
this.defined[name] = newDef
}
Expand All @@ -288,7 +288,7 @@ func ruleSpecificity(lhs Ex, rhs Ex) int {
// Condition rules will be ranked in order of definition, not
// specificity. I'm not entirely sure if this is correct, but it seems
// to be the case for all the Rubi rules.
specificity = 40
specificity = 100
}
return specificity
}
Expand Down Expand Up @@ -336,21 +336,27 @@ func (this *EvalState) Define(lhs Ex, rhs Ex) {
this.Debugf("Inside es.Define(\"%s\",%s,%s)", name, lhs, rhs)
if !this.IsDef(name) {
newDef := Def{
downvalues: []Expression{*NewExpression([]Ex{&Symbol{"System`Rule"}, lhs, rhs})},
downvalues: []DownValue{
DownValue{
rule: *NewExpression([]Ex{
&Symbol{"System`Rule"}, lhs, rhs,
}),
},
},
}
this.defined[name] = newDef
return
}

// Overwrite identical rules.
for i := range this.defined[name].downvalues {
existingRule := this.defined[name].downvalues[i]
existingRule := this.defined[name].downvalues[i].rule
existingLhs := existingRule.Parts[1]
if IsSameQ(existingLhs, lhs, &this.CASLogger) {
existingRhsCond := maskNonConditional(existingRule.Parts[2])
newRhsCond := maskNonConditional(rhs)
if IsSameQ(existingRhsCond, newRhsCond, &this.CASLogger) {
this.defined[name].downvalues[i].Parts[2] = rhs
this.defined[name].downvalues[i].rule.Parts[2] = rhs
return
}
}
Expand All @@ -361,24 +367,29 @@ func (this *EvalState) Define(lhs Ex, rhs Ex) {
var tmp = this.defined[name]
newSpecificity := ruleSpecificity(lhs, rhs)
for i := range this.defined[name].downvalues {
thisSpecificity := ruleSpecificity(
this.defined[name].downvalues[i].Parts[1],
this.defined[name].downvalues[i].Parts[2],
)
if thisSpecificity < newSpecificity {
if this.defined[name].downvalues[i].specificity == 0 {
this.defined[name].downvalues[i].specificity = ruleSpecificity(
this.defined[name].downvalues[i].rule.Parts[1],
this.defined[name].downvalues[i].rule.Parts[2],
)
}
if this.defined[name].downvalues[i].specificity < newSpecificity {
newRule := *NewExpression([]Ex{&Symbol{"System`Rule"}, lhs, rhs})
tmp.downvalues = append(
tmp.downvalues[:i],
append(
[]Expression{newRule},
[]DownValue{DownValue{
rule: newRule,
specificity: newSpecificity,
}},
this.defined[name].downvalues[i:]...,
)...,
)
this.defined[name] = tmp
return
}
}
tmp.downvalues = append(tmp.downvalues, *NewExpression([]Ex{&Symbol{"System`Rule"}, lhs, rhs}))
tmp.downvalues = append(tmp.downvalues, DownValue{rule: *NewExpression([]Ex{&Symbol{"System`Rule"}, lhs, rhs})})
this.defined[name] = tmp
}

Expand All @@ -389,7 +400,8 @@ func (this *EvalState) ClearAll() {
func (this *EvalState) Clear(name string) {
_, ok := this.defined[name]
if ok {
delete(this.defined, name)
this.defined[name] = Def{}
//delete(this.defined, name)
}
}

Expand Down
9 changes: 9 additions & 0 deletions expreduce/interp.go
Expand Up @@ -172,6 +172,7 @@ var unaryOps = map[int]string{
13: "Not",
115: "Factorial",
117: "Function",
15: "Plus",
}

var binaryOps = map[int]string{
Expand Down Expand Up @@ -349,6 +350,14 @@ func ParserExprConv(expr *wl.Expression) Ex {
set.Parts[2],
})
return e
case 137:
return NewExpression([]Ex{
NewExpression([]Ex{
&Symbol{"System`Derivative"},
NewInt(1),
}),
ParserExprConv(expr.Expression),
})
}
log.Fatalf("System`UnParsed: %+v %+v %+v", expr.Token, expr.Case, expr)
return nil
Expand Down

0 comments on commit b563d68

Please sign in to comment.