Skip to content

Commit

Permalink
Merge pull request #62 from corywalker/factorout
Browse files Browse the repository at this point in the history
Factor out numbertheory.
  • Loading branch information
corywalker committed Jul 22, 2017
2 parents 517caef + 7138a92 commit 79bdf32
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 97 deletions.
100 changes: 100 additions & 0 deletions 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))
}
}
98 changes: 1 addition & 97 deletions expreduce/builtin_numbertheory.go
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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"})
Expand Down
98 changes: 98 additions & 0 deletions expreduce/resources/numbertheory.m
@@ -1,15 +1,113 @@
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];
GCD[Rational[a_, b_], c_Integer, rest___] :=
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;
Expand Down

0 comments on commit 79bdf32

Please sign in to comment.