From 7138a92e97b0831bf167e9f202d969a79826154b Mon Sep 17 00:00:00 2001 From: cmwslw Date: Sat, 22 Jul 2017 02:57:57 -0700 Subject: [PATCH] Factor out numbertheory. --- example/factorout.go | 100 +++++++++++++++++++++++++++++ expreduce/builtin_numbertheory.go | 98 +--------------------------- expreduce/resources/numbertheory.m | 98 ++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 97 deletions(-) create mode 100644 example/factorout.go diff --git a/example/factorout.go b/example/factorout.go new file mode 100644 index 0000000..239d0df --- /dev/null +++ b/example/factorout.go @@ -0,0 +1,100 @@ +package main + +import ( + "fmt" + "bytes" + "flag" + "strings" + "regexp" + "log" + "github.com/corywalker/expreduce/expreduce" +) + +var modules = flag.String("modules", "", + "A regexp of modules to include, otherwise include all modules.") + +func main() { + flag.Parse() + //es := expreduce.NewEvalState() + var ModEx = regexp.MustCompile(*modules) + for _, defSet := range expreduce.GetAllDefinitions() { + if !ModEx.MatchString(defSet.Name) { + continue + } + var b bytes.Buffer + for _, def := range defSet.Defs { + if def.Bootstrap { + continue + } + if def.Usage != "" { + b.WriteString(fmt.Sprintf("%s::usage = \"%v\";\n", def.Name, def.Usage)) + for _, r := range def.Rules { + b.WriteString(fmt.Sprintf("%v := %v;\n", r.Lhs, r.Rhs)) + } + b.WriteString(fmt.Sprintf("Attributes[%v] = {", def.Name)) + for _, a := range def.Attributes { + b.WriteString(fmt.Sprintf("%s, ", a)) + } + b.WriteString(fmt.Sprintf("Protected};\n")) + var tests bytes.Buffer + hasTests := false + tests.WriteString(fmt.Sprintf("Tests`%v = {\n\t", def.Name)) + testCols := [][]expreduce.TestInstruction{ + def.SimpleExamples, + def.FurtherExamples, + def.Tests, + def.KnownFailures, + def.KnownDangerous, + } + testColNames := []string{ + "ESimpleExamples", + "EFurtherExamples", + "ETests", + "EKnownFailures", + "EKnownDangerous", + } + for i, testCol := range testCols { + if len(testCol) > 0 { + //fmt.Println(testCol, testColNames[i]) + if hasTests { + tests.WriteString(fmt.Sprintf(", %v[\n", testColNames[i])) + } else { + tests.WriteString(fmt.Sprintf("%v[\n", testColNames[i])) + } + for ti, t := range testCol { + tests.WriteString(fmt.Sprintf("\t\t")) + if tSame, tIsSame := t.(*expreduce.SameTest); tIsSame { + tests.WriteString(fmt.Sprintf("ESameTest[%v, %v]", tSame.Out, tSame.In)) + } else if tComment, tIsComment := t.(*expreduce.TestComment); tIsComment { + tests.WriteString(fmt.Sprintf("EComment[\"%v\"]", tComment.Comment)) + } else if tString, tIsString := t.(*expreduce.StringTest); tIsString { + tests.WriteString(fmt.Sprintf("EStringTest[\"%v\", \"%v\"]", tString.Out, tString.In)) + } else if tDiff, tIsDiff := t.(*expreduce.DiffTest); tIsDiff { + tests.WriteString(fmt.Sprintf("EDiffTest[%v, %v]", tDiff.Out, tDiff.In)) + } else if tExampleOnly, tIsExampleOnly := t.(*expreduce.ExampleOnlyInstruction); tIsExampleOnly { + tests.WriteString(fmt.Sprintf("EExampleOnlyInstruction[\"%v\", \"%v\"]", tExampleOnly.Out, tExampleOnly.In)) + } else if _, tIsResetState := t.(*expreduce.ResetState); tIsResetState { + tests.WriteString(fmt.Sprintf("EResetState[]")) + } else { + tests.WriteString(fmt.Sprintf("%v", t)) + log.Fatalf("%v %v %v", t, defSet.Name, def.Name) + } + if ti != len(testCol)-1 { + tests.WriteString(fmt.Sprintf(",")) + } + tests.WriteString(fmt.Sprintf("\n")) + } + tests.WriteString(fmt.Sprintf("\t]")) + hasTests = true + } + } + tests.WriteString(fmt.Sprintf("\n};")) + if hasTests { + b.WriteString(fmt.Sprintf("%v\n", tests.String())) + } + b.WriteString(fmt.Sprintf("\n")) + } + } + fmt.Printf("%s\n", strings.Replace(b.String(), "\t", " ", -1)) + } +} diff --git a/expreduce/builtin_numbertheory.go b/expreduce/builtin_numbertheory.go index 2350006..cb4b1a1 100644 --- a/expreduce/builtin_numbertheory.go +++ b/expreduce/builtin_numbertheory.go @@ -5,30 +5,10 @@ import "math/big" func GetNumberTheoryDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "PrimeQ", - Usage: "`PrimeQ[n]` returns True if `n` is prime, False otherwise.", - Attributes: []string{"Listable"}, legacyEvalFn: singleParamQEval(primeQ), - SimpleExamples: []TestInstruction{ - &SameTest{"True", "PrimeQ[5]"}, - &SameTest{"False", "PrimeQ[100]"}, - &SameTest{"True", "PrimeQ[982451653]"}, - &SameTest{"True", "PrimeQ[-2]"}, - }, - FurtherExamples: []TestInstruction{ - &TestComment{"`PrimeQ` only works for Integers:"}, - &SameTest{"False", "PrimeQ[5.]"}, - }, - Tests: []TestInstruction{ - &SameTest{"False", "PrimeQ[0]"}, - &SameTest{"False", "PrimeQ[1]"}, - &SameTest{"False", "PrimeQ[-1]"}, - &SameTest{"False", "PrimeQ[0.5]"}, - }, }) defs = append(defs, Definition{ Name: "GCD", - Usage: "`GCD[n1, n2, ...]` finds the greatest common denominator of the integer inputs.", - Attributes: []string{"Flat", "Listable", "OneIdentity", "Orderless"}, legacyEvalFn: func(this *Expression, es *EvalState) Ex { zero := big.NewInt(0) var ints [](*big.Int) @@ -58,70 +38,10 @@ func GetNumberTheoryDefinitions() (defs []Definition) { } return &Integer{gcd} }, - SimpleExamples: []TestInstruction{ - &SameTest{"3", "GCD[9, 6]"}, - &SameTest{"5", "GCD[100, 30, 15]"}, - }, - Tests: []TestInstruction{ - &SameTest{"1", "GCD[9, 2]"}, - &SameTest{"10", "GCD[100, 0, 10]"}, - &SameTest{"3", "GCD[9, 3]"}, - &SameTest{"10", "GCD[100, 30, 10]"}, - &SameTest{"10", "GCD[100, 30]"}, - &SameTest{"1", "GCD[100, 30, -1]"}, - &SameTest{"10", "GCD[100, 30, -60]"}, - &SameTest{"60", "GCD[-60, -60, -60]"}, - &SameTest{"GCD[-60, -60, -0.5]", "GCD[-60, -60, -0.5]"}, - &SameTest{"GCD[0.5]", "GCD[0.5]"}, - &SameTest{"GCD[1, a]", "GCD[1, a]"}, - &SameTest{"GCD[a, a]", "GCD[a, a]"}, - &SameTest{"0", "GCD[]"}, - &SameTest{"1", "GCD[1]"}, - &SameTest{"GCD[a]", "GCD[a]"}, - &SameTest{"1000", "GCD[1000]"}, - &SameTest{"5", "GCD[5, 15]"}, - &SameTest{"5", "GCD[5, 15, 30]"}, - &SameTest{"5", "GCD[10, 20, 25]"}, - &SameTest{"1", "GCD[5, 14]"}, - &SameTest{"5/2", "GCD[5/2, 15/2]"}, - &SameTest{"5/3", "GCD[5/3, 5]"}, - &SameTest{"GCD[5/3,a]", "GCD[5/3, a]"}, - &SameTest{"GCD[a,b,c]", "GCD[a, b, c]"}, - &SameTest{"0", "GCD[0]"}, - &SameTest{"0", "GCD[0, 0]"}, - &SameTest{"99", "GCD[-99]"}, - &SameTest{"5/2", "GCD[-5/2]"}, - &SameTest{"5", "GCD[10, -20, 25]"}, - &SameTest{"1", "GCD[5, -14]"}, - &SameTest{"5/2", "GCD[5/2, -15/2]"}, - &SameTest{"5/2", "GCD[5/2, -15/2, -15/2]"}, - &SameTest{"5/3", "GCD[-5/3, -5]"}, - &SameTest{"5/3", "GCD[-5/3, -5]"}, - &SameTest{"GCD[-(5/3),a]", "GCD[-5/3, a]"}, - }, - }) - defs = append(defs, Definition{ - Name: "LCM", - Usage: "`LCM[n1, n2, ...]` finds the least common multiple of the inputs.", - SimpleExamples: []TestInstruction{ - &SameTest{"70", "LCM[5, 14]"}, - &SameTest{"2380", "LCM[5, 14, 68]"}, - &SameTest{"2/3", "LCM[2/3, 1/3]"}, - &SameTest{"10/3", "LCM[2/3, 1/3, 5/6]"}, - &SameTest{"30", "LCM[2/3, 1/3, 5/6, 3]"}, - &SameTest{"{2/3,10/3,6}", "LCM[2/3, {1/3, 5/6, 3}]"}, - }, - Tests: []TestInstruction{ - &SameTest{"{10/3,10/3,30}", "LCM[2/3, {1/3, 5/6, 3}, 5/6]"}, - &SameTest{"LCM[a,b]", "LCM[a, b]"}, - &SameTest{"LCM[a,b,c]", "LCM[a, b, c]"}, - &SameTest{"LCM[5,6,c]", "LCM[5, 6, c]"}, - }, }) + defs = append(defs, Definition{Name: "LCM"}) defs = append(defs, Definition{ Name: "Mod", - Usage: "`Mod[x, y]` finds the remainder when `x` is divided by `y`.", - Attributes: []string{"Listable", "NumericFunction", "ReadProtected"}, legacyEvalFn: func(this *Expression, es *EvalState) Ex { if len(this.Parts) != 3 { return this @@ -138,22 +58,6 @@ func GetNumberTheoryDefinitions() (defs []Definition) { m.Mod(xi.Val, yi.Val) return &Integer{m} }, - SimpleExamples: []TestInstruction{ - &SameTest{"2", "Mod[5,3]"}, - &SameTest{"0", "Mod[0,3]"}, - &SameTest{"Indeterminate", "Mod[2,0]"}, - }, - Tests: []TestInstruction{ - &SameTest{"1", "Mod[-5,3]"}, - &SameTest{"Mod[a,3]", "Mod[a,3]"}, - &SameTest{"Indeterminate", "Mod[0,0]"}, - &SameTest{"Mod[2,a]", "Mod[2,a]"}, - &SameTest{"Mod[0,a]", "Mod[0,a]"}, - }, - KnownFailures: []TestInstruction{ - &SameTest{"1.5", "Mod[1.5,3]"}, - &SameTest{"0.", "Mod[2,0.5]"}, - }, }) defs = append(defs, Definition{Name: "EvenQ"}) defs = append(defs, Definition{Name: "OddQ"}) diff --git a/expreduce/resources/numbertheory.m b/expreduce/resources/numbertheory.m index c303d97..7eb653a 100644 --- a/expreduce/resources/numbertheory.m +++ b/expreduce/resources/numbertheory.m @@ -1,3 +1,23 @@ +PrimeQ::usage = "`PrimeQ[n]` returns True if `n` is prime, False otherwise."; +Attributes[PrimeQ] = {Listable, Protected}; +Tests`PrimeQ = { + ESimpleExamples[ + ESameTest[True, PrimeQ[5]], + ESameTest[False, PrimeQ[100]], + ESameTest[True, PrimeQ[982451653]], + ESameTest[True, PrimeQ[-2]] + ], EFurtherExamples[ + EComment["`PrimeQ` only works for Integers:"], + ESameTest[False, PrimeQ[5.]] + ], ETests[ + ESameTest[False, PrimeQ[0]], + ESameTest[False, PrimeQ[1]], + ESameTest[False, PrimeQ[-1]], + ESameTest[False, PrimeQ[0.5]] + ] +}; + +GCD::usage = "`GCD[n1, n2, ...]` finds the greatest common denominator of the integer inputs."; (* Eventually we should not need the rest___ term. GCD is Flat. *) GCD[Rational[a_, b_], Rational[c_, d_], rest___] := GCD[GCD[a*d, c*b]/(b*d), rest]; @@ -5,11 +25,89 @@ GCD[GCD[a, c*b]/b, rest]; (*This deviates from how it should be done*) GCD[a_Rational] := Abs[a]; +Attributes[GCD] = {Flat, Listable, OneIdentity, Orderless, Protected}; +Tests`GCD = { + ESimpleExamples[ + ESameTest[3, GCD[9, 6]], + ESameTest[5, GCD[100, 30, 15]] + ], ETests[ + ESameTest[1, GCD[9, 2]], + ESameTest[10, GCD[100, 0, 10]], + ESameTest[3, GCD[9, 3]], + ESameTest[10, GCD[100, 30, 10]], + ESameTest[10, GCD[100, 30]], + ESameTest[1, GCD[100, 30, -1]], + ESameTest[10, GCD[100, 30, -60]], + ESameTest[60, GCD[-60, -60, -60]], + ESameTest[GCD[-60, -60, -0.5], GCD[-60, -60, -0.5]], + ESameTest[GCD[0.5], GCD[0.5]], + ESameTest[GCD[1, a], GCD[1, a]], + ESameTest[GCD[a, a], GCD[a, a]], + ESameTest[0, GCD[]], + ESameTest[1, GCD[1]], + ESameTest[GCD[a], GCD[a]], + ESameTest[1000, GCD[1000]], + ESameTest[5, GCD[5, 15]], + ESameTest[5, GCD[5, 15, 30]], + ESameTest[5, GCD[10, 20, 25]], + ESameTest[1, GCD[5, 14]], + ESameTest[5/2, GCD[5/2, 15/2]], + ESameTest[5/3, GCD[5/3, 5]], + ESameTest[GCD[5/3,a], GCD[5/3, a]], + ESameTest[GCD[a,b,c], GCD[a, b, c]], + ESameTest[0, GCD[0]], + ESameTest[0, GCD[0, 0]], + ESameTest[99, GCD[-99]], + ESameTest[5/2, GCD[-5/2]], + ESameTest[5, GCD[10, -20, 25]], + ESameTest[1, GCD[5, -14]], + ESameTest[5/2, GCD[5/2, -15/2]], + ESameTest[5/2, GCD[5/2, -15/2, -15/2]], + ESameTest[5/3, GCD[-5/3, -5]], + ESameTest[5/3, GCD[-5/3, -5]], + ESameTest[GCD[-(5/3),a], GCD[-5/3, a]] + ] +}; +LCM::usage = "`LCM[n1, n2, ...]` finds the least common multiple of the inputs."; LCM[a_?NumberQ, b_?NumberQ] := (a/GCD[a, b])*b; LCM[a_?NumberQ, b_?NumberQ, rest__?NumberQ] := LCM[LCM[a, b], rest]; Attributes[LCM]={Flat,Listable,OneIdentity,Orderless,Protected}; +Tests`LCM = { + ESimpleExamples[ + ESameTest[70, LCM[5, 14]], + ESameTest[2380, LCM[5, 14, 68]], + ESameTest[2/3, LCM[2/3, 1/3]], + ESameTest[10/3, LCM[2/3, 1/3, 5/6]], + ESameTest[30, LCM[2/3, 1/3, 5/6, 3]], + ESameTest[{2/3,10/3,6}, LCM[2/3, {1/3, 5/6, 3}]] + ], ETests[ + ESameTest[{10/3,10/3,30}, LCM[2/3, {1/3, 5/6, 3}, 5/6]], + ESameTest[LCM[a,b], LCM[a, b]], + ESameTest[LCM[a,b,c], LCM[a, b, c]], + ESameTest[LCM[5,6,c], LCM[5, 6, c]] + ] +}; + +Mod::usage = "`Mod[x, y]` finds the remainder when `x` is divided by `y`."; +Attributes[Mod] = {Listable, NumericFunction, ReadProtected, Protected}; +Tests`Mod = { + ESimpleExamples[ + ESameTest[2, Mod[5,3]], + ESameTest[0, Mod[0,3]], + ESameTest[Indeterminate, Mod[2,0]] + ], ETests[ + ESameTest[1, Mod[-5,3]], + ESameTest[Mod[a,3], Mod[a,3]], + ESameTest[Indeterminate, Mod[0,0]], + ESameTest[Mod[2,a], Mod[2,a]], + ESameTest[Mod[0,a], Mod[0,a]] + ], EKnownFailures[ + ESameTest[1.5, Mod[1.5,3]], + ESameTest[0., Mod[2,0.5]] + ] +}; EvenQ::usage = "`EvenQ[n]` returns True if `n` is an even integer."; EvenQ[n_Integer] := Mod[n,2]===0;