Skip to content

Commit

Permalink
Factor out arith|atoms|boolea|calcu
Browse files Browse the repository at this point in the history
  • Loading branch information
corywalker committed Jul 22, 2017
1 parent 51b4a41 commit aa9d42f
Show file tree
Hide file tree
Showing 12 changed files with 475 additions and 478 deletions.
6 changes: 3 additions & 3 deletions expreduce/builtin.go
Expand Up @@ -56,12 +56,12 @@ func ToTestInstructions(tc *Expression) []TestInstruction {
st.Parts[1].(*String).Val, st.Parts[2].(*String).Val})
continue
}
if comment, isComment := HeadAssertion(tiEx, "System`EComment"); isComment {
if len(comment.Parts) != 2 {
if st, isSt := HeadAssertion(tiEx, "System`EComment"); isSt {
if len(st.Parts) != 2 {
log.Fatalf("Invalid test case: %v\n", tiEx)
continue
}
comStr, comIsStr := comment.Parts[1].(*String)
comStr, comIsStr := st.Parts[1].(*String)
if !comIsStr {
log.Fatalf("Invalid test case: %v\n", tiEx)
continue
Expand Down
195 changes: 1 addition & 194 deletions expreduce/builtin_arithmetic.go
Expand Up @@ -221,14 +221,7 @@ func collectTerms(e *Expression) *Expression {
func getArithmeticDefinitions() (defs []Definition) {
defs = append(defs, Definition{
Name: "Plus",
Usage: "`(e1 + e2 + ...)` computes the sum of all expressions in the function.",
Attributes: []string{"Flat", "Listable", "NumericFunction", "OneIdentity", "Orderless"},
Default: "0",
Rules: []Rule{
//{"Verbatim[Plus][beg___, Optional[c1_?NumberQ]*a_, Optional[c2_?NumberQ]*a_, end___]", "beg+(c1+c2)*a+end"},
// The world is not ready for this madness.
//{"Verbatim[Plus][beg___, Verbatim[Times][Optional[c1_?NumberQ],a__], Verbatim[Times][Optional[c2_?NumberQ],a__], end___]", "beg+(c1+c2)*a+end"},
},
toString: func(this *Expression, form string, context *String, contextPath *Expression) (bool, string) {
return ToStringInfix(this.Parts[1:], " + ", form, context, contextPath)
},
Expand Down Expand Up @@ -264,129 +257,16 @@ func getArithmeticDefinitions() (defs []Definition) {

return res
},
SimpleExamples: []TestInstruction{
&SameTest{"2", "1 + 1"},
&TestComment{"If Reals are present, other Integers are demoted to Reals:"},
&SameTest{"0.", "(5.2 - .2) - 5"},
&TestComment{"Plus automatically combines like terms:"},
&SameTest{"a+6*b^2", "a + b^2 + 5*b^2"},
&SameTest{"((5 * c^a) + (3 * d))", "(a+b)-(a+b)+c-c+2*c^a+2*d+5*d+d-5*d+3*c^a"},
&SameTest{"-3 a b c d e f", "4*a*b*c*d*e*f + -7*a*b*c*d*e*f"},
},
Tests: []TestInstruction{
// Test automatic expansion
&StringTest{"(a + b)", "1*(a + b)"},
&StringTest{"(1. * (a + b))", "1.*(a + b)"},
&StringTest{"(2. * (a + b))", "2.*(a + b)"},
&StringTest{"(a + b)", "(a + b)/1"},
&StringTest{"(1. * (a + b))", "(a + b)/1."},
&StringTest{"(2 * (a + b))", "2*(a + b)"},
&StringTest{"(a * (b + c))", "a*(b + c)"},
&StringTest{"((-1 * a) + (-1 * b))", "-1*(a + b)"},
&StringTest{"((-1 * a) + (-1 * b))", "-(a + b)"},
&StringTest{"(-1. * (a + b))", "-1.*(a + b)"},
&StringTest{"((-1 * a) + (-1 * b))", "(a + b)/-1"},
&StringTest{"(-1. * (a + b))", "(a + b)/-1."},

// Test that we do not delete all the addends
&SameTest{"0.", "(5.2 - .2) - 5"},
&SameTest{"0", "0 + 0"},

// Test empty Plus expressions
&SameTest{"0", "Plus[]"},

// Test proper accumulation of Rationals
&StringTest{"(47/6 + sym)", "Rational[5, 2] + Rational[7, 3] + 3 + sym"},
&StringTest{"(17/6 + sym)", "Rational[5, -2] + Rational[7, 3] + 3 + sym"},
&StringTest{"(-19/6 + sym)", "Rational[5, -2] + Rational[7, 3] - 3 + sym"},
&StringTest{"(-47/6 + sym)", "Rational[5, -2] + Rational[-7, 3] - 3 + sym"},

// Test combining monomials of degree 1
&SameTest{"a+7*b", "a + 2*b + 5*b"},

// Test a more general version
&SameTest{"a+7*b", "a + 2*b + 5*b"},
&DiffTest{"a+7*b", "a + 2*b^2 + 5*b^2"},
&SameTest{"a+7*b^2", "a + 2*b^2 + 5*b^2"},
&SameTest{"a+3*b^2", "a - 2*b^2 + 5*b^2"},

// Test using terms without a coefficient
&SameTest{"a+6*b^2", "a + b^2 + 5*b^2"},

// Test additive identity
&SameTest{"a", "a+0"},
&SameTest{"a+b", "(a+b)+0"},

// Test additive inverse
&SameTest{"0", "a-a"},
&SameTest{"0", "-a + a"},
&SameTest{"0", "(a+b)-(a+b)"},
&SameTest{"0", "-(a+b)+(a+b)"},
&SameTest{"0", "(a+b)-(a+b)"},
&SameTest{"0", "-(a+b)+(a+b)"},

// Test basic simplifications
&SameTest{"d", "(a+b)-(a+b)+c-c+d"},
&SameTest{"((5 * c^a) + (3 * d))", "(a+b)-(a+b)+c-c+2*c^a+2*d+5*d+d-5*d+3*c^a"},
&SameTest{"87.5 + 3 * x", "((x + 80. + 3. + x) + 2. + x + 2.5)"},
&SameTest{"87.5 + (7. * x)", "((x + 80. + 3. + x) + 2. + (x * 2. * 2.) + (0. * 3. * x) + x + 2.5)"},
&SameTest{"50*a", "a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a"},

// More complicated term combining
&SameTest{"-3 * m - 10 * n", "-9 * n - n - 3 * m"},

&SameTest{"7*a * b - 2*a * c", "3*a*b - 2*a*c + 4*a*b"},
&SameTest{"-3*a - 2*b + 3*a*b", "2*a - 4*b + 3*a*b - 5*a + 2*b"},
&SameTest{"7*x - 11*y + x*y", "8*x - 9*y - 3*x*y - 2*y - x + 4*x*y"},
&SameTest{"-3*a*b*c*d*e*f", "4*a*b*c*d*e*f + -7*a*b*c*d*e*f"},
&SameTest{"-3*a*b*c*d*e*f", "a*b*c*4*d*e*f + -a*b*c*d*e*f*7"},
&SameTest{"-3*a*b*c*d*e*f", "a*b*2*c*2*d*e*f + -a*b*c*d*e*f*7"},
&SameTest{"2 r + 2 t", "2 r - 3 s - t + 3 t + 3 s"},
&SameTest{"3 (x - 2 y) - 4 x y + 2 (-1 + x y)", "2 (x*y - 1) + 3 (x - 2 y) - 4 x*y"},
&SameTest{"-4 s + 4 r s - 3 (1 + r s)", "4 r*s - 2 s - 3 (r*s + 1) - 2 s"},
&SameTest{"7 y - z + 3 y z", "8 y - 2 z - (y - z) + 3 y*z"},
},
})
defs = append(defs, Definition{
Name: "Sum",
Usage: "`Sum[expr, n]` returns the sum of `n` copies of `expr`.\n\n" +
"`Sum[expr, {sym, n}]` returns the sum of `expr` evaluated with `sym` = 1 to `n`.\n\n" +
"`Sum[expr, {sym, m, n}]` returns the sum of `expr` evaluated with `sym` = `m` to `n`.",
Attributes: []string{"HoldAll", "ReadProtected"},
Rules: []Rule{
{"Sum[i_Symbol, {i_Symbol, 0, n_Integer}]", "1/2*n*(1 + n)"},
{"Sum[i_Symbol, {i_Symbol, 1, n_Integer}]", "1/2*n*(1 + n)"},
{"Sum[i_Symbol, {i_Symbol, n_Integer}]", "1/2*n*(1 + n)"},
{"Sum[i_Symbol, {i_Symbol, 0, n_Symbol}]", "1/2*n*(1 + n)"},
{"Sum[i_Symbol, {i_Symbol, 1, n_Symbol}]", "1/2*n*(1 + n)"},
},
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
return this.evalIterationFunc(es, &Integer{big.NewInt(0)}, "System`Plus")
},
SimpleExamples: []TestInstruction{
&SameTest{"45", "Sum[i, {i, 5, 10}]"},
&SameTest{"55", "Sum[i, {i, 1, 10}]"},
&SameTest{"55", "Sum[i, {i, 0, 10}]"},
&SameTest{"450015000", "Sum[i, {i, 1, 30000}]"},
&SameTest{"450015000", "Sum[i, {i, 0, 30000}]"},
&SameTest{"1/2*n*(1 + n)", "Sum[i, {i, 0, n}]"},
&SameTest{"1/2*n*(1 + n)", "Sum[i, {i, 1, n}]"},
&SameTest{"30", "Sum[a + b, {a, 0, 2}, {b, 0, 3}]"},
&SameTest{"b+c+d+e", "Sum[a, {a, {b, c, d, e}}]"},
&SameTest{"b g + c g + d g + e g + b h + c h + d h + e h", "Sum[a*f, {a, {b, c, d, e}}, {f, {g, h}}]"},
},
})
defs = append(defs, Definition{
Name: "Times",
Usage: "`(e1 * e2 * ...)` computes the product of all expressions in the function.",
Attributes: []string{"Flat", "Listable", "NumericFunction", "OneIdentity", "Orderless"},
Default: "1",
Rules: []Rule{
{"Verbatim[Times][beg___, a_^Optional[m_], a_^Optional[n_], end___]", "beg*a^(m+n)*end"},
{"Times[den_Integer^-1, num_Integer, rest___]", "Rational[num,den] * rest"},
{"(1/Infinity)", "0"},
{"Times[ComplexInfinity, rest___]", "ComplexInfinity"},
},
toString: func(this *Expression, form string, context *String, contextPath *Expression) (bool, string) {
return ToStringInfix(this.Parts[1:], " * ", form, context, contextPath)
},
Expand Down Expand Up @@ -451,86 +331,13 @@ func getArithmeticDefinitions() (defs []Definition) {

return res
},
SimpleExamples: []TestInstruction{
&TestComment{"Simplification rules apply automatically:"},
&SameTest{"3/2", "(3 + (x^2 * 0)) * 2^-1"},
&SameTest{"a^(2+c)", "a^2*a^c"},
&SameTest{"a/(b*c*d)", "a/b/c/d"},
},
FurtherExamples: []TestInstruction{
&TestComment{"Rational numbers are suppported (explicit rational declaration added for clarity):"},
&StringTest{"-2/3", "Rational[1, -2]*Rational[-2, 3]*-2"},
&TestComment{"The product of nothing is defined to be one:"},
&SameTest{"1", "Times[]"},
},
Tests: []TestInstruction{
// Test that we do not delete all the multiplicands
&SameTest{"1", "1*1"},
&SameTest{"1", "5*1/5*1"},

// Test empty Times expressions
&SameTest{"1", "Times[]"},

// Test fraction simplification
&SameTest{"25", "50/2"},
&SameTest{"50", "100/2"},
&SameTest{"50", "1/2*100"},
&SameTest{"5/4", "1/2*5/2"},
&SameTest{"1/4", "1/2*1/2"},
&SameTest{"a/(b*c*d)", "a/b/c/d"},

// Test Rational detection
&StringTest{"10", "40/2^2"},
&StringTest{"10", "40/4"},
&StringTest{"40/3", "40/3"},
&StringTest{"20/3", "40/6"},
&StringTest{"10", "1/4*40"},
&StringTest{"10", "1/(2^2)*40"},

// Test proper accumulation of Rationals
&StringTest{"(2 * sym)", "sym*Rational[1,2]*Rational[2,3]*6"},
&StringTest{"-2/3", "Rational[1, -2]*Rational[-2, 3]*-2"},
&StringTest{"Rational", "Rational[1, -2]*Rational[-2, 3]*-2 // Head"},

// Test multiplicative identity
&StringTest{"5", "5*1"},
&StringTest{"a", "1*a"},
&StringTest{"(1. * a)", "1.*a"},

// Test multiplicative inverse
&StringTest{"1", "8*1/8"},
&StringTest{"1", "a*1/a"},
&StringTest{"1", "1/a*a"},

// Test multiplicative property of zero
&SameTest{"3/2", "(3 + (x^2 * 0)) * 2^-1"},

// Simplifications with Power
&SameTest{"a^(2+c)", "a^2*a^c"},
&SameTest{"a^(2-c)", "a^2/a^c"},
&SameTest{"m^2", "m*m"},
&SameTest{"1", "m/m"},
&SameTest{"1", "m^2/m^2"},
},
})
defs = append(defs, Definition{
Name: "Product",
Usage: "`Product[expr, n]` returns the product of `n` copies of `expr`.\n\n" +
"`Product[expr, {sym, n}]` returns the product of `expr` evaluated with `sym` = 1 to `n`.\n\n" +
"`Product[expr, {sym, m, n}]` returns the product of `expr` evaluated with `sym` = `m` to `n`.",
Attributes: []string{"HoldAll", "ReadProtected"},
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
return this.evalIterationFunc(es, &Integer{big.NewInt(1)}, "System`Times")
},
SimpleExamples: []TestInstruction{
&SameTest{"120", "Product[a, {a, 1, 5}]"},
&SameTest{"f[1] * f[2] * f[3] * f[4] * f[5]", "Product[f[a], {a, 1, 5}]"},
&SameTest{"576", "Product[a^2, {a, 4}]"},
&SameTest{"1440", "Product[a + b, {a, 1, 2}, {b, 1, 3}]"},
},
})
defs = append(defs, Definition{
Name: "Abs",
})
defs = append(defs, Definition{Name: "Abs"})
return
}
89 changes: 3 additions & 86 deletions expreduce/builtin_atoms.go
Expand Up @@ -3,7 +3,6 @@ package expreduce
func getAtomsDefinitions() (defs []Definition) {
defs = append(defs, Definition{
Name: "Rational",
Usage: "`Rational` is the head for the atomic rational type.",
legacyEvalFn: func(this *Expression, es *EvalState) Ex {
if len(this.Parts) != 3 {
return this
Expand All @@ -15,91 +14,9 @@ func getAtomsDefinitions() (defs []Definition) {
}
return this
},
SimpleExamples: []TestInstruction{
&TestComment{"Rationals are created from `Times` when a rational form is encountered:"},
&SameTest{"Rational", "Times[5, 6^-1] // Head"},
&TestComment{"Which is equivalent to typing them in directly:"},
&SameTest{"Rational", "5/6 // Head"},
&TestComment{"Or being even more explicit:"},
&SameTest{"Rational", "Rational[5, 6] // Head"},
&TestComment{"Rationals simplify on evaluation:"},
&StringTest{"5/3", "Rational[10, 6]"},
&TestComment{"Which might include evaluating to an Integer:"},
&SameTest{"Integer", "Rational[-100, 10] // Head"},
&TestComment{"Rationals of non-Integer types are not allowed:"},
&StringTest{"Rational[0, n]", "Rational[0, n]"},
},
FurtherExamples: []TestInstruction{
&TestComment{"Undefined rationals are handled accordingly:"},
&StringTest{"Indeterminate", "Rational[0, 0]"},
&StringTest{"ComplexInfinity", "Rational[1, 0]"},
&TestComment{"Rational numbers have some special handling for pattern matching:"},
&SameTest{"2/3", "test = Rational[2, 3]"},
&SameTest{"True", "MatchQ[test, 2/3]"},
&SameTest{"True", "MatchQ[test, Rational[a_Integer, b_Integer]]"},
&SameTest{"{2, 3}", "2/3 /. Rational[a_Integer, b_Integer] -> {a, b}"},
&SameTest{"2/3", "2/3 /. a_Integer/b_Integer -> {a, b}"},
},
Tests: []TestInstruction{
&StringTest{"10/7", "Rational[10, 7]"},
&StringTest{"Rational[x, 10]", "Rational[x, 10]"},
&StringTest{"10", "Rational[100, 10]"},
&StringTest{"-10", "Rational[-100, 10]"},
&StringTest{"10", "Rational[-100, -10]"},
&StringTest{"-5/3", "Rational[-10, 6]"},
&StringTest{"5/3", "Rational[-10, -6]"},
&StringTest{"0", "Rational[0, 5]"},
&StringTest{"Rational[0, n]", "Rational[0, n]"},
&StringTest{"ComplexInfinity", "Rational[-1, 0]"},
&StringTest{"ComplexInfinity", "Rational[-1, -0]"},
&StringTest{"Indeterminate", "Rational[-0, -0]"},
&StringTest{"Indeterminate", "Rational[-0, 0]"},

// Rational matching and replacement
&SameTest{"buzz[bar]", "foo[bar, 1/2] /. foo[base_, 1/2] -> buzz[base]"},
&SameTest{"buzz[bar]", "foo[bar, 1/2] /. foo[base_, Rational[1, 2]] -> buzz[base]"},
&SameTest{"buzz[bar]", "foo[bar, Rational[1, 2]] /. foo[base_, 1/2] -> buzz[base]"},
&SameTest{"buzz[bar]", "foo[bar, Rational[1, 2]] /. foo[base_, Rational[1, 2]] -> buzz[base]"},
&SameTest{"True", "MatchQ[1/2, Rational[1, 2]]"},
&SameTest{"True", "MatchQ[Rational[1, 2], 1/2]"},
&SameTest{"False", "Hold[Rational[1, 2]] === Hold[1/2]"},
},
})
defs = append(defs, Definition{
Name: "String",
Usage: "`String` is the head for the atomic string type.",
SimpleExamples: []TestInstruction{
&SameTest{"\"Hello\"", "\"Hello\""},
&SameTest{"True", "\"Hello\" == \"Hello\""},
&SameTest{"False", "\"Hello\" == \"Hello world\""},
&SameTest{"String", "Head[\"Hello\"]"},
},
})
defs = append(defs, Definition{
Name: "Real",
Usage: "`Real` is the head for the atomic floating point type.",
SimpleExamples: []TestInstruction{
&SameTest{"Real", "Head[1.53]"},
&TestComment{"One can force Real interperetation on an Integer by appending a decimal point:"},
&SameTest{"Real", "Head[1.]"},
&TestComment{"Real numbers are backed by arbitrary-precision floating points:"},
&StringTest{"10.", "10.^5000 / 10.^4999"},
},
FurtherExamples: []TestInstruction{
&SameTest{"True", "MatchQ[1.53, _Real]"},
},
})
defs = append(defs, Definition{
Name: "Integer",
Usage: "`Integer` is the head for the atomic integer type.",
SimpleExamples: []TestInstruction{
&SameTest{"Integer", "Head[153]"},
&TestComment{"Integer numbers are backed by arbitrary-precision data structures:"},
&SameTest{"815915283247897734345611269596115894272000000000", "Factorial[40]"},
},
FurtherExamples: []TestInstruction{
&SameTest{"True", "MatchQ[153, _Integer]"},
},
})
defs = append(defs, Definition{Name: "String"})
defs = append(defs, Definition{Name: "Real"})
defs = append(defs, Definition{Name: "Integer"})
return
}

0 comments on commit aa9d42f

Please sign in to comment.