diff --git a/.travis.yml b/.travis.yml index f4f5f63..2dd891d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ os: language: go go: - - "1.6" - - "1.7" - "1.8" - "1.9" - "1.10" diff --git a/expreduce.go b/expreduce.go index 490df18..6401cce 100644 --- a/expreduce.go +++ b/expreduce.go @@ -1,17 +1,21 @@ package main import ( + "bufio" + "bytes" "flag" "fmt" - "github.com/corywalker/expreduce/expreduce" - "gopkg.in/readline.v1" "log" - "os" - "bytes" - "bufio" - "runtime/pprof" "net/http" _ "net/http/pprof" + "os" + "runtime/pprof" + + "github.com/corywalker/expreduce/expreduce" + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "gopkg.in/readline.v1" ) var debug = flag.Bool("debug", false, "Debug mode. No initial definitions.") @@ -21,13 +25,10 @@ var netprofile = flag.Bool("netprofile", false, "Enable live profiling at http:/ var scriptfile = flag.String("script", "", "script `file` to read from") var initfile = flag.String("initfile", "", "A script to run on initialization.") - - - func main() { flag.Parse() - if *cpuprofile != "" { + if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) @@ -74,14 +75,12 @@ func main() { } } - func scriptSession(es *expreduce.EvalState, srcText string, srcPath string) { exp := expreduce.EvalInterpMany(srcText, srcPath, es) - res := exp.Eval(es) + res := es.Eval(exp) res = es.ProcessTopLevelResult(res, res) } - func interactiveSession(es *expreduce.EvalState) { rl, err := readline.NewEx(&readline.Config{ HistoryFile: "/tmp/readline.tmp", @@ -113,8 +112,8 @@ func interactiveSession(es *expreduce.EvalState) { } fmt.Printf("\n") - exp := expreduce.Interp(line, es) - res := exp.Eval(es) + exp := parser.Interp(line, es) + res := es.Eval(exp) res = es.ProcessTopLevelResult(exp, res) printFormattedOutput(es, res, true, promptNum) @@ -122,10 +121,9 @@ func interactiveSession(es *expreduce.EvalState) { } } - -func printFormattedOutput(es *expreduce.EvalState, res expreduce.Ex, isInteractive bool, promptNum int) { +func printFormattedOutput(es *expreduce.EvalState, res expreduceapi.Ex, isInteractive bool, promptNum int) { isNull := false - asSym, isSym := res.(*expreduce.Symbol) + asSym, isSym := res.(*atoms.Symbol) if isSym { if asSym.Name == "System`Null" { isNull = true @@ -140,7 +138,7 @@ func printFormattedOutput(es *expreduce.EvalState, res expreduce.Ex, isInteracti } wasSpecialForm := false for _, specialForm := range specialForms { - asSpecialForm, isSpecialForm := expreduce.HeadAssertion( + asSpecialForm, isSpecialForm := atoms.HeadAssertion( res, specialForm) if !isSpecialForm { continue diff --git a/expreduce/atoms/calculator.go b/expreduce/atoms/calculator.go new file mode 100644 index 0000000..ef6e9a1 --- /dev/null +++ b/expreduce/atoms/calculator.go @@ -0,0 +1,141 @@ +package atoms + +import "github.com/corywalker/expreduce/pkg/expreduceapi" + +type foldFn int + +const ( + // FoldFnAdd designates that values should be added. + FoldFnAdd foldFn = iota + // FoldFnMul designates that values should be multiplied. + FoldFnMul +) + +func typedRealPart(fn foldFn, i *Integer, r *Rational, f *Flt, c *Complex) expreduceapi.Ex { + if c != nil { + toReturn := c + if f != nil { + if fn == FoldFnAdd { + toReturn.addF(f) + } else if fn == FoldFnMul { + toReturn.mulF(f) + } + } + if r != nil { + if fn == FoldFnAdd { + toReturn.addR(r) + } else if fn == FoldFnMul { + toReturn.mulR(r) + } + } + if i != nil { + if fn == FoldFnAdd { + toReturn.addI(i) + } else if fn == FoldFnMul { + toReturn.mulI(i) + } + } + return toReturn + } + if f != nil { + toReturn := f + if r != nil { + if fn == FoldFnAdd { + toReturn.addR(r) + } else if fn == FoldFnMul { + toReturn.mulR(r) + } + } + if i != nil { + if fn == FoldFnAdd { + toReturn.addI(i) + } else if fn == FoldFnMul { + toReturn.mulI(i) + } + } + return toReturn + } + if r != nil { + toReturn := r + if i != nil { + if fn == FoldFnAdd { + toReturn.addI(i) + } else if fn == FoldFnMul { + toReturn.mulI(i) + } + } + return toReturn + } + if i != nil { + return i + } + return nil +} + +func ComputeNumericPart(fn foldFn, e expreduceapi.ExpressionInterface) (expreduceapi.Ex, int) { + var foldedInt *Integer + var foldedRat *Rational + var foldedFlt *Flt + var foldedComp *Complex + for i := 1; i < len(e.GetParts()); i++ { + // TODO: implement short circuiting if we encounter a zero while + // multiplying. + asInt, isInt := e.GetParts()[i].(*Integer) + if isInt { + if foldedInt == nil { + // Try deepcopy if problems. I think this does not cause + // problems now because we will only modify the value if we end + // up creating an entirely new expression. + foldedInt = asInt.DeepCopy().(*Integer) + continue + } + if fn == FoldFnAdd { + foldedInt.addI(asInt) + } else if fn == FoldFnMul { + foldedInt.mulI(asInt) + } + continue + } + asRat, isRat := e.GetParts()[i].(*Rational) + if isRat { + if foldedRat == nil { + foldedRat = asRat.DeepCopy().(*Rational) + continue + } + if fn == FoldFnAdd { + foldedRat.addR(asRat) + } else if fn == FoldFnMul { + foldedRat.mulR(asRat) + } + continue + } + asFlt, isFlt := e.GetParts()[i].(*Flt) + if isFlt { + if foldedFlt == nil { + foldedFlt = asFlt.DeepCopy().(*Flt) + continue + } + if fn == FoldFnAdd { + foldedFlt.addF(asFlt) + } else if fn == FoldFnMul { + foldedFlt.mulF(asFlt) + } + continue + } + asComp, isComp := e.GetParts()[i].(*Complex) + if isComp { + if foldedComp == nil { + foldedComp = asComp.DeepCopy().(*Complex) + continue + } + if fn == FoldFnAdd { + foldedComp.addC(asComp) + } else if fn == FoldFnMul { + foldedComp.mulC(asComp) + } + continue + } + return typedRealPart(fn, foldedInt, foldedRat, foldedFlt, foldedComp), i + } + return typedRealPart(fn, foldedInt, foldedRat, foldedFlt, foldedComp), -1 +} diff --git a/expreduce/atoms/ex_complex.go b/expreduce/atoms/ex_complex.go new file mode 100644 index 0000000..a0b746c --- /dev/null +++ b/expreduce/atoms/ex_complex.go @@ -0,0 +1,136 @@ +package atoms + +import ( + "encoding/binary" + "fmt" + "hash/fnv" + + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type Complex struct { + Re expreduceapi.Ex + Im expreduceapi.Ex + needsEval bool +} + +func (cmplx *Complex) StringForm(p expreduceapi.ToStringParams) string { + if p.Form == "FullForm" { + return fmt.Sprintf("Complex[%v, %v]", cmplx.Re, cmplx.Im) + } + reInt, reIsInt := cmplx.Re.(*Integer) + imInt, imIsInt := cmplx.Im.(*Integer) + if reIsInt && reInt.Val.Sign() == 0 { + if imIsInt && imInt.Val.Int64() == 1 { + return "I" + } + p.PreviousHead = "System`Times" + return fmt.Sprintf("(%v*I)", cmplx.Im.StringForm(p)) + } + p.PreviousHead = "System`Plus" + return fmt.Sprintf("(%v + %v*I)", cmplx.Re.StringForm(p), cmplx.Im.StringForm(p)) +} + +func (cmplx *Complex) IsEqual(other expreduceapi.Ex) string { + otherConv, otherIsComplex := other.(*Complex) + if !otherIsComplex { + return "EQUAL_FALSE" + } + if (cmplx.Re.IsEqual(otherConv.Re) != "EQUAL_TRUE") || (cmplx.Im.IsEqual(otherConv.Im) != "EQUAL_TRUE") { + return "EQUAL_FALSE" + } + return "EQUAL_TRUE" +} + +func (cmplx *Complex) DeepCopy() expreduceapi.Ex { + return &Complex{cmplx.Re.DeepCopy(), cmplx.Im.DeepCopy(), cmplx.needsEval} +} + +func (cmplx *Complex) Copy() expreduceapi.Ex { + return cmplx.DeepCopy() +} + +func (cmplx *Complex) NeedsEval() bool { + return cmplx.needsEval +} + +func NewComplex(r expreduceapi.Ex, i expreduceapi.Ex) *Complex { + return &Complex{r, i, true} +} + +func (cmplx *Complex) Hash() uint64 { + h := fnv.New64a() + h.Write([]byte{82, 226, 223, 39, 113, 26, 149, 249}) + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, cmplx.Re.Hash()) + h.Write(b) + binary.LittleEndian.PutUint64(b, cmplx.Im.Hash()) + h.Write(b) + return h.Sum64() +} + +func (cmplx *Complex) addReal(e expreduceapi.Ex) { + a, _ := ComputeNumericPart(FoldFnAdd, E(S("Dummy"), cmplx.Re, e)) + cmplx.Re = a + cmplx.needsEval = true +} + +func (cmplx *Complex) addI(i *Integer) { + cmplx.addReal(i) +} + +func (cmplx *Complex) addF(f *Flt) { + cmplx.addReal(f) +} + +func (cmplx *Complex) addR(r *Rational) { + cmplx.addReal(r) +} + +func (cmplx *Complex) addC(c *Complex) { + a, _ := ComputeNumericPart(FoldFnAdd, E(S("Dummy"), cmplx.Re, c.Re)) + b, _ := ComputeNumericPart(FoldFnAdd, E(S("Dummy"), cmplx.Im, c.Im)) + cmplx.Re = a + cmplx.Im = b + cmplx.needsEval = true +} + +func (cmplx *Complex) mulReal(e expreduceapi.Ex) { + a, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), cmplx.Re, e)) + b, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), cmplx.Im, e)) + cmplx.Re = a + cmplx.Im = b + cmplx.needsEval = true +} + +func (cmplx *Complex) mulI(i *Integer) { + cmplx.mulReal(i) +} + +func (cmplx *Complex) mulF(f *Flt) { + cmplx.mulReal(f) +} + +func (cmplx *Complex) mulR(r *Rational) { + cmplx.mulReal(r) +} + +func (cmplx *Complex) mulC(c *Complex) { + // HoldPattern[Complex[x_, y_]*Complex[u_, v_]*rest___] -> Complex[x*u + (y*v)*(-1), x*v + y*u]*rest) + // cmplx is ugly. Need to refactor. + // Perhaps create "Calculator" utility?? + // TODO(corywalker) Remove the definition that cmplx implements in code. + a, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), cmplx.Re, c.Re)) + b, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), NewInt(-1), cmplx.Im, c.Im)) + cc, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), cmplx.Re, c.Im)) + d, _ := ComputeNumericPart(FoldFnMul, E(S("Dummy"), cmplx.Im, c.Re)) + e, _ := ComputeNumericPart(FoldFnAdd, E(S("Dummy"), a, b)) + f, _ := ComputeNumericPart(FoldFnAdd, E(S("Dummy"), cc, d)) + cmplx.Re = e + cmplx.Im = f + cmplx.needsEval = true +} + +func (cmplx *Complex) SetNeedsEval(newVal bool) { + cmplx.needsEval = newVal +} diff --git a/expreduce/atoms/ex_expression.go b/expreduce/atoms/ex_expression.go new file mode 100644 index 0000000..0769c08 --- /dev/null +++ b/expreduce/atoms/ex_expression.go @@ -0,0 +1,292 @@ +package atoms + +import ( + "bytes" + "encoding/binary" + "hash/fnv" + "sync/atomic" + + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type Expression struct { + Parts []expreduceapi.Ex + needsEval bool + correctlyInstantiated bool + EvaledHash uint64 + CachedHash uint64 +} + +// HeadAssertion checks if the Ex is an Expression of with a head of 'head'. +// Deprecated in favor of headExAssertion +func HeadAssertion(ex expreduceapi.Ex, head string) (*Expression, bool) { + expr, isExpr := ex.(*Expression) + if isExpr { + sym, isSym := expr.GetParts()[0].(*Symbol) + if isSym { + if sym.Name == head { + return expr, true + } + } + } + return nil, false +} + +func HeadExAssertion(ex expreduceapi.Ex, head expreduceapi.Ex, cl expreduceapi.LoggingInterface) (*Expression, bool) { + expr, isExpr := ex.(*Expression) + if isExpr { + if IsSameQ(head, expr.GetParts()[0]) { + return expr, true + } + } + return nil, false +} + +func OperatorAssertion(ex expreduceapi.Ex, opHead string) (*Expression, *Expression, bool) { + expr, isExpr := ex.(*Expression) + if isExpr { + headExpr, headIsExpr := expr.GetParts()[0].(*Expression) + if headIsExpr { + sym, isSym := headExpr.GetParts()[0].(*Symbol) + if isSym { + if sym.Name == opHead { + return expr, headExpr, true + } + } + } + } + return nil, nil, false +} + +func (thisExpr *Expression) PropagateConditionals() (*Expression, bool) { + foundCond := false + for _, e := range thisExpr.GetParts()[1:] { + if cond, isCond := HeadAssertion(e, "System`ConditionalExpression"); isCond { + if len(cond.GetParts()) == 3 { + foundCond = true + break + } + } + } + if foundCond { + resEx := E(thisExpr.GetParts()[0]) + resCond := E(S("And")) + for _, e := range thisExpr.GetParts()[1:] { + if cond, isCond := HeadAssertion(e, "System`ConditionalExpression"); isCond { + if len(cond.GetParts()) == 3 { + resEx.AppendEx(cond.GetParts()[1].DeepCopy()) + resCond.AppendEx(cond.GetParts()[2].DeepCopy()) + continue + } + } + resEx.AppendEx(e.DeepCopy()) + } + return E(S("ConditionalExpression"), resEx, resCond), true + } + return thisExpr, false +} + +func (thisExpr *Expression) StringForm(params expreduceapi.ToStringParams) string { + headAsSym, isHeadSym := thisExpr.GetParts()[0].(*Symbol) + fullForm := false + if isHeadSym && !fullForm && params.Esi != nil { + res, ok := "", false + headStr := headAsSym.Name + toStringFn, hasToStringFn := params.Esi.GetStringFn(headStr) + if hasToStringFn { + ok, res = toStringFn(thisExpr, params) + } + if ok { + return res + } + } + + if len(thisExpr.GetParts()) == 2 && isHeadSym && (headAsSym.Name == "System`InputForm" || + headAsSym.Name == "System`FullForm" || + headAsSym.Name == "System`TraditionalForm" || + headAsSym.Name == "System`TeXForm" || + headAsSym.Name == "System`StandardForm" || + headAsSym.Name == "System`OutputForm") { + mutatedParams := params + mutatedParams.Form = headAsSym.Name[7:] + return thisExpr.GetParts()[1].StringForm(mutatedParams) + } + + // Default printing format + var buffer bytes.Buffer + buffer.WriteString(thisExpr.GetParts()[0].StringForm(params)) + buffer.WriteString("[") + params.PreviousHead = "" + for i, e := range thisExpr.GetParts() { + if i == 0 { + continue + } + buffer.WriteString(e.StringForm(params)) + if i != len(thisExpr.GetParts())-1 { + buffer.WriteString(", ") + } + } + buffer.WriteString("]") + return buffer.String() +} + +func (thisExpr *Expression) String() string { + return thisExpr.StringForm(defaultStringParams()) +} + +func (thisExpr *Expression) IsEqual(otherEx expreduceapi.Ex) string { + other, ok := otherEx.(*Expression) + if !ok { + return "EQUAL_UNK" + } + + if len(thisExpr.GetParts()) != len(other.GetParts()) { + return "EQUAL_UNK" + } + for i := range thisExpr.GetParts() { + res := thisExpr.GetParts()[i].IsEqual(other.GetParts()[i]) + switch res { + case "EQUAL_FALSE": + return "EQUAL_UNK" + case "EQUAL_TRUE": + case "EQUAL_UNK": + return "EQUAL_UNK" + } + } + return "EQUAL_TRUE" +} + +func (thisExpr *Expression) DeepCopy() expreduceapi.Ex { + var thisExprcopy = NewEmptyExpression() + for i := range thisExpr.GetParts() { + thisExprcopy.AppendEx(thisExpr.GetParts()[i].DeepCopy()) + } + thisExprcopy.needsEval = thisExpr.needsEval + thisExprcopy.correctlyInstantiated = thisExpr.correctlyInstantiated + thisExprcopy.EvaledHash = thisExpr.EvaledHash + thisExprcopy.CachedHash = thisExpr.CachedHash + return thisExprcopy +} + +func ShallowCopy(thisExprExprInt expreduceapi.ExpressionInterface) *Expression { + thisExpr := thisExprExprInt.(*Expression) + var thisExprcopy = NewEmptyExpression() + thisExprcopy.Parts = append([]expreduceapi.Ex{}, thisExpr.GetParts()...) + thisExprcopy.needsEval = thisExpr.needsEval + thisExprcopy.correctlyInstantiated = thisExpr.correctlyInstantiated + thisExprcopy.EvaledHash = thisExpr.EvaledHash + thisExprcopy.CachedHash = thisExpr.CachedHash + return thisExprcopy +} + +func (thisExpr *Expression) Copy() expreduceapi.Ex { + var thisExprcopy = newEmptyExpressionOfLength(len(thisExpr.GetParts())) + for i := range thisExpr.GetParts() { + thisExprcopy.GetParts()[i] = thisExpr.GetParts()[i].Copy() + } + thisExprcopy.needsEval = thisExpr.needsEval + thisExprcopy.correctlyInstantiated = thisExpr.correctlyInstantiated + thisExprcopy.EvaledHash = thisExpr.EvaledHash + thisExprcopy.CachedHash = thisExpr.CachedHash + return thisExprcopy +} + +// Implement the sort.Interface +func (thisExpr *Expression) Len() int { + return len(thisExpr.GetParts()) - 1 +} + +func (thisExpr *Expression) Less(i, j int) bool { + return ExOrder(thisExpr.GetParts()[i+1], thisExpr.GetParts()[j+1]) == 1 +} + +func (thisExpr *Expression) Swap(i, j int) { + thisExpr.GetParts()[j+1], thisExpr.GetParts()[i+1] = thisExpr.GetParts()[i+1], thisExpr.GetParts()[j+1] +} + +func (thisExpr *Expression) AppendEx(e expreduceapi.Ex) { + thisExpr.Parts = append(thisExpr.Parts, e) +} + +func (thisExpr *Expression) AppendExArray(e []expreduceapi.Ex) { + thisExpr.Parts = append(thisExpr.Parts, e...) +} + +func (thisExpr *Expression) NeedsEval() bool { + return thisExpr.needsEval +} + +func (thisExpr *Expression) SetNeedsEval(newVal bool) { + thisExpr.needsEval = newVal +} + +func (thisExpr *Expression) Hash() uint64 { + if atomic.LoadUint64(&thisExpr.CachedHash) > 0 { + return thisExpr.CachedHash + } + h := fnv.New64a() + h.Write([]byte{72, 5, 244, 86, 5, 210, 69, 30}) + b := make([]byte, 8) + for _, part := range thisExpr.GetParts() { + binary.LittleEndian.PutUint64(b, part.Hash()) + h.Write(b) + } + atomic.StoreUint64(&thisExpr.CachedHash, h.Sum64()) + return h.Sum64() +} + +func (thisExpr *Expression) HeadStr() string { + sym, isSym := thisExpr.GetParts()[0].(*Symbol) + if isSym { + return sym.Name + } + return "" +} + +func NewExpression(parts []expreduceapi.Ex) *Expression { + return &Expression{ + Parts: parts, + needsEval: true, + correctlyInstantiated: true, + } +} + +func E(parts ...expreduceapi.Ex) *Expression { + return NewExpression(parts) +} + +func NewHead(head string) *Expression { + return NewExpression([]expreduceapi.Ex{NewSymbol(head)}) +} + +func NewEmptyExpression() *Expression { + return &Expression{ + needsEval: true, + correctlyInstantiated: true, + } +} + +func newEmptyExpressionOfLength(n int) *Expression { + return &Expression{ + Parts: make([]expreduceapi.Ex, n), + needsEval: true, + correctlyInstantiated: true, + } +} + +func (thisExpr *Expression) GetParts() []expreduceapi.Ex { + return thisExpr.Parts +} + +func (thisExpr *Expression) GetPart(i int) expreduceapi.Ex { + return thisExpr.Parts[i] +} + +func (thisExpr *Expression) SetParts(newParts []expreduceapi.Ex) { + thisExpr.Parts = newParts +} + +func (thisExpr *Expression) ClearHashes() { + thisExpr.EvaledHash = 0 + thisExpr.CachedHash = 0 +} diff --git a/expreduce/atoms/ex_integer.go b/expreduce/atoms/ex_integer.go new file mode 100644 index 0000000..dcf0323 --- /dev/null +++ b/expreduce/atoms/ex_integer.go @@ -0,0 +1,105 @@ +package atoms + +import ( + "fmt" + "hash/fnv" + "math/big" + + "github.com/corywalker/expreduce/expreduce/parser/parens" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +// Integer numbers represented by big.Int +type Integer struct { + Val *big.Int + cachedHash uint64 +} + +/*func (f *Integer) StringForm(params ToStringParams) string { + return fmt.Sprintf("%d", f.Val) +}*/ + +func (thisInt *Integer) StringForm(params expreduceapi.ToStringParams) string { + if thisInt.Val.Cmp(big.NewInt(0)) < 0 { + if parens.NeedsParens("System`Times", params.PreviousHead) { + if params.Form == "TeXForm" { + return fmt.Sprintf("{(%d)}", thisInt.Val) + } + return fmt.Sprintf("(%d)", thisInt.Val) + } + } + return fmt.Sprintf("%d", thisInt.Val) +} + +func (thisInt *Integer) String() string { + return thisInt.StringForm(defaultStringParams()) +} + +func (thisInt *Integer) IsEqual(other expreduceapi.Ex) string { + otherConv, ok := other.(*Integer) + if !ok { + otherFlt, ok := other.(*Flt) + if ok { + thisIntAsFlt := big.NewFloat(0) + thisIntAsFlt.SetInt(thisInt.Val) + if thisIntAsFlt.Cmp(otherFlt.Val) == 0 { + return "EQUAL_TRUE" + } + } + return "EQUAL_UNK" + } + if thisInt.Val.Cmp(otherConv.Val) != 0 { + return "EQUAL_FALSE" + } + return "EQUAL_TRUE" +} + +func (thisInt *Integer) DeepCopy() expreduceapi.Ex { + tmp := big.NewInt(0) + tmp.Set(thisInt.Val) + return &Integer{Val: tmp, cachedHash: thisInt.cachedHash} +} + +func (thisInt *Integer) Copy() expreduceapi.Ex { + return thisInt +} + +func (thisInt *Integer) NeedsEval() bool { + return false +} + +func NewInteger(i *big.Int) *Integer { + return &Integer{Val: i} +} + +func NewInt(i int64) *Integer { + return NewInteger(big.NewInt(i)) +} + +func (thisInt *Integer) Hash() uint64 { + if thisInt.cachedHash > 0 { + return thisInt.cachedHash + } + h := fnv.New64a() + h.Write([]byte{242, 99, 84, 113, 102, 46, 118, 94}) + bytes, _ := thisInt.Val.GobEncode() + h.Write(bytes) + thisInt.cachedHash = h.Sum64() + return h.Sum64() +} + +func (thisInt *Integer) asBigFloat() *big.Float { + newfloat := big.NewFloat(0) + newfloat.SetInt(thisInt.Val) + return newfloat +} + +func (thisInt *Integer) addI(i *Integer) { + thisInt.Val.Add(thisInt.Val, i.Val) + thisInt.cachedHash = 0 +} + +func (thisInt *Integer) mulI(i *Integer) { + thisInt.Val.Mul(thisInt.Val, i.Val) + thisInt.cachedHash = 0 +} diff --git a/expreduce/atoms/ex_rational.go b/expreduce/atoms/ex_rational.go new file mode 100644 index 0000000..c527015 --- /dev/null +++ b/expreduce/atoms/ex_rational.go @@ -0,0 +1,118 @@ +package atoms + +import ( + "fmt" + "hash/fnv" + "math/big" + + "github.com/corywalker/expreduce/expreduce/parser/parens" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type Rational struct { + Num *big.Int + Den *big.Int + needsEval bool +} + +func (thisRational *Rational) StringForm(params expreduceapi.ToStringParams) string { + if params.Form == "FullForm" { + return fmt.Sprintf("Rational[%d, %d]", thisRational.Num, thisRational.Den) + } + if params.Form == "TeXForm" { + return fmt.Sprintf("\\frac{%d}{%d}", thisRational.Num, thisRational.Den) + } + if parens.NeedsParens("System`Times", params.PreviousHead) { + return fmt.Sprintf("(%d/%d)", thisRational.Num, thisRational.Den) + } + return fmt.Sprintf("%d/%d", thisRational.Num, thisRational.Den) +} + +func (thisRational *Rational) IsEqual(other expreduceapi.Ex) string { + otherConv, otherIsRational := other.(*Rational) + if !otherIsRational { + return "EQUAL_FALSE" + } + // Assume rational already simplified + if (thisRational.Num.Cmp(otherConv.Num) != 0) || (thisRational.Den.Cmp(otherConv.Den) != 0) { + return "EQUAL_FALSE" + } + return "EQUAL_TRUE" +} + +func (thisRational *Rational) DeepCopy() expreduceapi.Ex { + tmpn := big.NewInt(0) + tmpn.Set(thisRational.Num) + tmpd := big.NewInt(0) + tmpd.Set(thisRational.Den) + return &Rational{tmpn, tmpd, thisRational.needsEval} +} + +func (thisRational *Rational) Copy() expreduceapi.Ex { + return thisRational.DeepCopy() +} + +func (thisRational *Rational) asBigRat() *big.Rat { + res := big.NewRat(1, 1) + return res.SetFrac(thisRational.Num, thisRational.Den) +} + +func (thisRational *Rational) NeedsEval() bool { + return thisRational.needsEval +} + +func (thisRational *Rational) SetNeedsEval(newVal bool) { + thisRational.needsEval = newVal +} + +func NewRational(n *big.Int, d *big.Int) *Rational { + return &Rational{n, d, true} +} + +func (thisRational *Rational) Hash() uint64 { + h := fnv.New64a() + h.Write([]byte{90, 82, 214, 51, 52, 7, 7, 33}) + nBytes, _ := thisRational.Num.GobEncode() + h.Write(nBytes) + dBytes, _ := thisRational.Den.GobEncode() + h.Write(dBytes) + return h.Sum64() +} + +func (thisRational *Rational) asBigFloat() *big.Float { + num := big.NewFloat(0) + den := big.NewFloat(0) + newquo := big.NewFloat(0) + num.SetInt(thisRational.Num) + den.SetInt(thisRational.Den) + newquo.Quo(num, den) + return newquo +} + +func (thisRational *Rational) addI(i *Integer) { + tmp := big.NewInt(0) + tmp.Mul(i.Val, thisRational.Den) + thisRational.Num.Add(thisRational.Num, tmp) +} + +func (thisRational *Rational) addR(otherR *Rational) { + tmp := big.NewInt(0) + // lastrNum/lastrDen + theratNum/theratDen // Together + tmp.Mul(thisRational.Den, otherR.Num) + thisRational.Den.Mul(thisRational.Den, otherR.Den) + thisRational.Num.Mul(thisRational.Num, otherR.Den) + thisRational.Num.Add(thisRational.Num, tmp) +} + +func (thisRational *Rational) mulI(i *Integer) { + thisRational.Num.Mul(thisRational.Num, i.Val) +} + +func (thisRational *Rational) MulBigI(i *big.Int) { + thisRational.Num.Mul(thisRational.Num, i) +} + +func (thisRational *Rational) mulR(otherR *Rational) { + thisRational.Num.Mul(thisRational.Num, otherR.Num) + thisRational.Den.Mul(thisRational.Den, otherR.Den) +} diff --git a/expreduce/atoms/ex_real.go b/expreduce/atoms/ex_real.go new file mode 100644 index 0000000..d3f211f --- /dev/null +++ b/expreduce/atoms/ex_real.go @@ -0,0 +1,126 @@ +package atoms + +import ( + "bytes" + "fmt" + "hash/fnv" + "math/big" + "strings" + + "github.com/corywalker/expreduce/expreduce/parser/parens" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +// Flt represents a floating point number in Expreduce. The values are +// represented by big.Float internally. +type Flt struct { + Val *big.Float +} + +func (flt *Flt) StringForm(params expreduceapi.ToStringParams) string { + var buffer bytes.Buffer + useParens := false + if flt.Val.Cmp(big.NewFloat(0)) < 0 { + if parens.NeedsParens("System`Times", params.PreviousHead) { + useParens = true + if params.Form == "TeXForm" { + buffer.WriteString("{") + } + buffer.WriteString("(") + } + } + buffer.WriteString(fmt.Sprintf("%.6g", flt.Val)) + if bytes.IndexRune(buffer.Bytes(), '.') == -1 { + buffer.WriteString(".") + } + if useParens { + buffer.WriteString(")") + if params.Form == "TeXForm" { + buffer.WriteString("}") + } + } + return buffer.String() +} + +func (flt *Flt) IsEqual(other expreduceapi.Ex) string { + otherConv, ok := other.(*Flt) + if !ok { + otherInteger, ok := other.(*Integer) + if ok { + otherAsFlt := big.NewFloat(0) + otherAsFlt.SetInt(otherInteger.Val) + if otherAsFlt.Cmp(flt.Val) == 0 { + return "EQUAL_TRUE" + } + } + return "EQUAL_UNK" + } + fltStr := fmt.Sprintf("%.14g", flt.Val) + otherStr := fmt.Sprintf("%.14g", otherConv.Val) + if strings.Compare(fltStr, otherStr) != 0 { + return "EQUAL_FALSE" + } + return "EQUAL_TRUE" +} + +func (flt *Flt) DeepCopy() expreduceapi.Ex { + tmp := big.NewFloat(0) + tmp.Copy(flt.Val) + return NewReal(tmp) +} + +func (flt *Flt) Copy() expreduceapi.Ex { + return flt.DeepCopy() +} + +func IntegerToFlt(i *Integer) (*Flt, bool) { + newfloat := big.NewFloat(0) + newfloat.SetInt(i.Val) + return NewReal(newfloat), true +} + +func RationalToFlt(r *Rational) (*Flt, bool) { + newfloat := big.NewFloat(0) + newfloat.SetRat(r.asBigRat()) + return NewReal(newfloat), true +} + +func (flt *Flt) NeedsEval() bool { + return false +} + +func (flt *Flt) Hash() uint64 { + h := fnv.New64a() + h.Write([]byte{195, 244, 76, 249, 227, 115, 88, 251}) + bytes, _ := flt.Val.GobEncode() + h.Write(bytes) + return h.Sum64() +} + +func (flt *Flt) addI(i *Integer) { + flt.Val.Add(flt.Val, i.asBigFloat()) +} + +func (flt *Flt) addR(r *Rational) { + flt.Val.Add(flt.Val, r.asBigFloat()) +} + +func (flt *Flt) addF(f *Flt) { + flt.Val.Add(flt.Val, f.Val) +} + +func (flt *Flt) mulI(i *Integer) { + flt.Val.Mul(flt.Val, i.asBigFloat()) +} + +func (flt *Flt) mulR(r *Rational) { + flt.Val.Mul(flt.Val, r.asBigFloat()) +} + +func (flt *Flt) mulF(f *Flt) { + flt.Val.Mul(flt.Val, f.Val) +} + +func NewReal(v *big.Float) *Flt { + return &Flt{v} +} diff --git a/expreduce/atoms/ex_string.go b/expreduce/atoms/ex_string.go new file mode 100644 index 0000000..faf50c3 --- /dev/null +++ b/expreduce/atoms/ex_string.go @@ -0,0 +1,64 @@ +package atoms + +import ( + "fmt" + "hash/fnv" + + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type String struct { + Val string +} + +func (str *String) StringForm(params expreduceapi.ToStringParams) string { + if params.Form == "OutputForm" || + params.Form == "TraditionalForm" || + params.Form == "StandardForm" { + return fmt.Sprintf("%v", str.Val) + } + return fmt.Sprintf("\"%v\"", str.Val) +} + +func (this *String) String() string { + return this.StringForm(defaultStringParams()) +} + +func (str *String) IsEqual(other expreduceapi.Ex) string { + otherConv, ok := other.(*String) + if !ok { + return "EQUAL_FALSE" + } + if str.Val != otherConv.Val { + return "EQUAL_FALSE" + } + return "EQUAL_TRUE" +} + +func (str *String) DeepCopy() expreduceapi.Ex { + strcopy := *str + return &strcopy +} + +func (str *String) Copy() expreduceapi.Ex { + return str.DeepCopy() +} + +func (str *String) NeedsEval() bool { + return false +} + +func (str *String) GetValue() string { + return str.Val +} + +func (str *String) Hash() uint64 { + h := fnv.New64a() + h.Write([]byte{102, 206, 57, 172, 207, 100, 198, 133}) + h.Write([]byte(str.Val)) + return h.Sum64() +} + +func NewString(v string) *String { + return &String{v} +} diff --git a/expreduce/atoms/ex_symbol.go b/expreduce/atoms/ex_symbol.go new file mode 100644 index 0000000..ec387dc --- /dev/null +++ b/expreduce/atoms/ex_symbol.go @@ -0,0 +1,272 @@ +package atoms + +import ( + "fmt" + "hash/fnv" + "sort" + "strings" + + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +// Symbol represents a symbol in Expreduce. Symbols are defined by a +// string-based name. +type Symbol struct { + Name string + cachedHash uint64 +} + +func formatSymName(name string, params expreduceapi.ToStringParams) string { + if params.Form == "TeXForm" { + if name == "E" { + return "e" + } + if name == "Pi" { + return "\\pi" + } + if name == "Infinity" { + return "\\infty" + } + if len(name) > 1 { + return fmt.Sprintf("\\text{%v}", name) + } + } + return fmt.Sprintf("%v", name) +} + +func (sym *Symbol) StringForm(params expreduceapi.ToStringParams) string { + if len(sym.Name) == 0 { + return "" + } + if strings.HasPrefix(sym.Name, params.Context.GetValue()) { + return formatSymName(sym.Name[len(params.Context.GetValue()):], params) + } + for _, pathPart := range params.ContextPath.GetParts()[1:] { + path := pathPart.(*String).Val + if strings.HasPrefix(sym.Name, path) { + return formatSymName(sym.Name[len(path):], params) + } + } + return formatSymName(sym.Name, params) +} + +func (sym *Symbol) String() string { + return sym.StringForm(defaultStringParams()) +} + +func (sym *Symbol) IsEqual(other expreduceapi.Ex) string { + otherConv, ok := other.(*Symbol) + if !ok { + return "EQUAL_UNK" + } + if sym.Name == "System`False" && otherConv.Name == "System`True" { + return "EQUAL_FALSE" + } + if sym.Name == "System`True" && otherConv.Name == "System`False" { + return "EQUAL_FALSE" + } + if sym.Name != otherConv.Name { + return "EQUAL_UNK" + } + return "EQUAL_TRUE" +} + +func (sym *Symbol) DeepCopy() expreduceapi.Ex { + symcopy := *sym + return &symcopy +} + +func (sym *Symbol) Copy() expreduceapi.Ex { + return sym +} + +func (sym *Symbol) Attrs(dm expreduceapi.DefinitionMap) expreduceapi.Attributes { + def, isDef := dm.Get(sym.Name) + if !isDef { + return expreduceapi.Attributes{} + } + return def.Attributes +} + +func (sym *Symbol) Default(dm expreduceapi.DefinitionMap) expreduceapi.Ex { + def, isDef := dm.Get(sym.Name) + if !isDef { + return nil + } + return def.DefaultExpr +} + +func StringsToAttributes(strings []string) expreduceapi.Attributes { + attrs := expreduceapi.Attributes{} + for _, s := range strings { + if s == "Orderless" { + attrs.Orderless = true + } + if s == "Flat" { + attrs.Flat = true + } + if s == "OneIdentity" { + attrs.OneIdentity = true + } + if s == "Listable" { + attrs.Listable = true + } + if s == "Constant" { + attrs.Constant = true + } + if s == "NumericFunction" { + attrs.NumericFunction = true + } + if s == "Protected" { + attrs.Protected = true + } + if s == "Locked" { + attrs.Locked = true + } + if s == "ReadProtected" { + attrs.ReadProtected = true + } + if s == "HoldFirst" { + attrs.HoldFirst = true + } + if s == "HoldRest" { + attrs.HoldRest = true + } + if s == "HoldAll" { + attrs.HoldAll = true + } + if s == "HoldAllComplete" { + attrs.HoldAllComplete = true + } + if s == "NHoldFirst" { + attrs.NHoldFirst = true + } + if s == "NHoldRest" { + attrs.NHoldRest = true + } + if s == "NHoldAll" { + attrs.NHoldAll = true + } + if s == "SequenceHold" { + attrs.SequenceHold = true + } + if s == "Temporary" { + attrs.Temporary = true + } + if s == "Stub" { + attrs.Stub = true + } + } + return attrs +} + +func AttrsToStrings(sym *expreduceapi.Attributes) []string { + var strings []string + if sym.Orderless { + strings = append(strings, "Orderless") + } + if sym.Flat { + strings = append(strings, "Flat") + } + if sym.OneIdentity { + strings = append(strings, "OneIdentity") + } + if sym.Listable { + strings = append(strings, "Listable") + } + if sym.Constant { + strings = append(strings, "Constant") + } + if sym.NumericFunction { + strings = append(strings, "NumericFunction") + } + if sym.Protected { + strings = append(strings, "Protected") + } + if sym.Locked { + strings = append(strings, "Locked") + } + if sym.ReadProtected { + strings = append(strings, "ReadProtected") + } + if sym.HoldFirst { + strings = append(strings, "HoldFirst") + } + if sym.HoldRest { + strings = append(strings, "HoldRest") + } + if sym.HoldAll { + strings = append(strings, "HoldAll") + } + if sym.HoldAllComplete { + strings = append(strings, "HoldAllComplete") + } + if sym.NHoldFirst { + strings = append(strings, "NHoldFirst") + } + if sym.NHoldRest { + strings = append(strings, "NHoldRest") + } + if sym.NHoldAll { + strings = append(strings, "NHoldAll") + } + if sym.SequenceHold { + strings = append(strings, "SequenceHold") + } + if sym.Temporary { + strings = append(strings, "Temporary") + } + if sym.Stub { + strings = append(strings, "Stub") + } + + sort.Strings(strings) + return strings +} + +func AttrsToSymList(sym *expreduceapi.Attributes) expreduceapi.ExpressionInterface { + toReturn := E(S("List")) + for _, s := range AttrsToStrings(sym) { + toReturn.AppendEx(S(s)) + } + return toReturn +} + +func (sym *Symbol) NeedsEval() bool { + return false +} + +func (sym *Symbol) Hash() uint64 { + if sym.cachedHash > 0 { + return sym.cachedHash + } + h := fnv.New64a() + h.Write([]byte{107, 10, 247, 23, 33, 221, 163, 156}) + h.Write([]byte(sym.Name)) + sym.cachedHash = h.Sum64() + return h.Sum64() +} + +func ContainsSymbol(e expreduceapi.Ex, name string) bool { + asSym, isSym := e.(*Symbol) + if isSym { + return asSym.Name == name + } + asExpr, isExpr := e.(expreduceapi.ExpressionInterface) + if isExpr { + for _, part := range asExpr.GetParts() { + if ContainsSymbol(part, name) { + return true + } + } + } + return false +} + +func NewSymbol(name string) *Symbol { + return &Symbol{Name: name} +} + +func S(name string) expreduceapi.Ex { + return NewSymbol("System`" + name) +} diff --git a/expreduce/order.go b/expreduce/atoms/order.go similarity index 69% rename from expreduce/order.go rename to expreduce/atoms/order.go index 5052112..36a3661 100644 --- a/expreduce/order.go +++ b/expreduce/atoms/order.go @@ -1,7 +1,16 @@ -package expreduce +package atoms + +import "github.com/corywalker/expreduce/pkg/expreduceapi" + +func min(x, y int) int { + if x < y { + return x + } + return y +} func compareStrings(a string, b string) int64 { - minchars := Min(len(a), len(b)) + minchars := min(len(a), len(b)) for i := 0; i < minchars; i++ { if a[i] > b[i] { return -1 @@ -17,15 +26,15 @@ func compareStrings(a string, b string) int64 { return 0 } -func ExOrder(a Ex, b Ex) int64 { +func ExOrder(a expreduceapi.Ex, b expreduceapi.Ex) int64 { // Support Flt, Integer, Rational, Expression, Symbol aAsSymbol, aIsSymbol := a.(*Symbol) bAsSymbol, bIsSymbol := b.(*Symbol) aAsString, aIsString := a.(*String) bAsString, bIsString := b.(*String) - aAsExp, aIsExp := a.(*Expression) - bAsExp, bIsExp := b.(*Expression) + aAsExp, aIsExp := a.(expreduceapi.ExpressionInterface) + bAsExp, bIsExp := b.(expreduceapi.ExpressionInterface) aAsFlt, aIsFlt := a.(*Flt) bAsFlt, bIsFlt := b.(*Flt) @@ -71,28 +80,28 @@ func ExOrder(a Ex, b Ex) int64 { _, aIsTimes := HeadAssertion(aAsExp, "System`Times") _, bIsTimes := HeadAssertion(bAsExp, "System`Times") if !aIsTimes && bIsTimes { - return ExOrder(NewExpression([]Ex{ + return ExOrder(NewExpression([]expreduceapi.Ex{ NewSymbol("System`Times"), NewInt(1), aAsExp, }), b) } if aIsPow && !bIsPow { - return ExOrder(a, NewExpression([]Ex{ + return ExOrder(a, NewExpression([]expreduceapi.Ex{ NewSymbol("System`Power"), bAsExp, NewInt(1), })) } if !bIsTimes && aIsTimes { - return ExOrder(aAsExp, NewExpression([]Ex{ + return ExOrder(aAsExp, NewExpression([]expreduceapi.Ex{ NewSymbol("System`Times"), NewInt(1), bAsExp, })) } if !aIsPow && bIsPow { - return ExOrder(NewExpression([]Ex{ + return ExOrder(NewExpression([]expreduceapi.Ex{ NewSymbol("System`Power"), aAsExp, NewInt(1), @@ -100,49 +109,48 @@ func ExOrder(a Ex, b Ex) int64 { } timesMode := aIsTimes && bIsTimes if !timesMode { - if len(aAsExp.Parts) < len(bAsExp.Parts) { + if len(aAsExp.GetParts()) < len(bAsExp.GetParts()) { return 1 - } else if len(aAsExp.Parts) > len(bAsExp.Parts) { + } else if len(aAsExp.GetParts()) > len(bAsExp.GetParts()) { return -1 } - for i := 0; i < len(aAsExp.Parts); i++ { - aPart, bPart := aAsExp.Parts[i], bAsExp.Parts[i] + for i := 0; i < len(aAsExp.GetParts()); i++ { + aPart, bPart := aAsExp.GetParts()[i], bAsExp.GetParts()[i] o := ExOrder(aPart, bPart) if o != 0 { return o } } return 0 - } else { - ai := len(aAsExp.Parts) - 1 - bi := len(bAsExp.Parts) - 1 - for ai >= 0 && bi >= 0 { - aPart, bPart := aAsExp.Parts[ai], bAsExp.Parts[bi] - ai, bi = ai-1, bi-1 - if numberQ(aPart) && numberQ(bPart) { - continue - } + } + ai := len(aAsExp.GetParts()) - 1 + bi := len(bAsExp.GetParts()) - 1 + for ai >= 0 && bi >= 0 { + aPart, bPart := aAsExp.GetParts()[ai], bAsExp.GetParts()[bi] + ai, bi = ai-1, bi-1 + if NumberQ(aPart) && NumberQ(bPart) { + continue + } + o := ExOrder(aPart, bPart) + if o != 0 { + return o + } + } + for i := 0; i < min(len(aAsExp.GetParts()), len(bAsExp.GetParts())); i++ { + aPart, bPart := aAsExp.GetParts()[i], bAsExp.GetParts()[i] + if NumberQ(aPart) && NumberQ(bPart) { o := ExOrder(aPart, bPart) if o != 0 { return o } } - for i := 0; i < Min(len(aAsExp.Parts), len(bAsExp.Parts)); i++ { - aPart, bPart := aAsExp.Parts[i], bAsExp.Parts[i] - if numberQ(aPart) && numberQ(bPart) { - o := ExOrder(aPart, bPart) - if o != 0 { - return o - } - } - } - if len(aAsExp.Parts) < len(bAsExp.Parts) { - return 1 - } else if len(aAsExp.Parts) > len(bAsExp.Parts) { - return -1 - } else { - return 0 - } + } + if len(aAsExp.GetParts()) < len(bAsExp.GetParts()) { + return 1 + } else if len(aAsExp.GetParts()) > len(bAsExp.GetParts()) { + return -1 + } else { + return 0 } } @@ -185,7 +193,7 @@ func ExOrder(a Ex, b Ex) int64 { if aIsSymbol && bIsExp { _, bIsPow := HeadAssertion(bAsExp, "System`Power") if bIsPow { - return ExOrder(NewExpression([]Ex{ + return ExOrder(NewExpression([]expreduceapi.Ex{ NewSymbol("System`Power"), a, NewInt(1), @@ -193,7 +201,7 @@ func ExOrder(a Ex, b Ex) int64 { } _, bIsTimes := HeadAssertion(bAsExp, "System`Times") if bIsTimes { - return ExOrder(NewExpression([]Ex{ + return ExOrder(NewExpression([]expreduceapi.Ex{ NewSymbol("System`Times"), NewInt(1), a, @@ -211,7 +219,7 @@ func ExOrder(a Ex, b Ex) int64 { if aIsExp && bIsSymbol { _, aIsPow := HeadAssertion(aAsExp, "System`Power") if aIsPow { - return ExOrder(a, NewExpression([]Ex{ + return ExOrder(a, NewExpression([]expreduceapi.Ex{ NewSymbol("System`Power"), b, NewInt(1), @@ -219,7 +227,7 @@ func ExOrder(a Ex, b Ex) int64 { } _, aIsTimes := HeadAssertion(aAsExp, "System`Times") if aIsTimes { - return ExOrder(a, NewExpression([]Ex{ + return ExOrder(a, NewExpression([]expreduceapi.Ex{ NewSymbol("System`Times"), NewInt(1), b, diff --git a/expreduce/atoms/qfunctions.go b/expreduce/atoms/qfunctions.go new file mode 100644 index 0000000..96fa06a --- /dev/null +++ b/expreduce/atoms/qfunctions.go @@ -0,0 +1,23 @@ +package atoms + +import "github.com/corywalker/expreduce/pkg/expreduceapi" + +func NumberQ(e expreduceapi.Ex) bool { + _, ok := e.(*Integer) + if ok { + return true + } + _, ok = e.(*Flt) + if ok { + return true + } + _, ok = e.(*Rational) + if ok { + return true + } + _, ok = e.(*Complex) + if ok { + return true + } + return false +} diff --git a/expreduce/atoms/sameq.go b/expreduce/atoms/sameq.go new file mode 100644 index 0000000..888b0cc --- /dev/null +++ b/expreduce/atoms/sameq.go @@ -0,0 +1,32 @@ +package atoms + +import ( + "math" + + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +// IsSameQ returns if two expressions are the same. It is mostly just a +// comparison of the hash values but it does include special handling for +// floats. +func IsSameQ(a expreduceapi.Ex, b expreduceapi.Ex) bool { + aFlt, aIsFlt := a.(*Flt) + bFlt, bIsFlt := b.(*Flt) + + if aIsFlt && bIsFlt { + // This is important, without it e.g. NestWhileList[(# + 3/#)/2 &, 1.0, UnsameQ, 2] never converges + // https://stackoverflow.com/questions/46136886/comparing-floats-by-ignoring-last-bit-in-golang + aVal, _ := aFlt.Val.Float64() + bVal, _ := bFlt.Val.Float64() + + if !(math.IsInf(aVal, 0) || math.IsInf(bVal, 0)) { + return almostEqual(aVal, bVal) + } + } + return a.Hash() == b.Hash() +} + +func almostEqual(a, b float64) bool { + ai, bi := int64(math.Float64bits(a)), int64(math.Float64bits(b)) + return a == b || -1 <= ai-bi && ai-bi <= 1 +} diff --git a/expreduce/atoms/string_utils.go b/expreduce/atoms/string_utils.go new file mode 100644 index 0000000..317cc6b --- /dev/null +++ b/expreduce/atoms/string_utils.go @@ -0,0 +1,27 @@ +package atoms + +import "github.com/corywalker/expreduce/pkg/expreduceapi" + +type fakeEvalState struct{} + +func (fes fakeEvalState) GetStringFn(headStr string) (expreduceapi.ToStringFnType, bool) { + return nil, false +} + +func (fes fakeEvalState) GetDefined(name string) (expreduceapi.Def, bool) { + return expreduceapi.Def{}, false +} + +func defaultStringParams() expreduceapi.ToStringParams { + context := NewString("Global`") + contextPath := NewExpression([]expreduceapi.Ex{ + NewSymbol("System`List"), + NewString("System`"), + }) + return expreduceapi.ToStringParams{ + Form: "InputForm", + Context: context, + ContextPath: contextPath, + Esi: fakeEvalState{}, + } +} diff --git a/expreduce/blank.go b/expreduce/blank.go deleted file mode 100644 index 6cfb3c1..0000000 --- a/expreduce/blank.go +++ /dev/null @@ -1,102 +0,0 @@ -package expreduce - -func IsBlankTypeOnly(e Ex) bool { - asPattern, patternOk := HeadAssertion(e, "System`Pattern") - if patternOk { - _, blankOk := HeadAssertion(asPattern.Parts[2], "System`Blank") - _, bsOk := HeadAssertion(asPattern.Parts[2], "System`BlankSequence") - _, bnsOk := HeadAssertion(asPattern.Parts[2], "System`BlankNullSequence") - if blankOk || bsOk || bnsOk { - return true - } - } - _, blankOk := HeadAssertion(e, "System`Blank") - _, bsOk := HeadAssertion(e, "System`BlankSequence") - _, bnsOk := HeadAssertion(e, "System`BlankNullSequence") - if blankOk || bsOk || bnsOk { - return true - } - return false -} - -func IsBlankTypeCapturing(e Ex, target Ex, head Ex, pm *PDManager, cl *CASLogger) (bool, *PDManager) { - // Similar to IsBlankType, but will capture target into es.patternDefined - // if there is a valid match. - asPattern, patternOk := HeadAssertion(e, "System`Pattern") - if patternOk { - asBlank, blankOk := HeadAssertion(asPattern.Parts[2], "System`Blank") - asBS, bsOk := HeadAssertion(asPattern.Parts[2], "System`BlankSequence") - asBNS, bnsOk := HeadAssertion(asPattern.Parts[2], "System`BlankNullSequence") - if blankOk || bsOk || bnsOk { - parts := []Ex{} - if blankOk { - parts = asBlank.Parts - } else if bsOk { - parts = asBS.Parts - } else if bnsOk { - parts = asBNS.Parts - } - //if len(parts) < 2 { - //return true, pm - //} - cl.Debugf("%v %v", parts, len(parts)) - matchesHead := false - if len(parts) < 2 { - matchesHead = true - } else { - matchesHead = IsSameQ(head, parts[1], cl) - } - cl.Debugf("%v", matchesHead) - if matchesHead { - sAsSymbol, sAsSymbolOk := asPattern.Parts[1].(*Symbol) - if sAsSymbolOk { - // TODO: we should handle matches with BlankSequences - // differently here. - toMatch, ispd := pm.patternDefined[sAsSymbol.Name] - if !ispd { - toMatch = target - pm.LazyMakeMap() - pm.patternDefined[sAsSymbol.Name] = target - } - if !IsSameQ(toMatch, target, cl) { - return false, pm - } - } - return true, pm - } - return false, pm - } - } - asBlank, blankOk := HeadAssertion(e, "System`Blank") - asBS, bsOk := HeadAssertion(e, "System`BlankSequence") - asBNS, bnsOk := HeadAssertion(e, "System`BlankNullSequence") - if blankOk || bsOk || bnsOk { - parts := []Ex{} - if blankOk { - parts = asBlank.Parts - } else if bsOk { - parts = asBS.Parts - } else if bnsOk { - parts = asBNS.Parts - } - if len(parts) < 2 { - return true, pm - } - return IsSameQ(head, parts[1], cl), pm - } - return false, pm -} - -func BlankNullSequenceToBlank(bns *Expression) *Expression { - if len(bns.Parts) < 2 { - return NewExpression([]Ex{NewSymbol("System`Blank")}) - } - return NewExpression([]Ex{NewSymbol("System`Blank"), bns.Parts[1]}) -} - -func BlankSequenceToBlank(bs *Expression) *Expression { - if len(bs.Parts) < 2 { - return NewExpression([]Ex{NewSymbol("System`Blank")}) - } - return NewExpression([]Ex{NewSymbol("System`Blank"), bs.Parts[1]}) -} diff --git a/expreduce/builtin.go b/expreduce/builtin.go index 3e67e04..9d91741 100644 --- a/expreduce/builtin.go +++ b/expreduce/builtin.go @@ -1,13 +1,16 @@ +//go:generate go-bindata -pkg expreduce -o resources.go resources/... + package expreduce -import "log" -import "fmt" +import ( + "fmt" + "log" -type Rule struct { - Lhs string - Rhs string -} + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) +// The Definition struct provides metadata about a builtin function. type Definition struct { // The symbol name, like "Mean", and "Total" Name string @@ -16,59 +19,59 @@ type Definition struct { // SetDelayed, we define it first. Bootstrap bool OmitDocumentation bool - ExpreduceSpecific bool + expreduceSpecific bool Details string // Map symbol to Eval() function - legacyEvalFn (func(*Expression, *EvalState) Ex) + legacyEvalFn (func(expreduceapi.ExpressionInterface, expreduceapi.EvalStateInterface) expreduceapi.Ex) SimpleExamples []TestInstruction FurtherExamples []TestInstruction Tests []TestInstruction KnownFailures []TestInstruction KnownDangerous []TestInstruction - toString ToStringFnType + toString expreduceapi.ToStringFnType Attributes []string Default string } -func ToTestInstructions(tc *Expression) []TestInstruction { +func toTestInstructions(tc expreduceapi.ExpressionInterface) []TestInstruction { instructions := []TestInstruction{} - for _, tiEx := range tc.Parts[1:] { - if st, isSt := HeadAssertion(tiEx, "System`ESameTest"); isSt { - if len(st.Parts) != 3 { + for _, tiEx := range tc.GetParts()[1:] { + if st, isSt := atoms.HeadAssertion(tiEx, "System`ESameTest"); isSt { + if len(st.GetParts()) != 3 { log.Fatalf("Invalid test case: %v\n", tiEx) continue } instructions = append(instructions, &SameTestEx{ - st.Parts[1], st.Parts[2]}) + st.GetParts()[1], st.GetParts()[2]}) continue } - if st, isSt := HeadAssertion(tiEx, "System`EStringTest"); isSt { - if len(st.Parts) != 3 { + if st, isSt := atoms.HeadAssertion(tiEx, "System`EStringTest"); isSt { + if len(st.GetParts()) != 3 { log.Fatalf("Invalid test case: %v\n", tiEx) continue } instructions = append(instructions, &StringTest{ - st.Parts[1].(*String).Val, st.Parts[2].(*String).Val}) + st.GetParts()[1].(*atoms.String).Val, st.GetParts()[2].(*atoms.String).Val}) continue } - if st, isSt := HeadAssertion(tiEx, "System`EExampleOnlyInstruction"); isSt { - if len(st.Parts) != 3 { + if st, isSt := atoms.HeadAssertion(tiEx, "System`EExampleOnlyInstruction"); isSt { + if len(st.GetParts()) != 3 { log.Fatalf("Invalid test case: %v\n", tiEx) continue } instructions = append(instructions, &ExampleOnlyInstruction{ - st.Parts[1].(*String).Val, st.Parts[2].(*String).Val}) + st.GetParts()[1].(*atoms.String).Val, st.GetParts()[2].(*atoms.String).Val}) continue } - if st, isSt := HeadAssertion(tiEx, "System`EComment"); isSt { - if len(st.Parts) != 2 { + if st, isSt := atoms.HeadAssertion(tiEx, "System`EComment"); isSt { + if len(st.GetParts()) != 2 { log.Fatalf("Invalid test case: %v\n", tiEx) continue } - comStr, comIsStr := st.Parts[1].(*String) + comStr, comIsStr := st.GetParts()[1].(*atoms.String) if !comIsStr { log.Fatalf("Invalid test case: %v\n", tiEx) continue @@ -77,15 +80,15 @@ func ToTestInstructions(tc *Expression) []TestInstruction { comStr.Val}) continue } - if st, isSt := HeadAssertion(tiEx, "System`EResetState"); isSt { - if len(st.Parts) != 1 { + if st, isSt := atoms.HeadAssertion(tiEx, "System`EResetState"); isSt { + if len(st.GetParts()) != 1 { log.Fatalf("Invalid test case: %v\n", tiEx) continue } instructions = append(instructions, &ResetState{}) continue } - if _, isSt := HeadAssertion(tiEx, "System`List"); isSt { + if _, isSt := atoms.HeadAssertion(tiEx, "System`List"); isSt { fmt.Printf("Ignoring unfilled test: %v\n", tiEx) continue } @@ -94,108 +97,116 @@ func ToTestInstructions(tc *Expression) []TestInstruction { return instructions } -func (def *Definition) AnnotateWithDynamicTests(es *EvalState) { +func (def *Definition) annotateWithDynamicTests(es expreduceapi.EvalStateInterface) { tests, testsDef := es.GetSymDef("Tests`" + def.Name) if !testsDef { return } - testsList, testsIsList := HeadAssertion(tests, "System`List") + testsList, testsIsList := atoms.HeadAssertion(tests, "System`List") if !testsIsList { return } - for _, testCol := range testsList.Parts[1:] { - testColExpr, testColIsExpr := testCol.(*Expression) + for _, testCol := range testsList.GetParts()[1:] { + testColExpr, testColIsExpr := testCol.(expreduceapi.ExpressionInterface) if !testColIsExpr { continue } - headSym, headIsSym := testColExpr.Parts[0].(*Symbol) + headSym, headIsSym := testColExpr.GetParts()[0].(*atoms.Symbol) if !headIsSym { continue } if headSym.Name == "System`ESimpleExamples" { def.SimpleExamples = append( def.SimpleExamples, - ToTestInstructions(testColExpr)...) + toTestInstructions(testColExpr)...) } else if headSym.Name == "System`EFurtherExamples" { def.FurtherExamples = append( def.FurtherExamples, - ToTestInstructions(testColExpr)...) + toTestInstructions(testColExpr)...) } else if headSym.Name == "System`ETests" { def.Tests = append( def.Tests, - ToTestInstructions(testColExpr)...) + toTestInstructions(testColExpr)...) } else if headSym.Name == "System`EKnownFailures" { def.KnownFailures = append( def.KnownFailures, - ToTestInstructions(testColExpr)...) + toTestInstructions(testColExpr)...) } else if headSym.Name == "System`EKnownDangerous" { def.KnownDangerous = append( def.KnownDangerous, - ToTestInstructions(testColExpr)...) + toTestInstructions(testColExpr)...) } else { log.Fatalf("Invalid test collection: %v\n", testColExpr) } } } -func (def *Definition) AnnotateWithDynamicUsage(es *EvalState) { +func (def *Definition) annotateWithDynamicUsage(es expreduceapi.EvalStateInterface) { if len(def.Usage) > 0 { return } - lhs := NewExpression([]Ex{ - NewSymbol("System`MessageName"), - NewSymbol("System`" + def.Name), - NewString("usage"), + lhs := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`MessageName"), + atoms.NewSymbol("System`" + def.Name), + atoms.NewString("usage"), }) + usage, usageIsDef, _ := es.GetDef("System`MessageName", lhs) if !usageIsDef { return } - if usageStr, usageIsStr := usage.(*String); usageIsStr { + if usageStr, usageIsStr := usage.(*atoms.String); usageIsStr { def.Usage = usageStr.Val } } -func (def *Definition) AnnotateWithDynamic(es *EvalState) { - def.AnnotateWithDynamicTests(es) - def.AnnotateWithDynamicUsage(es) +// AnnotateWithDynamic annotates a Definition with anything else that might have +// been defined dynamically, perhaps through the initialization of the builtin +// function through builtin Expreduce code. Helpful in generating documentation. +func (def *Definition) AnnotateWithDynamic(es expreduceapi.EvalStateInterface) { + def.annotateWithDynamicTests(es) + def.annotateWithDynamicUsage(es) } +// NamedDefSet provides a means of grouping Definitions under a category name. +// This is useful for generating documentation. type NamedDefSet struct { Name string Defs []Definition } +// GetAllDefinitions returns a list of all builtin functions with metadata. The +// function returns a list organized by category. func GetAllDefinitions() (defs []NamedDefSet) { defs = append(defs, NamedDefSet{"combinatorics", getCombinatoricsDefinitions()}) defs = append(defs, NamedDefSet{"calculus", getCalculusDefinitions()}) defs = append(defs, NamedDefSet{"comparison", getComparisonDefinitions()}) defs = append(defs, NamedDefSet{"atoms", getAtomsDefinitions()}) defs = append(defs, NamedDefSet{"functional", getFunctionalDefinitions()}) - defs = append(defs, NamedDefSet{"expression", GetExpressionDefinitions()}) - defs = append(defs, NamedDefSet{"equationdata", GetEquationDataDefinitions()}) - defs = append(defs, NamedDefSet{"solve", GetSolveDefinitions()}) - defs = append(defs, NamedDefSet{"flowcontrol", GetFlowControlDefinitions()}) - defs = append(defs, NamedDefSet{"list", GetListDefinitions()}) - defs = append(defs, NamedDefSet{"matrix", GetMatrixDefinitions()}) + defs = append(defs, NamedDefSet{"expression", getExpressionDefinitions()}) + defs = append(defs, NamedDefSet{"equationdata", getEquationDataDefinitions()}) + defs = append(defs, NamedDefSet{"solve", getSolveDefinitions()}) + defs = append(defs, NamedDefSet{"flowcontrol", getFlowControlDefinitions()}) + defs = append(defs, NamedDefSet{"list", getListDefinitions()}) + defs = append(defs, NamedDefSet{"matrix", getMatrixDefinitions()}) defs = append(defs, NamedDefSet{"arithmetic", getArithmeticDefinitions()}) defs = append(defs, NamedDefSet{"specialsyms", getSpecialSymsDefinitions()}) - defs = append(defs, NamedDefSet{"power", GetPowerDefinitions()}) - defs = append(defs, NamedDefSet{"random", GetRandomDefinitions()}) + defs = append(defs, NamedDefSet{"power", getPowerDefinitions()}) + defs = append(defs, NamedDefSet{"random", getRandomDefinitions()}) defs = append(defs, NamedDefSet{"replacement", getReplacementDefinitions()}) - defs = append(defs, NamedDefSet{"sort", GetSortDefinitions()}) - defs = append(defs, NamedDefSet{"system", GetSystemDefinitions()}) - defs = append(defs, NamedDefSet{"trig", GetTrigDefinitions()}) - defs = append(defs, NamedDefSet{"plot", GetPlotDefinitions()}) - defs = append(defs, NamedDefSet{"string", GetStringDefinitions()}) - defs = append(defs, NamedDefSet{"time", GetTimeDefinitions()}) - defs = append(defs, NamedDefSet{"pattern", GetPatternDefinitions()}) - defs = append(defs, NamedDefSet{"boolean", GetBooleanDefinitions()}) - defs = append(defs, NamedDefSet{"simplify", GetSimplifyDefinitions()}) - defs = append(defs, NamedDefSet{"numbertheory", GetNumberTheoryDefinitions()}) - defs = append(defs, NamedDefSet{"stats", GetStatsDefinitions()}) - defs = append(defs, NamedDefSet{"manip", GetManipDefinitions()}) - defs = append(defs, NamedDefSet{"rubi", GetRubiDefinitions()}) + defs = append(defs, NamedDefSet{"sort", getSortDefinitions()}) + defs = append(defs, NamedDefSet{"system", getSystemDefinitions()}) + defs = append(defs, NamedDefSet{"trig", getTrigDefinitions()}) + defs = append(defs, NamedDefSet{"plot", getPlotDefinitions()}) + defs = append(defs, NamedDefSet{"string", getStringDefinitions()}) + defs = append(defs, NamedDefSet{"time", getTimeDefinitions()}) + defs = append(defs, NamedDefSet{"pattern", getPatternDefinitions()}) + defs = append(defs, NamedDefSet{"boolean", getBooleanDefinitions()}) + defs = append(defs, NamedDefSet{"simplify", getSimplifyDefinitions()}) + defs = append(defs, NamedDefSet{"numbertheory", getNumberTheoryDefinitions()}) + defs = append(defs, NamedDefSet{"stats", getStatsDefinitions()}) + defs = append(defs, NamedDefSet{"manip", getManipDefinitions()}) + defs = append(defs, NamedDefSet{"rubi", getRubiDefinitions()}) // Check for duplicate definitions definedNames := make(map[string]bool) diff --git a/expreduce/builtin_arithmetic.go b/expreduce/builtin_arithmetic.go index de910a6..44f2fdf 100644 --- a/expreduce/builtin_arithmetic.go +++ b/expreduce/builtin_arithmetic.go @@ -1,269 +1,114 @@ package expreduce -import "math/big" -import "strings" +import ( + "math/big" + "strings" -func ExArrayContainsFloat(a []Ex) bool { - res := false - for _, e := range a { - _, isfloat := e.(*Flt) - res = res || isfloat - } - return res -} - -func RationalAssertion(num Ex, den Ex) (r *Rational, isR bool) { - numInt, numIsInt := num.(*Integer) - denPow, denIsPow := HeadAssertion(den, "System`Power") - if !numIsInt || !denIsPow { - return nil, false - } - powInt, powIsInt := denPow.Parts[2].(*Integer) - if !powIsInt { - return nil, false - } - if powInt.Val.Cmp(big.NewInt(-1)) != 0 { - return nil, false - } - denInt, denIsInt := denPow.Parts[1].(*Integer) - if !denIsInt { - return nil, false - } - return NewRational(numInt.Val, denInt.Val), true -} - -type FoldFn int - -const ( - FoldFnAdd FoldFn = iota - FoldFnMul + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/iterspec" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) -func typedRealPart(fn FoldFn, i *Integer, r *Rational, f *Flt, c *Complex) Ex { - if c != nil { - toReturn := c - if f != nil { - if fn == FoldFnAdd { - toReturn.AddF(f) - } else if fn == FoldFnMul { - toReturn.MulF(f) - } - } - if r != nil { - if fn == FoldFnAdd { - toReturn.AddR(r) - } else if fn == FoldFnMul { - toReturn.MulR(r) - } - } - if i != nil { - if fn == FoldFnAdd { - toReturn.AddI(i) - } else if fn == FoldFnMul { - toReturn.MulI(i) - } - } - return toReturn - } - if f != nil { - toReturn := f - if r != nil { - if fn == FoldFnAdd { - toReturn.AddR(r) - } else if fn == FoldFnMul { - toReturn.MulR(r) - } - } - if i != nil { - if fn == FoldFnAdd { - toReturn.AddI(i) - } else if fn == FoldFnMul { - toReturn.MulI(i) - } - } - return toReturn - } - if r != nil { - toReturn := r - if i != nil { - if fn == FoldFnAdd { - toReturn.AddI(i) - } else if fn == FoldFnMul { - toReturn.MulI(i) - } - } - return toReturn - } - if i != nil { - return i - } - return nil -} - -func computeNumericPart(fn FoldFn, e *Expression) (Ex, int) { - var foldedInt *Integer - var foldedRat *Rational - var foldedFlt *Flt - var foldedComp *Complex - for i := 1; i < len(e.Parts); i++ { - // TODO: implement short circuiting if we encounter a zero while - // multiplying. - asInt, isInt := e.Parts[i].(*Integer) - if isInt { - if foldedInt == nil { - // Try deepcopy if problems. I think this does not cause - // problems now because we will only modify the value if we end - // up creating an entirely new expression. - foldedInt = asInt.DeepCopy().(*Integer) - continue - } - if fn == FoldFnAdd { - foldedInt.AddI(asInt) - } else if fn == FoldFnMul { - foldedInt.MulI(asInt) - } - continue - } - asRat, isRat := e.Parts[i].(*Rational) - if isRat { - if foldedRat == nil { - foldedRat = asRat.DeepCopy().(*Rational) - continue - } - if fn == FoldFnAdd { - foldedRat.AddR(asRat) - } else if fn == FoldFnMul { - foldedRat.MulR(asRat) - } - continue - } - asFlt, isFlt := e.Parts[i].(*Flt) - if isFlt { - if foldedFlt == nil { - foldedFlt = asFlt.DeepCopy().(*Flt) - continue - } - if fn == FoldFnAdd { - foldedFlt.AddF(asFlt) - } else if fn == FoldFnMul { - foldedFlt.MulF(asFlt) - } - continue - } - asComp, isComp := e.Parts[i].(*Complex) - if isComp { - if foldedComp == nil { - foldedComp = asComp.DeepCopy().(*Complex) - continue - } - if fn == FoldFnAdd { - foldedComp.AddC(asComp) - } else if fn == FoldFnMul { - foldedComp.MulC(asComp) - } - continue - } - return typedRealPart(fn, foldedInt, foldedRat, foldedFlt, foldedComp), i - } - return typedRealPart(fn, foldedInt, foldedRat, foldedFlt, foldedComp), -1 -} - // Define a special NumberQ for our purposes since this logic does not support // complex numbers yet. TODO(corywalker): fix this. -func numberQForTermCollection(e Ex) bool { +func numberQForTermCollection(e expreduceapi.Ex) bool { // _, ok := e.(*Complex) // if ok { // return false // } - return numberQ(e) + return atoms.NumberQ(e) } -func splitTerm(e Ex) (Ex, Ex, bool) { - asSym, isSym := e.(*Symbol) +func splitTerm(e expreduceapi.Ex) (expreduceapi.Ex, expreduceapi.Ex, bool) { + asSym, isSym := e.(*atoms.Symbol) if isSym { - return NewInteger(big.NewInt(1)), NewExpression([]Ex{ - NewSymbol("System`Times"), - asSym, - }), true + return atoms.NewInteger(big.NewInt(1)), atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + asSym, + }), + + true } - asTimes, isTimes := HeadAssertion(e, "System`Times") + asTimes, isTimes := atoms.HeadAssertion(e, "System`Times") if isTimes { - if len(asTimes.Parts) < 2 { + if len(asTimes.GetParts()) < 2 { return nil, nil, false } - if numberQForTermCollection(asTimes.Parts[1]) { - if len(asTimes.Parts) > 2 { - return asTimes.Parts[1], NewExpression(append([]Ex{NewSymbol("System`Times")}, asTimes.Parts[2:]...)), true + if numberQForTermCollection(asTimes.GetParts()[1]) { + if len(asTimes.GetParts()) > 2 { + return asTimes.GetParts()[1], atoms.NewExpression(append([]expreduceapi.Ex{atoms.NewSymbol("System`Times")}, asTimes.GetParts()[2:]...)), true } } else { - return NewInteger(big.NewInt(1)), NewExpression(append([]Ex{NewSymbol("System`Times")}, asTimes.Parts[1:]...)), true + return atoms.NewInteger(big.NewInt(1)), atoms.NewExpression(append([]expreduceapi.Ex{atoms.NewSymbol("System`Times")}, asTimes.GetParts()[1:]...)), true } } - asExpr, isExpr := e.(*Expression) + asExpr, isExpr := e.(expreduceapi.ExpressionInterface) if isExpr { - return NewInteger(big.NewInt(1)), NewExpression([]Ex{ - NewSymbol("System`Times"), - asExpr, - }), true + return atoms.NewInteger(big.NewInt(1)), atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + asExpr, + }), + + true } return nil, nil, false } -func collectedToTerm(coeffs []Ex, vars Ex, fullPart Ex) Ex { +func collectedToTerm(coeffs []expreduceapi.Ex, vars expreduceapi.Ex, fullPart expreduceapi.Ex) expreduceapi.Ex { // Preserve the original expression if there is no need to change it. // We can keep all the cached values like the hash. if len(coeffs) == 1 { return fullPart } - finalC, _ := computeNumericPart(FoldFnAdd, NewExpression(append([]Ex{ - NewSymbol("System`Plus")}, coeffs...))) + finalC, _ := atoms.ComputeNumericPart(atoms.FoldFnAdd, atoms.NewExpression(append([]expreduceapi.Ex{ + atoms.NewSymbol("System`Plus")}, coeffs...))) - toAdd := NewExpression([]Ex{NewSymbol("System`Times")}) - cAsInt, cIsInt := finalC.(*Integer) + toAdd := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Times")}) + cAsInt, cIsInt := finalC.(*atoms.Integer) if !(cIsInt && cAsInt.Val.Cmp(big.NewInt(1)) == 0) { - toAdd.Parts = append(toAdd.Parts, finalC) + toAdd.AppendEx(finalC) } - vAsExpr, vIsExpr := HeadAssertion(vars, "System`Times") - if vIsExpr && len(vAsExpr.Parts) == 2 { - vars = vAsExpr.Parts[1] + vAsExpr, vIsExpr := atoms.HeadAssertion(vars, "System`Times") + if vIsExpr && len(vAsExpr.GetParts()) == 2 { + vars = vAsExpr.GetParts()[1] } - toAdd.Parts = append(toAdd.Parts, vars) - if len(toAdd.Parts) == 2 { - return toAdd.Parts[1] + toAdd.AppendEx(vars) + if len(toAdd.GetParts()) == 2 { + return toAdd.GetParts()[1] } return toAdd } -func collectTerms(e *Expression) *Expression { - collected := NewExpression([]Ex{NewSymbol("System`Plus")}) - var lastVars Ex - var lastFullPart Ex - lastCoeffs := []Ex{} - for _, part := range e.Parts[1:] { +func collectTerms(e expreduceapi.ExpressionInterface) expreduceapi.ExpressionInterface { + collected := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Plus")}) + var lastVars expreduceapi.Ex + var lastFullPart expreduceapi.Ex + lastCoeffs := []expreduceapi.Ex{} + for _, part := range e.GetParts()[1:] { coeff, vars, isTerm := splitTerm(part) if isTerm { if lastVars == nil { - lastCoeffs = []Ex{coeff} + lastCoeffs = []expreduceapi.Ex{coeff} lastVars = vars lastFullPart = part } else { if hashEx(vars) == hashEx(lastVars) { lastCoeffs = append(lastCoeffs, coeff) } else { - collected.Parts = append(collected.Parts, collectedToTerm(lastCoeffs, lastVars, lastFullPart)) + collected.AppendEx(collectedToTerm(lastCoeffs, lastVars, lastFullPart)) - lastCoeffs = []Ex{coeff} + lastCoeffs = []expreduceapi.Ex{coeff} lastVars = vars lastFullPart = part } } } else { - collected.Parts = append(collected.Parts, part) + collected.AppendEx(part) } } if lastVars != nil { - collected.Parts = append(collected.Parts, collectedToTerm(lastCoeffs, lastVars, lastFullPart)) + collected.AppendEx(collectedToTerm(lastCoeffs, lastVars, lastFullPart)) } return collected } @@ -272,27 +117,27 @@ func getArithmeticDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Plus", Default: "0", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfix(this.Parts[1:], " + ", "System`Plus", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfix(this.GetParts()[1:], " + ", "System`Plus", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // Calls without argument receive identity values - if len(this.Parts) == 1 { - return NewInteger(big.NewInt(0)) + if len(this.GetParts()) == 1 { + return atoms.NewInteger(big.NewInt(0)) } res := this - realPart, symStart := computeNumericPart(FoldFnAdd, this) + realPart, symStart := atoms.ComputeNumericPart(atoms.FoldFnAdd, this) if realPart != nil { if symStart == -1 { return realPart } - res = NewExpression([]Ex{NewSymbol("System`Plus")}) - rAsInt, rIsInt := realPart.(*Integer) + res = atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Plus")}) + rAsInt, rIsInt := realPart.(*atoms.Integer) if !(rIsInt && rAsInt.Val.Cmp(big.NewInt(0)) == 0) { - res.Parts = append(res.Parts, realPart) + res.AppendEx(realPart) } - res.Parts = append(res.Parts, this.Parts[symStart:]...) + res.AppendExArray(this.GetParts()[symStart:]) } collected := collectTerms(res) @@ -301,12 +146,12 @@ func getArithmeticDefinitions() (defs []Definition) { } // If one expression remains, replace this Plus with the expression - if len(res.Parts) == 2 { - return res.Parts[1] + if len(res.GetParts()) == 2 { + return res.GetParts()[1] } // Not exactly right because of "1. + foo[1]", but close enough. - if _, rIsReal := realPart.(*Flt); rIsReal { + if _, rIsReal := realPart.(*atoms.Flt); rIsReal { return exprToN(es, res) } return res @@ -314,86 +159,88 @@ func getArithmeticDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Sum", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - return this.evalIterationFunc(es, NewInteger(big.NewInt(0)), "System`Plus") + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return iterspec.EvalIterationFunc(this, es, atoms.NewInteger(big.NewInt(0)), "System`Plus") }, }) defs = append(defs, Definition{ Name: "Times", Default: "1", - toString: func(this *Expression, params ToStringParams) (bool, string) { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { delim := "*" - if params.form == "TeXForm" { + if params.Form == "TeXForm" { delim = " " } - ok, res := ToStringInfix(this.Parts[1:], delim, "System`Times", params) - if ok && strings.HasPrefix(res, "(-1)" + delim) { + ok, res := toStringInfix(this.GetParts()[1:], delim, "System`Times", params) + if ok && strings.HasPrefix(res, "(-1)"+delim) { return ok, "-" + res[5:] } return ok, res }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // Calls without argument receive identity values - if len(this.Parts) == 1 { - return NewInteger(big.NewInt(1)) + if len(this.GetParts()) == 1 { + return atoms.NewInteger(big.NewInt(1)) } res := this - realPart, symStart := computeNumericPart(FoldFnMul, this) + realPart, symStart := atoms.ComputeNumericPart(atoms.FoldFnMul, this) if realPart != nil { if symStart == -1 { return realPart } - res = NewExpression([]Ex{NewSymbol("System`Times")}) - rAsInt, rIsInt := realPart.(*Integer) + res = atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Times")}) + rAsInt, rIsInt := realPart.(*atoms.Integer) if rIsInt && rAsInt.Val.Cmp(big.NewInt(0)) == 0 { - containsInfinity := MemberQ(this.Parts[symStart:], NewExpression([]Ex{ - NewSymbol("System`Alternatives"), - NewSymbol("System`Infinity"), - NewSymbol("System`ComplexInfinity"), - NewSymbol("System`Indeterminate"), - }), es) + containsInfinity := memberQ(this.GetParts()[symStart:], atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Alternatives"), + atoms.NewSymbol("System`Infinity"), + atoms.NewSymbol("System`ComplexInfinity"), + atoms.NewSymbol("System`Indeterminate"), + }), + + es) if containsInfinity { - return NewSymbol("System`Indeterminate") + return atoms.NewSymbol("System`Indeterminate") } - return NewInteger(big.NewInt(0)) + return atoms.NewInteger(big.NewInt(0)) } if !(rIsInt && rAsInt.Val.Cmp(big.NewInt(1)) == 0) { - res.Parts = append(res.Parts, realPart) + res.AppendEx(realPart) } - res.Parts = append(res.Parts, this.Parts[symStart:]...) + res.AppendExArray(this.GetParts()[symStart:]) } // If one expression remains, replace this Times with the expression - if len(res.Parts) == 2 { - return res.Parts[1] + if len(res.GetParts()) == 2 { + return res.GetParts()[1] } // Automatically Expand negations (*-1), not (*-1.) of a Plus expression // Perhaps better implemented as a rule. - if len(res.Parts) == 3 { - leftint, leftintok := res.Parts[1].(*Integer) - rightplus, rightplusok := HeadAssertion(res.Parts[2], "System`Plus") + if len(res.GetParts()) == 3 { + leftint, leftintok := res.GetParts()[1].(*atoms.Integer) + rightplus, rightplusok := atoms.HeadAssertion(res.GetParts()[2], "System`Plus") if leftintok && rightplusok { if leftint.Val.Cmp(big.NewInt(-1)) == 0 { - toreturn := NewExpression([]Ex{NewSymbol("System`Plus")}) - addends := rightplus.Parts[1:len(rightplus.Parts)] + toreturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Plus")}) + addends := rightplus.GetParts()[1:len(rightplus.GetParts())] for i := range addends { - toAppend := NewExpression([]Ex{ - NewSymbol("System`Times"), + toAppend := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), addends[i], - NewInteger(big.NewInt(-1)), + atoms.NewInteger(big.NewInt(-1)), }) - toreturn.Parts = append(toreturn.Parts, toAppend) + toreturn.AppendEx(toAppend) } - return toreturn.Eval(es) + return es.Eval(toreturn) } } } // Not exactly right because of "1. + foo[1]", but close enough. - if _, rIsReal := realPart.(*Flt); rIsReal { + if _, rIsReal := realPart.(*atoms.Flt); rIsReal { return exprToN(es, res) } return res @@ -401,8 +248,8 @@ func getArithmeticDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Product", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - return this.evalIterationFunc(es, NewInteger(big.NewInt(1)), "System`Times") + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return iterspec.EvalIterationFunc(this, es, atoms.NewInteger(big.NewInt(1)), "System`Times") }, }) defs = append(defs, Definition{Name: "Abs"}) diff --git a/expreduce/builtin_atoms.go b/expreduce/builtin_atoms.go index f28aca6..64fce11 100644 --- a/expreduce/builtin_atoms.go +++ b/expreduce/builtin_atoms.go @@ -1,40 +1,45 @@ package expreduce +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + func getAtomsDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Rational", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - nAsInt, nIsInt := this.Parts[1].(*Integer) - dAsInt, dIsInt := this.Parts[2].(*Integer) + nAsInt, nIsInt := this.GetParts()[1].(*atoms.Integer) + dAsInt, dIsInt := this.GetParts()[2].(*atoms.Integer) if nIsInt && dIsInt { - return NewRational(nAsInt.Val, dAsInt.Val).Eval(es) + return es.Eval(atoms.NewRational(nAsInt.Val, dAsInt.Val)) } return this }, }) defs = append(defs, Definition{ Name: "Complex", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - validComplexType := func(e Ex) bool { + validComplexType := func(e expreduceapi.Ex) bool { switch e.(type) { - case *Integer: + case *atoms.Integer: return true - case *Flt: + case *atoms.Flt: return true - case *Rational: + case *atoms.Rational: return true default: return false } } - if validComplexType(this.Parts[1]) && validComplexType(this.Parts[2]) { - return NewComplex(this.Parts[1], this.Parts[2]).Eval(es) + if validComplexType(this.GetParts()[1]) && validComplexType(this.GetParts()[2]) { + return es.Eval(atoms.NewComplex(this.GetParts()[1], this.GetParts()[2])) } return this }, @@ -46,12 +51,17 @@ func getAtomsDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Im", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, }) defs = append(defs, Definition{ Name: "Re", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, + }) + defs = append(defs, Definition{ + Name: "ReIm", + OmitDocumentation: true, + expreduceSpecific: true, }) return } diff --git a/expreduce/builtin_boolean.go b/expreduce/builtin_boolean.go index a43764d..e264125 100644 --- a/expreduce/builtin_boolean.go +++ b/expreduce/builtin_boolean.go @@ -1,69 +1,74 @@ package expreduce -func GetBooleanDefinitions() (defs []Definition) { +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func getBooleanDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "And", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfix(this.Parts[1:], " && ", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfix(this.GetParts()[1:], " && ", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - res := NewExpression([]Ex{NewSymbol("System`And")}) - for i := 1; i < len(this.Parts); i++ { - this.Parts[i] = this.Parts[i].Eval(es) - if booleanQ(this.Parts[i], &es.CASLogger) { - if falseQ(this.Parts[i], &es.CASLogger) { - return NewSymbol("System`False") + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + res := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`And")}) + for i := 1; i < len(this.GetParts()); i++ { + this.GetParts()[i] = es.Eval(this.GetParts()[i]) + if booleanQ(this.GetParts()[i], es.GetLogger()) { + if falseQ(this.GetParts()[i], es.GetLogger()) { + return atoms.NewSymbol("System`False") } } else { - res.appendEx(this.Parts[i]) + res.AppendEx(this.GetParts()[i]) } } - if len(res.Parts) == 1 { - return NewSymbol("System`True") + if len(res.GetParts()) == 1 { + return atoms.NewSymbol("System`True") } - if len(res.Parts) == 2 { - return res.Parts[1] + if len(res.GetParts()) == 2 { + return res.GetParts()[1] } return res }, }) defs = append(defs, Definition{ Name: "Or", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfix(this.Parts[1:], " || ", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfix(this.GetParts()[1:], " || ", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - res := NewExpression([]Ex{NewSymbol("System`Or")}) - for i := 1; i < len(this.Parts); i++ { - this.Parts[i] = this.Parts[i].Eval(es) - if booleanQ(this.Parts[i], &es.CASLogger) { - if trueQ(this.Parts[i], &es.CASLogger) { - return NewSymbol("System`True") + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + res := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Or")}) + for i := 1; i < len(this.GetParts()); i++ { + this.GetParts()[i] = es.Eval(this.GetParts()[i]) + if booleanQ(this.GetParts()[i], es.GetLogger()) { + if trueQ(this.GetParts()[i], es.GetLogger()) { + return atoms.NewSymbol("System`True") } } else { - res.appendEx(this.Parts[i]) + res.AppendEx(this.GetParts()[i]) } } - if len(res.Parts) == 1 { - return NewSymbol("System`False") + if len(res.GetParts()) == 1 { + return atoms.NewSymbol("System`False") } - if len(res.Parts) == 2 { - return res.Parts[1] + if len(res.GetParts()) == 2 { + return res.GetParts()[1] } return res }, }) defs = append(defs, Definition{ Name: "Not", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - if trueQ(this.Parts[1], &es.CASLogger) { - return NewSymbol("System`False") + if trueQ(this.GetParts()[1], es.GetLogger()) { + return atoms.NewSymbol("System`False") } - if falseQ(this.Parts[1], &es.CASLogger) { - return NewSymbol("System`True") + if falseQ(this.GetParts()[1], es.GetLogger()) { + return atoms.NewSymbol("System`True") } return this }, diff --git a/expreduce/builtin_combinatorics.go b/expreduce/builtin_combinatorics.go index 55833db..87b5977 100644 --- a/expreduce/builtin_combinatorics.go +++ b/expreduce/builtin_combinatorics.go @@ -2,6 +2,9 @@ package expreduce import ( "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) // Used for the IntegerPartitions builtin @@ -16,20 +19,20 @@ func genIntegerPartitions(n int, k int, startAt int, prefix []int, parts *[][]in *parts = append(*parts, make([]int, len(prefix))) copy((*parts)[len(*parts)-1], prefix) } else { - genIntegerPartitions(n-i, k, Min(i, n-i), prefix, parts) + genIntegerPartitions(n-i, k, min(i, n-i), prefix, parts) } } } // Used for the Permutations builtin -func permListContains(permList [][]Ex, perm []Ex, cl *CASLogger) bool { +func permListContains(permList [][]expreduceapi.Ex, perm []expreduceapi.Ex, cl expreduceapi.LoggingInterface) bool { for _, permInList := range permList { if len(permInList) != len(perm) { continue } same := true for i := range perm { - if !IsSameQ(perm[i], permInList[i], cl) { + if !atoms.IsSameQ(perm[i], permInList[i]) { same = false //break } @@ -42,25 +45,25 @@ func permListContains(permList [][]Ex, perm []Ex, cl *CASLogger) bool { } // Used for the Permutations builtin -func genPermutations(parts []Ex, cl *CASLogger) (perms [][]Ex) { +func genPermutations(parts []expreduceapi.Ex, cl expreduceapi.LoggingInterface) (perms [][]expreduceapi.Ex) { // Base case if len(parts) == 1 { - return [][]Ex{parts} + return [][]expreduceapi.Ex{parts} } // Recursion - toReturn := [][]Ex{} + toReturn := [][]expreduceapi.Ex{} for i, first := range parts { // We must make a copy of "parts" because selecting "others" actually // modifies "parts" and corrupts it. - copyParts := make([]Ex, len(parts)) + copyParts := make([]expreduceapi.Ex, len(parts)) copy(copyParts, parts) others := append(copyParts[:i], copyParts[i+1:]...) // TODO: This might be bad for memory complexity. otherPerms := genPermutations(others, cl) for _, perm := range otherPerms { - prepended := make([]Ex, len(perm)) + prepended := make([]expreduceapi.Ex, len(perm)) copy(prepended, perm) - perm = append([]Ex{first}, perm...) + perm = append([]expreduceapi.Ex{first}, perm...) // TODO: And this is bad for time complexity: if !permListContains(toReturn, perm, cl) { toReturn = append(toReturn, perm) @@ -89,43 +92,43 @@ func factorial(n *big.Int) (result *big.Int) { func getCombinatoricsDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "IntegerPartitions", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 && len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 && len(this.GetParts()) != 3 { return this } - n, nIsInt := this.Parts[1].(*Integer) + n, nIsInt := this.GetParts()[1].(*atoms.Integer) if !nIsInt { return this } - nMachine := int(n.Val.Int64()) + nnumMachine := int(n.Val.Int64()) - kMachine := nMachine - if len(this.Parts) == 3 { - k, kIsInt := this.Parts[2].(*Integer) - if !kIsInt { + knumMachine := nnumMachine + if len(this.GetParts()) == 3 { + k, knumIsInt := this.GetParts()[2].(*atoms.Integer) + if !knumIsInt { return this } - kMachine = int(k.Val.Int64()) + knumMachine = int(k.Val.Int64()) } cmpVal := n.Val.Cmp(big.NewInt(0)) if cmpVal == -1 { - return NewExpression([]Ex{NewSymbol("System`List")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) } else if cmpVal == 0 { - return NewExpression([]Ex{NewSymbol("System`List"), NewExpression([]Ex{NewSymbol("System`List")})}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List"), atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")})}) } var parts [][]int - genIntegerPartitions(nMachine, kMachine, nMachine, []int{}, &parts) + genIntegerPartitions(nnumMachine, knumMachine, nnumMachine, []int{}, &parts) - exParts := NewExpression([]Ex{NewSymbol("System`List")}) + exParts := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for _, partition := range parts { - toAppend := NewExpression([]Ex{NewSymbol("System`List")}) + toAppend := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for _, integer := range partition { - toAppend.Parts = append(toAppend.Parts, NewInteger(big.NewInt(int64(integer)))) + toAppend.AppendEx(atoms.NewInteger(big.NewInt(int64(integer)))) } - exParts.Parts = append(exParts.Parts, toAppend) + exParts.AppendEx(toAppend) } return exParts @@ -133,25 +136,25 @@ func getCombinatoricsDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Permutations", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - list, listIsExpr := this.Parts[1].(*Expression) + list, listIsExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !listIsExpr { return this } - perms := genPermutations(list.Parts[1:], &es.CASLogger) + perms := genPermutations(list.GetParts()[1:], es.GetLogger()) - exPerms := NewExpression([]Ex{NewSymbol("System`List")}) + exPerms := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for _, perm := range perms { - toAppend := NewExpression([]Ex{NewSymbol("System`List")}) + toAppend := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for _, ex := range perm { - toAppend.Parts = append(toAppend.Parts, ex) + toAppend.AppendEx(ex) } - exPerms.Parts = append(exPerms.Parts, toAppend) + exPerms.AppendEx(toAppend) } return exPerms @@ -162,16 +165,16 @@ func getCombinatoricsDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Factorial", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - asInt, isInt := this.Parts[1].(*Integer) + asInt, isInt := this.GetParts()[1].(*atoms.Integer) if isInt { if asInt.Val.Cmp(big.NewInt(0)) == -1 { - return NewSymbol("System`ComplexInfinity") + return atoms.NewSymbol("System`ComplexInfinity") } - return NewInteger(factorial(asInt.Val)) + return atoms.NewInteger(factorial(asInt.Val)) } return this }, diff --git a/expreduce/builtin_comparison.go b/expreduce/builtin_comparison.go index 12a06b6..45fc8dc 100644 --- a/expreduce/builtin_comparison.go +++ b/expreduce/builtin_comparison.go @@ -1,57 +1,61 @@ package expreduce -import "sort" +import ( + "sort" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) type extremaFnType int const ( - MaxFn extremaFnType = iota - MinFn + maxFn extremaFnType = iota + minFn ) -func extremaFunction(this *Expression, fnType extremaFnType, es *EvalState) Ex { +func extremaFunction(this expreduceapi.ExpressionInterface, fnType extremaFnType, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // Flatten nested lists into arguments. - origHead := this.Parts[0] - this.Parts[0] = S("List") - dst := E(S("List")) - flattenExpr(this, dst, 999999999, &es.CASLogger) + origHead := this.GetParts()[0] + this.GetParts()[0] = atoms.S("List") + dst := atoms.E(atoms.S("List")) + flattenExpr(this, dst, 999999999, es.GetLogger()) // Previously I always set the pointer but it led to an endless // eval loop. I think evaluation might use the pointer to make a // "same" comparison. - if !IsSameQ(this, dst, &es.CASLogger) { + if !atoms.IsSameQ(this, dst) { this = dst sort.Sort(this) } - this.Parts[0] = origHead + this.GetParts()[0] = origHead - if len(this.Parts) == 1 { - if fnType == MaxFn { - return E(S("Times"), NewInt(-1), S("Infinity")) - } else { - return S("Infinity") + if len(this.GetParts()) == 1 { + if fnType == maxFn { + return atoms.E(atoms.S("Times"), atoms.NewInt(-1), atoms.S("Infinity")) } + return atoms.S("Infinity") } - if len(this.Parts) == 2 { - return this.Parts[1] + if len(this.GetParts()) == 2 { + return this.GetParts()[1] } var i int - for i = 1; i < len(this.Parts); i++ { - if !numberQ(this.Parts[i]) { + for i = 1; i < len(this.GetParts()); i++ { + if !atoms.NumberQ(this.GetParts()[i]) { break } } - if fnType == MaxFn { - i -= 1 - return NewExpression(append([]Ex{this.Parts[0]}, this.Parts[i:]...)) + if fnType == maxFn { + i-- + return atoms.NewExpression(append([]expreduceapi.Ex{this.GetParts()[0]}, this.GetParts()[i:]...)) } if i == 1 { return this } - return NewExpression(append(this.Parts[:2], this.Parts[i:]...)) + return atoms.NewExpression(append(this.GetParts()[:2], this.GetParts()[i:]...)) } -func getCompSign(e Ex) int { - sym, isSym := e.(*Symbol) +func getCompSign(e expreduceapi.Ex) int { + sym, isSym := e.(*atoms.Symbol) if !isSym { return -2 } @@ -73,211 +77,210 @@ func getCompSign(e Ex) int { func getComparisonDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Equal", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " == ", "System`Equal", false, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " == ", "System`Equal", false, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 1 { return this } isequal := true - for i := 2; i < len(this.Parts); i++ { - var equalstr string = this.Parts[1].IsEqual(this.Parts[i], &es.CASLogger) + for i := 2; i < len(this.GetParts()); i++ { + var equalstr string = this.GetParts()[1].IsEqual(this.GetParts()[i]) if equalstr == "EQUAL_UNK" { return this } isequal = isequal && (equalstr == "EQUAL_TRUE") } if isequal { - return NewSymbol("System`True") + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "Unequal", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " != ", "System`Unequal", false, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " != ", "System`Unequal", false, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - var isequal string = this.Parts[1].IsEqual(this.Parts[2], &es.CASLogger) + var isequal string = this.GetParts()[1].IsEqual(this.GetParts()[2]) if isequal == "EQUAL_UNK" { return this } else if isequal == "EQUAL_TRUE" { - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") } else if isequal == "EQUAL_FALSE" { - return NewSymbol("System`True") + return atoms.NewSymbol("System`True") } - return NewExpression([]Ex{NewSymbol("System`Error"), NewString("Unexpected equality return value.")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString("Unexpected equality return value.")}) }, }) defs = append(defs, Definition{ Name: "SameQ", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " === ", "System`SameQ", false, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " === ", "System`SameQ", false, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 1 { return this } issame := true - for i := 2; i < len(this.Parts); i++ { - issame = issame && IsSameQ(this.Parts[1], this.Parts[i], &es.CASLogger) + for i := 2; i < len(this.GetParts()); i++ { + issame = issame && atoms.IsSameQ(this.GetParts()[1], this.GetParts()[i]) } if issame { - return NewSymbol("System`True") - } else { - return NewSymbol("System`False") + return atoms.NewSymbol("System`True") } + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "UnsameQ", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " =!= ", "System`UnsameQ", false, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " =!= ", "System`UnsameQ", false, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 1 { return this } - for i := 1; i < len(this.Parts); i++ { - for j := i + 1; j < len(this.Parts); j++ { - if IsSameQ(this.Parts[i], this.Parts[j], &es.CASLogger) { - return NewSymbol("System`False") + for i := 1; i < len(this.GetParts()); i++ { + for j := i + 1; j < len(this.GetParts()); j++ { + if atoms.IsSameQ(this.GetParts()[i], this.GetParts()[j]) { + return atoms.NewSymbol("System`False") } } } - return NewSymbol("System`True") + return atoms.NewSymbol("System`True") }, }) defs = append(defs, Definition{ Name: "AtomQ", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - _, IsExpr := this.Parts[1].(*Expression) - if IsExpr { - return NewSymbol("System`False") + _, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) + if isExpr { + return atoms.NewSymbol("System`False") } - return NewSymbol("System`True") + return atoms.NewSymbol("System`True") }, }) defs = append(defs, Definition{ Name: "NumberQ", - legacyEvalFn: singleParamQEval(numberQ), + legacyEvalFn: singleParamQEval(atoms.NumberQ), }) defs = append(defs, Definition{ Name: "NumericQ", }) defs = append(defs, Definition{ Name: "Less", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " < ", "", true, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " < ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - a := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[1]}).Eval(es) - b := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[2]}).Eval(es) + a := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[1]})) + b := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[2]})) - if !numberQ(a) || !numberQ(b) { + if !atoms.NumberQ(a) || !atoms.NumberQ(b) { return this } // Less - if ExOrder(a, b) == 1 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == 1 { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "Greater", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " > ", "", true, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " > ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - a := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[1]}).Eval(es) - b := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[2]}).Eval(es) + a := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[1]})) + b := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[2]})) - if !numberQ(a) || !numberQ(b) { + if !atoms.NumberQ(a) || !atoms.NumberQ(b) { return this } // Greater - if ExOrder(a, b) == -1 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == -1 { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "LessEqual", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " <= ", "", true, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " <= ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - a := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[1]}).Eval(es) - b := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[2]}).Eval(es) + a := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[1]})) + b := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[2]})) - if !numberQ(a) || !numberQ(b) { + if !atoms.NumberQ(a) || !atoms.NumberQ(b) { return this } // Less - if ExOrder(a, b) == 1 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == 1 { + return atoms.NewSymbol("System`True") } // Equal - if ExOrder(a, b) == 0 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == 0 { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "GreaterEqual", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], " >= ", "", true, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfixAdvanced(this.GetParts()[1:], " >= ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - a := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[1]}).Eval(es) - b := NewExpression([]Ex{NewSymbol("System`N"), this.Parts[2]}).Eval(es) + a := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[1]})) + b := es.Eval(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), this.GetParts()[2]})) - if !numberQ(a) || !numberQ(b) { + if !atoms.NumberQ(a) || !atoms.NumberQ(b) { return this } // Greater - if ExOrder(a, b) == -1 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == -1 { + return atoms.NewSymbol("System`True") } // Equal - if ExOrder(a, b) == 0 { - return NewSymbol("System`True") + if atoms.ExOrder(a, b) == 0 { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ @@ -288,14 +291,14 @@ func getComparisonDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Max", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - return extremaFunction(this, MaxFn, es) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return extremaFunction(this, maxFn, es) }, }) defs = append(defs, Definition{ Name: "Min", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - return extremaFunction(this, MinFn, es) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return extremaFunction(this, minFn, es) }, }) defs = append(defs, Definition{Name: "PossibleZeroQ"}) @@ -303,68 +306,68 @@ func getComparisonDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Element"}) defs = append(defs, Definition{ Name: "Inequality", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) == 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) == 1 { return this } - if len(this.Parts) == 2 { - return S("True") + if len(this.GetParts()) == 2 { + return atoms.S("True") } - if len(this.Parts) % 2 != 0 { + if len(this.GetParts())%2 != 0 { return this } - firstSign := getCompSign(this.Parts[2]) + firstSign := getCompSign(this.GetParts()[2]) if firstSign == -2 { return this } if firstSign != 0 { - for i := 4; i < len(this.Parts); i += 2 { - thisSign := getCompSign(this.Parts[i]) + for i := 4; i < len(this.GetParts()); i += 2 { + thisSign := getCompSign(this.GetParts()[i]) if thisSign == -2 { return this } if thisSign == -firstSign { - firstIneq := E(S("Inequality")) - secondIneq := E(S("Inequality")) - for j := 1; j < len(this.Parts); j++ { + firstIneq := atoms.E(atoms.S("Inequality")) + secondIneq := atoms.E(atoms.S("Inequality")) + for j := 1; j < len(this.GetParts()); j++ { if j < i { - firstIneq.appendEx(this.Parts[j]) + firstIneq.AppendEx(this.GetParts()[j]) } - if j > (i-2) { - secondIneq.appendEx(this.Parts[j]) + if j > (i - 2) { + secondIneq.AppendEx(this.GetParts()[j]) } } - return E(S("And"), firstIneq, secondIneq) + return atoms.E(atoms.S("And"), firstIneq, secondIneq) } } } - res := E(S("Inequality")) - for i := 0; i < (len(this.Parts)-1)/2; i++ { - lhs := this.Parts[2*i+1] - if len(res.Parts) > 1 { - lhs = res.Parts[len(res.Parts)-1] + res := atoms.E(atoms.S("Inequality")) + for i := 0; i < (len(this.GetParts())-1)/2; i++ { + lhs := this.GetParts()[2*i+1] + if len(res.GetParts()) > 1 { + lhs = res.GetParts()[len(res.GetParts())-1] } - op := this.Parts[2*i+2] - rhs := this.Parts[2*i+3] - for rhsI := 2*i+3; rhsI < len(this.Parts); rhsI+=2 { - if falseQ(E(op, lhs, this.Parts[rhsI]).Eval(es), &es.CASLogger) { - return S("False") + op := this.GetParts()[2*i+2] + rhs := this.GetParts()[2*i+3] + for rhsI := 2*i + 3; rhsI < len(this.GetParts()); rhsI += 2 { + if falseQ(es.Eval(atoms.E(op, lhs, this.GetParts()[rhsI])), es.GetLogger()) { + return atoms.S("False") } } - evalRes := E(op, lhs, rhs).Eval(es) - if !trueQ(evalRes, &es.CASLogger) { - if !IsSameQ(res.Parts[len(res.Parts)-1], lhs, &es.CASLogger) { - res.appendEx(lhs) + evalRes := es.Eval(atoms.E(op, lhs, rhs)) + if !trueQ(evalRes, es.GetLogger()) { + if !atoms.IsSameQ(res.GetParts()[len(res.GetParts())-1], lhs) { + res.AppendEx(lhs) } - res.appendEx(op) - res.appendEx(rhs) + res.AppendEx(op) + res.AppendEx(rhs) } } - if len(res.Parts) == 1 { - return S("True") + if len(res.GetParts()) == 1 { + return atoms.S("True") } - if len(res.Parts) == 4 { - return E(res.Parts[2], res.Parts[1], res.Parts[3]) + if len(res.GetParts()) == 4 { + return atoms.E(res.GetParts()[2], res.GetParts()[1], res.GetParts()[3]) } return res }, diff --git a/expreduce/builtin_equationdata.go b/expreduce/builtin_equationdata.go index a6c9e1e..fed08bc 100644 --- a/expreduce/builtin_equationdata.go +++ b/expreduce/builtin_equationdata.go @@ -1,5 +1,5 @@ package expreduce -func GetEquationDataDefinitions() (defs []Definition) { +func getEquationDataDefinitions() (defs []Definition) { return } diff --git a/expreduce/builtin_expression.go b/expreduce/builtin_expression.go index 070faee..5d9147e 100644 --- a/expreduce/builtin_expression.go +++ b/expreduce/builtin_expression.go @@ -1,38 +1,43 @@ package expreduce -import "math/big" +import ( + "math/big" -func CalcDepth(ex Ex) int { - expr, isExpr := ex.(*Expression) + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func calcDepth(ex expreduceapi.Ex) int { + expr, isExpr := ex.(expreduceapi.ExpressionInterface) if !isExpr { return 1 } theMax := 1 // Find max depth of params. Heads are not counted. - for i := 1; i < len(expr.Parts); i++ { - theMax = Max(theMax, CalcDepth(expr.Parts[i])) + for i := 1; i < len(expr.GetParts()); i++ { + theMax = max(theMax, calcDepth(expr.GetParts()[i])) } return theMax + 1 } -func flattenExpr(src *Expression, dst *Expression, level int64, cl *CASLogger) { +func flattenExpr(src expreduceapi.ExpressionInterface, dst expreduceapi.ExpressionInterface, level int64, cl expreduceapi.LoggingInterface) { continueFlatten := level > 0 - for i := 1; i < len(src.Parts); i++ { - expr, isExpr := src.Parts[i].(*Expression) + for i := 1; i < len(src.GetParts()); i++ { + expr, isExpr := src.GetParts()[i].(expreduceapi.ExpressionInterface) if continueFlatten && isExpr { - if IsSameQ(src.Parts[0], expr.Parts[0], cl) { + if atoms.IsSameQ(src.GetParts()[0], expr.GetParts()[0]) { flattenExpr(expr, dst, level-1, cl) continue } } - dst.Parts = append(dst.Parts, src.Parts[i]) + dst.AppendEx(src.GetParts()[i]) } } -func leafCount(e Ex) int64 { - if asExpr, isExpr := e.(*Expression); isExpr { +func leafCount(e expreduceapi.Ex) int64 { + if asExpr, isExpr := e.(expreduceapi.ExpressionInterface); isExpr { res := int64(0) - for _, part := range asExpr.Parts { + for _, part := range asExpr.GetParts() { res += leafCount(part) } return res @@ -40,66 +45,66 @@ func leafCount(e Ex) int64 { return 1 } -func GetExpressionDefinitions() (defs []Definition) { +func getExpressionDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Head", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - _, IsFlt := this.Parts[1].(*Flt) - if IsFlt { - return NewSymbol("System`Real") + _, isFlt := this.GetParts()[1].(*atoms.Flt) + if isFlt { + return atoms.NewSymbol("System`Real") } - _, IsInteger := this.Parts[1].(*Integer) - if IsInteger { - return NewSymbol("System`Integer") + _, isInteger := this.GetParts()[1].(*atoms.Integer) + if isInteger { + return atoms.NewSymbol("System`Integer") } - _, IsString := this.Parts[1].(*String) - if IsString { - return NewSymbol("System`String") + _, isString := this.GetParts()[1].(*atoms.String) + if isString { + return atoms.NewSymbol("System`String") } - _, IsSymbol := this.Parts[1].(*Symbol) - if IsSymbol { - return NewSymbol("System`Symbol") + _, isSymbol := this.GetParts()[1].(*atoms.Symbol) + if isSymbol { + return atoms.NewSymbol("System`Symbol") } - _, IsRational := this.Parts[1].(*Rational) - if IsRational { - return NewSymbol("System`Rational") + _, isRational := this.GetParts()[1].(*atoms.Rational) + if isRational { + return atoms.NewSymbol("System`Rational") } - _, IsComplex := this.Parts[1].(*Complex) - if IsComplex { - return NewSymbol("System`Complex") + _, isComplex := this.GetParts()[1].(*atoms.Complex) + if isComplex { + return atoms.NewSymbol("System`Complex") } - asExpr, IsExpression := this.Parts[1].(*Expression) - if IsExpression { - return asExpr.Parts[0] + asExpr, isExpression := this.GetParts()[1].(expreduceapi.ExpressionInterface) + if isExpression { + return asExpr.GetParts()[0] } return this }, }) defs = append(defs, Definition{ Name: "Depth", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - return NewInteger(big.NewInt(int64(CalcDepth(this.Parts[1])))) + return atoms.NewInteger(big.NewInt(int64(calcDepth(this.GetParts()[1])))) }, }) defs = append(defs, Definition{ Name: "Length", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - return NewInteger(big.NewInt(int64(len(expr.Parts) - 1))) + return atoms.NewInteger(big.NewInt(int64(len(expr.GetParts()) - 1))) } - return NewInteger(big.NewInt(0)) + return atoms.NewInteger(big.NewInt(0)) }, }) defs = append(defs, Definition{ @@ -113,46 +118,46 @@ func GetExpressionDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "HoldForm", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 2 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 2 { return false, "" } - if params.form == "FullForm" { + if params.Form == "FullForm" { return false, "" } - return true, this.Parts[1].StringForm(params) + return true, this.GetParts()[1].StringForm(params) }, }) defs = append(defs, Definition{ Name: "Flatten", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 2 { return this } level := int64(999999999999) - if len(this.Parts) > 2 { - asInt, isInt := this.Parts[2].(*Integer) + if len(this.GetParts()) > 2 { + asInt, isInt := this.GetParts()[2].(*atoms.Integer) if !isInt { return this } level = int64(asInt.Val.Int64()) } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { return this } - dst := NewExpression([]Ex{expr.Parts[0]}) - flattenExpr(expr, dst, level, &es.CASLogger) + dst := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) + flattenExpr(expr, dst, level, es.GetLogger()) return dst }, }) defs = append(defs, Definition{ Name: "LeafCount", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - return NewInt(leafCount(this.Parts[1])) + return atoms.NewInt(leafCount(this.GetParts()[1])) }, }) defs = append(defs, Definition{ diff --git a/expreduce/builtin_flowcontrol.go b/expreduce/builtin_flowcontrol.go index b6403f7..2787b17 100644 --- a/expreduce/builtin_flowcontrol.go +++ b/expreduce/builtin_flowcontrol.go @@ -1,21 +1,28 @@ package expreduce -func applyWithFn(e *Expression, es *EvalState) (Ex, bool) { - if len(e.Parts) != 3 { +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/iterspec" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func applyWithFn(e expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { + if len(e.GetParts()) != 3 { return nil, false } - vars, isList := HeadAssertion(e.Parts[1], "System`List") + vars, isList := atoms.HeadAssertion(e.GetParts()[1], "System`List") if !isList { return nil, false } - rules := []*Expression{} - for _, vDef := range vars.Parts[1:] { - set, isSet := HeadAssertion(vDef, "System`Set") - setDelayed, isSetDelayed := HeadAssertion(vDef, "System`SetDelayed") + rules := []expreduceapi.ExpressionInterface{} + for _, vDef := range vars.GetParts()[1:] { + set, isSet := atoms.HeadAssertion(vDef, "System`Set") + setDelayed, isSetDelayed := atoms.HeadAssertion(vDef, "System`SetDelayed") if !(isSet || isSetDelayed) { return nil, false } - var setEx *Expression = nil + var setEx expreduceapi.ExpressionInterface ruleHead := "" if isSet { setEx = set @@ -24,81 +31,81 @@ func applyWithFn(e *Expression, es *EvalState) (Ex, bool) { setEx = setDelayed ruleHead = "System`RuleDelayed" } - if len(setEx.Parts) != 3 { + if len(setEx.GetParts()) != 3 { return nil, false } - rules = append(rules, NewExpression([]Ex{ - NewSymbol(ruleHead), - setEx.Parts[1], - setEx.Parts[2], + rules = append(rules, atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol(ruleHead), + setEx.GetParts()[1], + setEx.GetParts()[2], })) } - return rulesReplaceAll(e.Parts[2], rules, es), true + return rulesReplaceAll(e.GetParts()[2], rules, es), true } -func isBreak(e Ex) bool { - _, isBr := HeadAssertion(e, "System`Break") +func isBreak(e expreduceapi.Ex) bool { + _, isBr := atoms.HeadAssertion(e, "System`Break") return isBr } -func GetFlowControlDefinitions() (defs []Definition) { +func getFlowControlDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "If", // WARNING: Watch out for putting rules here. It can interfere with how // Return works. - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) > 4 || len(this.Parts) < 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) > 4 || len(this.GetParts()) < 3 { return this } - var falseVal Ex = NewSymbol("System`Null") - if len(this.Parts) == 4 { - falseVal = this.Parts[3] + var falseVal expreduceapi.Ex = atoms.NewSymbol("System`Null") + if len(this.GetParts()) == 4 { + falseVal = this.GetParts()[3] } - var isequal string = this.Parts[1].IsEqual(NewSymbol("System`True"), &es.CASLogger) + var isequal string = this.GetParts()[1].IsEqual(atoms.NewSymbol("System`True")) if isequal == "EQUAL_UNK" { return this } else if isequal == "EQUAL_TRUE" { - return this.Parts[2] + return this.GetParts()[2] } else if isequal == "EQUAL_FALSE" { return falseVal } - return NewExpression([]Ex{NewSymbol("System`Error"), NewString("Unexpected equality return value.")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString("Unexpected equality return value.")}) }, }) defs = append(defs, Definition{ Name: "While", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - isTrue := IsSameQ(this.Parts[1].DeepCopy().Eval(es), NewSymbol("System`True"), &es.CASLogger) + isTrue := atoms.IsSameQ(es.Eval(this.GetParts()[1].DeepCopy()), atoms.NewSymbol("System`True")) for isTrue { - tmpRes := this.Parts[2].DeepCopy().Eval(es) + tmpRes := es.Eval(this.GetParts()[2].DeepCopy()) retVal, isReturn := tryReturnValue(tmpRes, nil, es) if isReturn { return retVal } if isBreak(tmpRes) { - return S("Null") + return atoms.S("Null") } - isTrue = IsSameQ(this.Parts[1].DeepCopy().Eval(es), NewSymbol("System`True"), &es.CASLogger) + isTrue = atoms.IsSameQ(es.Eval(this.GetParts()[1].DeepCopy()), atoms.NewSymbol("System`True")) } - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") }, }) defs = append(defs, Definition{ Name: "CompoundExpression", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - var toReturn Ex - for i := 1; i < len(this.Parts); i++ { - toReturn = this.Parts[i].Eval(es) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + var toReturn expreduceapi.Ex + for i := 1; i < len(this.GetParts()); i++ { + toReturn = es.Eval(this.GetParts()[i]) if es.HasThrown() { - return es.thrown + return es.Thrown() } - if _, isReturn := HeadAssertion(toReturn, "System`Return"); isReturn { + if _, isReturn := atoms.HeadAssertion(toReturn, "System`Return"); isReturn { return toReturn } } @@ -109,32 +116,32 @@ func GetFlowControlDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Return"}) defs = append(defs, Definition{ Name: "Which", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts)%2 != 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts())%2 != 1 { return this } - for i := 1; i < len(this.Parts); i += 2 { - condRes := this.Parts[i].Eval(es) - resSym, resIsSym := condRes.(*Symbol) + for i := 1; i < len(this.GetParts()); i += 2 { + condRes := es.Eval(this.GetParts()[i]) + resSym, resIsSym := condRes.(*atoms.Symbol) if !resIsSym { continue } if resSym.Name == "System`True" { - return this.Parts[i+1] + return this.GetParts()[i+1] } } - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") }, }) defs = append(defs, Definition{ Name: "Switch", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 4 || len(this.Parts)%2 != 0 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 4 || len(this.GetParts())%2 != 0 { return this } - for i := 2; i < len(this.Parts); i += 2 { - if match, _ := IsMatchQ(this.Parts[1], this.Parts[i], EmptyPD(), es); match { - return this.Parts[i+1] + for i := 2; i < len(this.GetParts()); i += 2 { + if match, _ := matcher.IsMatchQ(this.GetParts()[1], this.GetParts()[i], matcher.EmptyPD(), es); match { + return this.GetParts()[i+1] } } return this @@ -142,7 +149,7 @@ func GetFlowControlDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "With", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { res, ok := applyWithFn(this, es) if !ok { return this @@ -152,28 +159,28 @@ func GetFlowControlDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Do", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) >= 3 { - mis, isOk := multiIterSpecFromLists(es, this.Parts[2:]) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) >= 3 { + mis, isOk := iterspec.MultiSpecFromLists(es, this.GetParts()[2:]) if isOk { // Simulate evaluation within Block[] - mis.takeVarSnapshot(es) - for mis.cont() { - mis.defineCurrent(es) - res := this.Parts[1].DeepCopy().Eval(es) + mis.TakeVarSnapshot(es) + for mis.Cont() { + mis.DefineCurrent(es) + res := es.Eval(this.GetParts()[1].DeepCopy()) if es.HasThrown() { - return es.thrown + return es.Thrown() } - if asReturn, isReturn := HeadAssertion(res, "System`Return"); isReturn { - if len(asReturn.Parts) < 2 { - return NewSymbol("System`Null") + if asReturn, isReturn := atoms.HeadAssertion(res, "System`Return"); isReturn { + if len(asReturn.GetParts()) < 2 { + return atoms.NewSymbol("System`Null") } - return asReturn.Parts[1] + return asReturn.GetParts()[1] } - mis.next() + mis.Next() } - mis.restoreVarSnapshot(es) - return NewSymbol("System`Null") + mis.RestoreVarSnapshot(es) + return atoms.NewSymbol("System`Null") } } return this diff --git a/expreduce/builtin_functional.go b/expreduce/builtin_functional.go index 2882d60..6c19e48 100644 --- a/expreduce/builtin_functional.go +++ b/expreduce/builtin_functional.go @@ -2,76 +2,61 @@ package expreduce import ( "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) //The following functions help to interpret the Ex interface, they could probably be moved //to another file since they are useful in many common situations -func parseInteger(part Ex) (value int64, isInteger bool) { - integer, isInteger := part.(*Integer) +func parseInteger(part expreduceapi.Ex) (value int64, isInteger bool) { + integer, isInteger := part.(*atoms.Integer) if isInteger { return integer.Val.Int64(), true - } else { - return 0, false } + return 0, false } -func parseFloat(part Ex) (value float64, isFloat bool) { - float, isFloat := part.(*Flt) - if isFloat { - value, _ := float.Val.Float64() - return value, true - } else { - return 0, false - } -} - -func parseExpression(part Ex) (expression *Expression, isExpression bool) { - expression, isExpression = part.(*Expression) +func parseExpression(part expreduceapi.Ex) (expression expreduceapi.ExpressionInterface, isExpression bool) { + expression, isExpression = part.(expreduceapi.ExpressionInterface) return expression, isExpression } -func parseSymbol(part Ex) (symbol *Symbol, isSymbol bool) { - symbol, isSymbol = part.(*Symbol) +func parseSymbol(part expreduceapi.Ex) (symbol *atoms.Symbol, isSymbol bool) { + symbol, isSymbol = part.(*atoms.Symbol) return symbol, isSymbol } -func parseInfinity(part Ex, es *EvalState) bool { +func parseInfinity(part expreduceapi.Ex, es expreduceapi.EvalStateInterface) bool { symbol, isSymbol := parseSymbol(part) if isSymbol { - return symbol.IsEqual(NewSymbol("System`Infinity"), &es.CASLogger) == "EQUAL_TRUE" + return symbol.IsEqual(atoms.NewSymbol("System`Infinity")) == "EQUAL_TRUE" } return false } -func parseNegativeInfinity(part Ex, es *EvalState) bool { +func parseNegativeInfinity(part expreduceapi.Ex, es expreduceapi.EvalStateInterface) bool { expr, isExpr := parseExpression(part) if isExpr { - template := NewExpression([]Ex{ - NewSymbol("System`Times"), - NewInt(-1), - NewSymbol("System`Infinity"), + template := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + atoms.NewInt(-1), + atoms.NewSymbol("System`Infinity"), }) - return expr.IsEqual(template, &es.CASLogger) == "EQUAL_TRUE" + + return expr.IsEqual(template) == "EQUAL_TRUE" } return false } // The levelSpec struct is used to work with level specifications type levelSpec struct { - isMinDepth bool //If the min specification represents a depth (as opposed to level) - isMaxDepth bool //If the max specification represents a depth (as opposed to level) - min int64 - max int64 - valid bool -} - -func (spec levelSpec) isLevel() (bool, bool) { - return !spec.isMinDepth, !spec.isMaxDepth -} - -func (spec levelSpec) isDepth() (bool, bool) { - return spec.isMinDepth, spec.isMaxDepth + isMinDepth bool //If the min specification represents a depth (as opposed to level) + isMaxDepth bool //If the max specification represents a depth (as opposed to level) + min int64 + max int64 + valid bool } func (spec levelSpec) isValid() bool { @@ -106,7 +91,7 @@ func (spec levelSpec) checkDepth(depth int64) bool { // Levels can be specified in the form n, {n}, {n1, n2}, Infinity, -Infinity // n, n1, n2 are integers which can be positive or negative -func parseLevelSpec(this Ex, es *EvalState) levelSpec{ +func parseLevelSpec(this expreduceapi.Ex, es expreduceapi.EvalStateInterface) levelSpec { integer, isInteger := parseInteger(this) expression, isExpression := parseExpression(this) isInfinity := parseInfinity(this, es) @@ -123,9 +108,8 @@ func parseLevelSpec(this Ex, es *EvalState) levelSpec{ case isInteger: if integer < 0 { return levelSpec{false, true, 1, -integer, true} - } else { - return levelSpec{false, false, 1, integer, true} } + return levelSpec{false, false, 1, integer, true} case isInfinity: return levelSpec{false, false, 1, inf, true} case isNegativeInfinity: @@ -135,24 +119,23 @@ func parseLevelSpec(this Ex, es *EvalState) levelSpec{ } //If the head of the expression is not List, return false - expression, isList := headExAssertion(expression, NewSymbol("System`List"), &es.CASLogger) + expression, isList := atoms.HeadExAssertion(expression, atoms.NewSymbol("System`List"), es.GetLogger()) if !isList { return levelSpec{false, false, 1, 1, false} } //Handle case where the list has only one element - if len(expression.Parts) == 2 { - integer, isInteger = parseInteger(expression.Parts[1]) - isInfinity := parseInfinity(expression.Parts[1], es) - isNegativeInfinity := parseNegativeInfinity(expression.Parts[1], es) + if len(expression.GetParts()) == 2 { + integer, isInteger = parseInteger(expression.GetParts()[1]) + isInfinity := parseInfinity(expression.GetParts()[1], es) + isNegativeInfinity := parseNegativeInfinity(expression.GetParts()[1], es) switch { case isInteger: if integer < 0 { return levelSpec{true, true, -integer, -integer, true} - } else { - return levelSpec{false, false, integer, integer, true} } + return levelSpec{false, false, integer, integer, true} case isInfinity: return levelSpec{false, false, inf, inf, true} case isNegativeInfinity: @@ -161,29 +144,29 @@ func parseLevelSpec(this Ex, es *EvalState) levelSpec{ } //Handle case where the list has two elements - if len(expression.Parts) == 3 { - integer1, isInteger1 := parseInteger(expression.Parts[1]) - integer2, isInteger2 := parseInteger(expression.Parts[2]) + if len(expression.GetParts()) == 3 { + integer1, isInteger1 := parseInteger(expression.GetParts()[1]) + integer2, isInteger2 := parseInteger(expression.GetParts()[2]) - isInfinity1 := parseInfinity(expression.Parts[1], es) + isInfinity1 := parseInfinity(expression.GetParts()[1], es) if isInfinity1 { integer1 = inf isInteger1 = true } - isInfinity2 := parseInfinity(expression.Parts[2], es) + isInfinity2 := parseInfinity(expression.GetParts()[2], es) if isInfinity2 { integer2 = inf isInteger2 = true } - isNegativeInfinity1 := parseNegativeInfinity(expression.Parts[1], es) + isNegativeInfinity1 := parseNegativeInfinity(expression.GetParts()[1], es) if isNegativeInfinity1 { integer1 = ninf isInteger1 = true } - isNegativeInfinity2 := parseNegativeInfinity(expression.Parts[2], es) + isNegativeInfinity2 := parseNegativeInfinity(expression.GetParts()[2], es) if isNegativeInfinity2 { integer2 = ninf isInteger2 = true @@ -209,10 +192,10 @@ func parseLevelSpec(this Ex, es *EvalState) levelSpec{ //This is an optimization with regards to expressionWalkMapBackwards which only deals with level specification, //expressionWalkMapBackwards also deals with depths, but has to visit the entire expression tree. -func expressionWalkMap(f func(Ex, Ex, []int64, *int64, *EvalState) Ex, head Ex, partSpec[]int64, this *Expression, es *EvalState, spec levelSpec, generated *int64) *Expression { - toReturn := NewExpression([]Ex{this.Parts[0]}) +func expressionWalkMap(f func(expreduceapi.Ex, expreduceapi.Ex, []int64, *int64, expreduceapi.EvalStateInterface) expreduceapi.Ex, head expreduceapi.Ex, partSpec []int64, this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface, spec levelSpec, generated *int64) expreduceapi.ExpressionInterface { + toReturn := atoms.NewExpression([]expreduceapi.Ex{this.GetParts()[0]}) - for i, expr := range this.Parts[1:] { + for i, expr := range this.GetParts()[1:] { newExpression := expr //Keep track of which part in the full expression this corresponds to @@ -221,7 +204,7 @@ func expressionWalkMap(f func(Ex, Ex, []int64, *int64, *EvalState) Ex, head Ex, //If this part is nonatomic and its level is covered by the level specification, //apply expressionWalkMap recursively - expression, isExpression := newExpression.(*Expression) + expression, isExpression := newExpression.(expreduceapi.ExpressionInterface) if isExpression && level < spec.max { newExpression = expressionWalkMap(f, head, currentPartSpec, expression, es, spec, generated) } @@ -230,27 +213,27 @@ func expressionWalkMap(f func(Ex, Ex, []int64, *int64, *EvalState) Ex, head Ex, //specified by the first argument of Map if level >= spec.min { newExpression = f(head, newExpression, currentPartSpec, generated, es) - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } else { - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } } return toReturn } -func expressionWalkMapBackwards(f func(Ex, Ex, []int64, *int64, *EvalState) Ex, head Ex, partSpec[]int64, this *Expression, es *EvalState, spec levelSpec, generated *int64) (*Expression, int64) { - toReturn := NewExpression([]Ex{this.Parts[0]}) +func expressionWalkMapBackwards(f func(expreduceapi.Ex, expreduceapi.Ex, []int64, *int64, expreduceapi.EvalStateInterface) expreduceapi.Ex, head expreduceapi.Ex, partSpec []int64, this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface, spec levelSpec, generated *int64) (expreduceapi.ExpressionInterface, int64) { + toReturn := atoms.NewExpression([]expreduceapi.Ex{this.GetParts()[0]}) currentMaxDepth := int64(1) - for i, expr := range this.Parts[1:] { + for i, expr := range this.GetParts()[1:] { newExpression := expr - depth := int64(0) + var depth int64 currentPartSpec := append(partSpec, int64(i+1)) level := int64(len(currentPartSpec)) - expression, isExpression := newExpression.(*Expression) + expression, isExpression := newExpression.(expreduceapi.ExpressionInterface) if isExpression { //Determine the depth of this part newExpression, depth = expressionWalkMapBackwards(f, head, currentPartSpec, expression, es, spec, generated) @@ -260,46 +243,47 @@ func expressionWalkMapBackwards(f func(Ex, Ex, []int64, *int64, *EvalState) Ex, if spec.checkLevel(level) && spec.checkDepth(depth) { newExpression = f(head, newExpression, currentPartSpec, generated, es) - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } else { - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } } else { //If the node is atomic - level = level+1 + level = level + 1 depth = int64(1) if spec.checkLevel(level) && spec.checkDepth(depth) { newExpression = f(head, expr, currentPartSpec, generated, es) - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } else { - toReturn.Parts = append(toReturn.Parts, newExpression) + toReturn.AppendEx(newExpression) } } } - return toReturn, currentMaxDepth+1 + return toReturn, currentMaxDepth + 1 } -func wrapWithHead(head Ex, expr Ex, partList []int64, _ *int64, es *EvalState) Ex { - return NewExpression([]Ex{head, expr}) +func wrapWithHead(head expreduceapi.Ex, expr expreduceapi.Ex, partList []int64, _ *int64, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return atoms.NewExpression([]expreduceapi.Ex{head, expr}) } -func wrapWithHeadIndexed(head Ex, expr Ex, partList []int64, _ *int64, es *EvalState) Ex { - partSpec := []Ex{NewSymbol("System`List")} +func wrapWithHeadIndexed(head expreduceapi.Ex, expr expreduceapi.Ex, partList []int64, _ *int64, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + partSpec := []expreduceapi.Ex{atoms.NewSymbol("System`List")} for _, part := range partList { - partSpec = append(partSpec, NewInt(part)) + partSpec = append(partSpec, atoms.NewInt(part)) } - partSpecExpr := NewExpression(partSpec) - return NewExpression([]Ex{head, expr, partSpecExpr}) + partSpecExpr := atoms.NewExpression(partSpec) + return atoms.NewExpression([]expreduceapi.Ex{head, expr, partSpecExpr}) } -func applyHead(head Ex, expr Ex, partList []int64, _ *int64, es *EvalState) Ex { - expression, isExpr := expr.(*Expression) +func applyHead(head expreduceapi.Ex, expr expreduceapi.Ex, partList []int64, _ *int64, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + expression, isExpr := expr.(expreduceapi.ExpressionInterface) if !isExpr { return expr } - toReturn := NewExpression([]Ex{head}) - toReturn.Parts = append(toReturn.Parts, expression.Parts[1:]...) + toReturn := atoms.NewExpression([]expreduceapi.Ex{head}) + //toReturn.AppendExArray(expression.GetParts()[1:]) + toReturn.AppendExArray(expression.GetParts()[1:]) return toReturn } @@ -311,77 +295,76 @@ const ( applyOptimizedSimpleLevelSpec ) -func exOrGenerated(e Ex, generated *int64, returnGenerated bool) Ex { +func exOrGenerated(e expreduceapi.Ex, generated *int64, returnGenerated bool) expreduceapi.Ex { if returnGenerated { - return NewInt(*generated) + return atoms.NewInt(*generated) } return e } func levelSpecFunction( - f func(Ex, Ex, []int64, *int64, *EvalState) Ex, + f func(expreduceapi.Ex, expreduceapi.Ex, []int64, *int64, expreduceapi.EvalStateInterface) expreduceapi.Ex, optStrat levelSpecOptimizationStrategy, returnGenerated bool, leveledExprIsFirst bool, -) func(*Expression, *EvalState) Ex { - return func(this *Expression, es *EvalState) Ex { +) func(expreduceapi.ExpressionInterface, expreduceapi.EvalStateInterface) expreduceapi.Ex { + return func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // Optimization of the very common case where the levelspec-ed // operation has two arguments - if len(this.Parts) == 3 { + if len(this.GetParts()) == 3 { if optStrat == mapOptimizedSimpleLevelSpec { - expr, isExpr := this.Parts[2].(*Expression) + expr, isExpr := this.GetParts()[2].(expreduceapi.ExpressionInterface) if isExpr { - toReturn := NewExpression([]Ex{expr.Parts[0]}) - for i := 1; i < len(expr.Parts); i++ { - toReturn.Parts = append(toReturn.Parts, NewExpression([]Ex{ - this.Parts[1], - expr.Parts[i], + toReturn := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) + for i := 1; i < len(expr.GetParts()); i++ { + toReturn.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + this.GetParts()[1], + expr.GetParts()[i], })) } return toReturn } - return this.Parts[2] + return this.GetParts()[2] } else if optStrat == applyOptimizedSimpleLevelSpec { - sym, isSym := this.Parts[1].(*Symbol) - expr, isExpr := this.Parts[2].(*Expression) + sym, isSym := this.GetParts()[1].(*atoms.Symbol) + expr, isExpr := this.GetParts()[2].(expreduceapi.ExpressionInterface) if isSym && isExpr { - toReturn := NewExpression([]Ex{sym}) - toReturn.Parts = append(toReturn.Parts, expr.Parts[1:]...) - return toReturn.Eval(es) + toReturn := atoms.NewExpression([]expreduceapi.Ex{sym}) + toReturn.AppendExArray(expr.GetParts()[1:]) + return es.Eval(toReturn) } - return this.Parts[2] + return this.GetParts()[2] } } - if len(this.Parts) != 4 { + if len(this.GetParts()) != 4 { return this } - spec := parseLevelSpec(this.Parts[3], es) + spec := parseLevelSpec(this.GetParts()[3], es) if !spec.isValid() { return this } // For example the function to apply for Map or the pattern to match // for Count. - dataExpr := this.Parts[1] - leveledExpr := this.Parts[2] + dataExpr := this.GetParts()[1] + leveledExpr := this.GetParts()[2] if leveledExprIsFirst { - dataExpr = this.Parts[2] - leveledExpr = this.Parts[1] + dataExpr = this.GetParts()[2] + leveledExpr = this.GetParts()[1] } generatedData := int64(0) generated := &generatedData // If the leveled expression is atomic, it will be ignored except in // one case - expression, nonAtomic := leveledExpr.(*Expression) + expression, nonAtomic := leveledExpr.(expreduceapi.ExpressionInterface) if !nonAtomic { if spec.checkLevel(0) && spec.checkDepth(0) { return exOrGenerated(f(dataExpr, leveledExpr, []int64{}, generated, es), generated, returnGenerated) - } else { - return exOrGenerated(leveledExpr, generated, returnGenerated) } + return exOrGenerated(leveledExpr, generated, returnGenerated) } if spec.min == 0 && spec.max == 0 { @@ -396,9 +379,8 @@ func levelSpecFunction( if spec.checkLevel(0) && spec.checkDepth(0) { return exOrGenerated(f(dataExpr, newExpression, []int64{}, generated, es), generated, returnGenerated) - } else { - return exOrGenerated(newExpression, generated, returnGenerated) } + return exOrGenerated(newExpression, generated, returnGenerated) } //We now turn to the most general case, where levels can be specified as either @@ -408,13 +390,11 @@ func levelSpecFunction( //Whether to wrap the zeroth level with the function. if spec.checkLevel(0) && spec.checkDepth(depth) { return exOrGenerated(f(dataExpr, newExpression, []int64{}, generated, es), generated, returnGenerated) - } else { - return exOrGenerated(newExpression, generated, returnGenerated) } + return exOrGenerated(newExpression, generated, returnGenerated) } } - func getFunctionalDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Function", @@ -423,56 +403,56 @@ func getFunctionalDefinitions() (defs []Definition) { Name: "Slot", }) defs = append(defs, Definition{ - Name: "Apply", + Name: "Apply", legacyEvalFn: levelSpecFunction(applyHead, applyOptimizedSimpleLevelSpec, false, false), }) defs = append(defs, Definition{ - Name: "Map", + Name: "Map", legacyEvalFn: levelSpecFunction(wrapWithHead, mapOptimizedSimpleLevelSpec, false, false), }) defs = append(defs, Definition{ - Name: "MapIndexed", + Name: "MapIndexed", legacyEvalFn: levelSpecFunction(wrapWithHeadIndexed, mapOptimizedSimpleLevelSpec, false, false), }) defs = append(defs, Definition{ Name: "FoldList", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 4 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 4 { return this } - f := this.Parts[1] - first := this.Parts[2] - values, nonAtomic := this.Parts[3].(*Expression) + f := this.GetParts()[1] + first := this.GetParts()[2] + values, nonAtomic := this.GetParts()[3].(expreduceapi.ExpressionInterface) if !nonAtomic { return this } - toReturn := NewExpression([]Ex{values.Parts[0], first}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{values.GetParts()[0], first}) - if len(values.Parts) < 2 { + if len(values.GetParts()) < 2 { return toReturn } - expr := NewExpression([]Ex{ + expr := atoms.NewExpression([]expreduceapi.Ex{ f, first, - values.Parts[1], + values.GetParts()[1], }) - toReturn.Parts = append(toReturn.Parts, expr) + toReturn.AppendEx(expr) - for i := 2; i < len(values.Parts); i++ { - expr = NewExpression([]Ex{ + for i := 2; i < len(values.GetParts()); i++ { + expr = atoms.NewExpression([]expreduceapi.Ex{ f, expr, - values.Parts[i], + values.GetParts()[i], }) - toReturn.Parts = append(toReturn.Parts, expr) + toReturn.AppendEx(expr) } return toReturn @@ -482,14 +462,14 @@ func getFunctionalDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "NestList", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 4 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 4 { return this } - f := this.Parts[1] - expr := this.Parts[2] - nInt, isInteger := this.Parts[3].(*Integer) + f := this.GetParts()[1] + expr := this.GetParts()[2] + nInt, isInteger := this.GetParts()[3].(*atoms.Integer) if !isInteger { return this } @@ -498,15 +478,15 @@ func getFunctionalDefinitions() (defs []Definition) { return this } - toReturn := NewExpression([]Ex{NewSymbol("System`List"), expr}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List"), expr}) for i := int64(1); i <= n; i++ { - expr = NewExpression([]Ex{ + expr = atoms.NewExpression([]expreduceapi.Ex{ f, expr, }) - toReturn.Parts = append(toReturn.Parts, expr) + toReturn.AppendEx(expr) } return toReturn @@ -516,26 +496,26 @@ func getFunctionalDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Nest"}) defs = append(defs, Definition{ Name: "NestWhileList", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 4 || len(this.Parts) > 7 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) < 4 || len(this.GetParts()) > 7 { return this } - f := this.Parts[1] - expr := this.Parts[2] - test := this.Parts[3] + f := this.GetParts()[1] + expr := this.GetParts()[2] + test := this.GetParts()[3] m := int64(1) - if len(this.Parts) > 4 { - mInt, isInteger := this.Parts[4].(*Integer) - mSymbol, isSymbol := this.Parts[4].(*Symbol) + if len(this.GetParts()) > 4 { + mInt, isInteger := this.GetParts()[4].(*atoms.Integer) + mSymbol, isSymbol := this.GetParts()[4].(*atoms.Symbol) if isInteger { m = mInt.Val.Int64() if m < 0 { return this } } else if isSymbol { - if mSymbol.IsEqual(NewSymbol("System`All"), &es.CASLogger) == "EQUAL_TRUE" { + if mSymbol.IsEqual(atoms.NewSymbol("System`All")) == "EQUAL_TRUE" { m = -1 } else { return this @@ -546,16 +526,16 @@ func getFunctionalDefinitions() (defs []Definition) { } max := int64(-1) - if len(this.Parts) > 5 { - maxInt, isInteger := this.Parts[5].(*Integer) - maxSymbol, isSymbol := this.Parts[5].(*Symbol) + if len(this.GetParts()) > 5 { + maxInt, isInteger := this.GetParts()[5].(*atoms.Integer) + maxSymbol, isSymbol := this.GetParts()[5].(*atoms.Symbol) if isInteger { max = maxInt.Val.Int64() if maxInt.Val.Int64() < 0 { return this } } else if isSymbol { - if maxSymbol.IsEqual(NewSymbol("System`Infinity"), &es.CASLogger) == "EQUAL_TRUE" { + if maxSymbol.IsEqual(atoms.NewSymbol("System`Infinity")) == "EQUAL_TRUE" { max = -1 } else { return this @@ -566,34 +546,35 @@ func getFunctionalDefinitions() (defs []Definition) { } n := int64(0) - if len(this.Parts) > 6 { - bonusIterationsInt, isInteger := this.Parts[6].(*Integer) + if len(this.GetParts()) > 6 { + bonusIterationsInt, isInteger := this.GetParts()[6].(*atoms.Integer) if isInteger && bonusIterationsInt.Val.Int64() >= int64(0) { n = bonusIterationsInt.Val.Int64() } } - evaluated := []Ex{expr.DeepCopy().Eval(es)} - toReturn := NewExpression([]Ex{NewSymbol("System`List"), expr}) + evaluated := []expreduceapi.Ex{es.Eval(expr.DeepCopy())} + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List"), expr}) isequal := "EQUAL_TRUE" cont := isequal == "EQUAL_TRUE" for i := int64(2); cont; i++ { - expr = NewExpression([]Ex{ + expr = atoms.NewExpression([]expreduceapi.Ex{ f, expr, }) - toReturn.Parts = append(toReturn.Parts, expr) - evaluated = append(evaluated, expr.DeepCopy().Eval(es)) // Could use a stack of length m + + toReturn.AppendEx(expr) + evaluated = append(evaluated, es.Eval(expr.DeepCopy())) // Could use a stack of length m if i >= m { - testExpression := NewExpression([]Ex{test}) + testExpression := atoms.NewExpression([]expreduceapi.Ex{test}) if m >= 0 { - testExpression.Parts = append(testExpression.Parts, evaluated[int64(len(evaluated))-m:]...) + testExpression.AppendExArray(evaluated[int64(len(evaluated))-m:]) } else { - testExpression.Parts = append(testExpression.Parts, evaluated...) + testExpression.AppendExArray(evaluated) } - isequal = testExpression.Eval(es).IsEqual(NewSymbol("System`True"), &es.CASLogger) + isequal = es.Eval(testExpression).IsEqual(atoms.NewSymbol("System`True")) cont = isequal == "EQUAL_TRUE" } @@ -604,14 +585,15 @@ func getFunctionalDefinitions() (defs []Definition) { if n > 0 { for i := int64(0); i < n; i++ { - expr = NewExpression([]Ex{ + expr = atoms.NewExpression([]expreduceapi.Ex{ f, expr, }) - toReturn.Parts = append(toReturn.Parts, expr) + + toReturn.AppendEx(expr) } } else { - toReturn.Parts = toReturn.Parts[:int64(len(toReturn.Parts))+n] + toReturn.SetParts(toReturn.GetParts()[:int64(len(toReturn.GetParts()))+n]) } return toReturn @@ -621,40 +603,40 @@ func getFunctionalDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "FixedPointList"}) defs = append(defs, Definition{ Name: "FixedPoint", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - currVal := this.Parts[2] - nextVal := E(this.Parts[1], currVal).Eval(es) - for !IsSameQ(currVal, nextVal, &es.CASLogger) { + currVal := this.GetParts()[2] + nextVal := es.Eval(atoms.E(this.GetParts()[1], currVal)) + for !atoms.IsSameQ(currVal, nextVal) { currVal = nextVal - nextVal = E(this.Parts[1], currVal).Eval(es) + nextVal = es.Eval(atoms.E(this.GetParts()[1], currVal)) } return nextVal }, }) defs = append(defs, Definition{ Name: "Array", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - nInt, nOk := this.Parts[2].(*Integer) + nInt, nOk := this.GetParts()[2].(*atoms.Integer) if nOk { n := nInt.Val.Int64() - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for i := int64(1); i <= n; i++ { - toReturn.Parts = append(toReturn.Parts, NewExpression([]Ex{ - this.Parts[1], - NewInteger(big.NewInt(i)), + toReturn.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + this.GetParts()[1], + atoms.NewInteger(big.NewInt(i)), })) } return toReturn } - return this.Parts[2] + return this.GetParts()[2] }, }) defs = append(defs, Definition{ diff --git a/expreduce/builtin_list.go b/expreduce/builtin_list.go index fdcf07c..cc1f3b4 100644 --- a/expreduce/builtin_list.go +++ b/expreduce/builtin_list.go @@ -1,31 +1,41 @@ package expreduce -import "bytes" -import "math/big" -import "sort" -import "sync" +import ( + "bytes" + "math/big" + "sort" + "sync" -func (this *Expression) ToStringList(params ToStringParams) (bool, string) { - if params.form == "FullForm" { + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/iterspec" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +const maxUint64 = ^uint64(0) +const maxInt64 = int64(maxUint64 >> 1) + +func toStringList(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if params.Form == "FullForm" { return false, "" } var buffer bytes.Buffer - if params.form == "TeXForm" { + if params.Form == "TeXForm" { buffer.WriteString("\\left\\{") } else { buffer.WriteString("{") } - for i, e := range this.Parts[1:] { - params.previousHead = "" + for i, e := range this.GetParts()[1:] { + params.PreviousHead = "" buffer.WriteString(e.StringForm(params)) - if i != len(this.Parts[1:])-1 { + if i != len(this.GetParts()[1:])-1 { buffer.WriteString(",") - if params.form != "TeXForm" { + if params.Form != "TeXForm" { buffer.WriteString(" ") } } } - if params.form == "TeXForm" { + if params.Form == "TeXForm" { buffer.WriteString("\\right\\}") } else { buffer.WriteString("}") @@ -33,31 +43,31 @@ func (this *Expression) ToStringList(params ToStringParams) (bool, string) { return true, buffer.String() } -func MemberQ(components []Ex, item Ex, es *EvalState) bool { +func memberQ(components []expreduceapi.Ex, item expreduceapi.Ex, es expreduceapi.EvalStateInterface) bool { for _, part := range components { - if matchq, _ := IsMatchQ(part, item, EmptyPD(), es); matchq { + if matchq, _ := matcher.IsMatchQ(part, item, matcher.EmptyPD(), es); matchq { return true } } return false } -func ValidatePadParams(this *Expression) (list *Expression, n int64, x Ex, valid bool) { +func validatePadParams(this expreduceapi.ExpressionInterface) (list expreduceapi.ExpressionInterface, n int64, x expreduceapi.Ex, valid bool) { valid = false - x = NewInteger(big.NewInt(0)) - if len(this.Parts) == 4 { - x = this.Parts[3] - } else if len(this.Parts) != 3 { + x = atoms.NewInteger(big.NewInt(0)) + if len(this.GetParts()) == 4 { + x = this.GetParts()[3] + } else if len(this.GetParts()) != 3 { return } - nInt, nIsInt := this.Parts[2].(*Integer) + nInt, nIsInt := this.GetParts()[2].(*atoms.Integer) if !nIsInt { return } n = nInt.Val.Int64() - list, listIsExpr := this.Parts[1].(*Expression) + list, listIsExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !listIsExpr { return } @@ -66,8 +76,8 @@ func ValidatePadParams(this *Expression) (list *Expression, n int64, x Ex, valid return } -func validateIndex(i Ex, l int) (int64, bool) { - iInt, iIsInt := i.(*Integer) +func validateIndex(i expreduceapi.Ex, l int) (int64, bool) { + iInt, iIsInt := i.(*atoms.Integer) if !iIsInt { return 0, false } @@ -81,36 +91,36 @@ func validateIndex(i Ex, l int) (int64, bool) { return iInt.Val.Int64(), true } -func applyIndex(ex Ex, indices []Ex, currDim int) (Ex, bool) { +func applyIndex(ex expreduceapi.Ex, indices []expreduceapi.Ex, currDim int) (expreduceapi.Ex, bool) { // Base case if currDim >= len(indices) { return ex, true } - expr, isExpr := ex.(*Expression) + expr, isExpr := ex.(expreduceapi.ExpressionInterface) if !isExpr { return nil, false } // Singular selection - if _, iIsInt := indices[currDim].(*Integer); iIsInt { - indexVal, indexOk := validateIndex(indices[currDim], len(expr.Parts)) + if _, iIsInt := indices[currDim].(*atoms.Integer); iIsInt { + indexVal, indexOk := validateIndex(indices[currDim], len(expr.GetParts())) if !indexOk { return nil, false } - return applyIndex(expr.Parts[indexVal], indices, currDim+1) + return applyIndex(expr.GetParts()[indexVal], indices, currDim+1) } // Range selections rangeMin, rangeMax, rangeOk := int64(0), int64(0), false - if iSpan, iIsSpan := HeadAssertion(indices[currDim], "System`Span"); iIsSpan { - if len(iSpan.Parts) != 3 { + if iSpan, iIsSpan := atoms.HeadAssertion(indices[currDim], "System`Span"); iIsSpan { + if len(iSpan.GetParts()) != 3 { return nil, false } - start, startOk := validateIndex(iSpan.Parts[1], len(expr.Parts)+1) - end, endOk := validateIndex(iSpan.Parts[2], len(expr.Parts)) - if endSym, endIsSym := iSpan.Parts[2].(*Symbol); endIsSym { + start, startOk := validateIndex(iSpan.GetParts()[1], len(expr.GetParts())+1) + end, endOk := validateIndex(iSpan.GetParts()[2], len(expr.GetParts())) + if endSym, endIsSym := iSpan.GetParts()[2].(*atoms.Symbol); endIsSym { if endSym.Name == "System`All" { - end, endOk = int64(len(expr.Parts)-1), true + end, endOk = int64(len(expr.GetParts())-1), true } } if !startOk || !endOk { @@ -118,32 +128,32 @@ func applyIndex(ex Ex, indices []Ex, currDim int) (Ex, bool) { } rangeMin, rangeMax, rangeOk = start, end, true } - iSym, iIsSym := indices[currDim].(*Symbol) + iSym, iIsSym := indices[currDim].(*atoms.Symbol) if iIsSym { if iSym.Name == "System`All" { - rangeMin, rangeMax, rangeOk = 1, int64(len(expr.Parts)-1), true + rangeMin, rangeMax, rangeOk = 1, int64(len(expr.GetParts())-1), true } } if rangeOk { - toReturn := E(expr.Parts[0]) + toReturn := atoms.E(expr.GetParts()[0]) for i := rangeMin; i <= rangeMax; i++ { - applied, appOk := applyIndex(expr.Parts[i], indices, currDim+1) + applied, appOk := applyIndex(expr.GetParts()[i], indices, currDim+1) if !appOk { return nil, false } - toReturn.appendEx(applied) + toReturn.AppendEx(applied) } return toReturn, true } return nil, false } -func ThreadExpr(expr *Expression) (*Expression, bool) { +func threadExpr(expr expreduceapi.ExpressionInterface) (expreduceapi.ExpressionInterface, bool) { lengths := []int{} - for i := 1; i < len(expr.Parts); i++ { - list, isList := HeadAssertion(expr.Parts[i], "System`List") + for i := 1; i < len(expr.GetParts()); i++ { + list, isList := atoms.HeadAssertion(expr.GetParts()[i], "System`List") if isList { - lengths = append(lengths, len(list.Parts)-1) + lengths = append(lengths, len(list.GetParts())-1) } } if len(lengths) == 0 { @@ -157,33 +167,33 @@ func ThreadExpr(expr *Expression) (*Expression, bool) { return expr, false } listLen := lengths[0] - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for listI := 0; listI < listLen; listI++ { - thisExpr := NewExpression([]Ex{expr.Parts[0].DeepCopy()}) - for i := 1; i < len(expr.Parts); i++ { - list, isList := HeadAssertion(expr.Parts[i], "System`List") + thisExpr := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0].DeepCopy()}) + for i := 1; i < len(expr.GetParts()); i++ { + list, isList := atoms.HeadAssertion(expr.GetParts()[i], "System`List") if isList { - thisExpr.Parts = append(thisExpr.Parts, list.Parts[listI+1]) + thisExpr.AppendEx(list.GetParts()[listI+1]) } else { - thisExpr.Parts = append(thisExpr.Parts, expr.Parts[i]) + thisExpr.AppendEx(expr.GetParts()[i]) } } - toReturn.Parts = append(toReturn.Parts, thisExpr) + toReturn.AppendEx(thisExpr) } return toReturn, true } -func countFunctionLevelSpec(pattern Ex, e Ex, partList []int64, generated *int64, es *EvalState) Ex { - if isMatch, _ := IsMatchQ(e, pattern, EmptyPD(), es); isMatch { +func countFunctionLevelSpec(pattern expreduceapi.Ex, e expreduceapi.Ex, partList []int64, generated *int64, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if isMatch, _ := matcher.IsMatchQ(e, pattern, matcher.EmptyPD(), es); isMatch { *generated++ } return e } -func GetListDefinitions() (defs []Definition) { +func getListDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "List", - toString: (*Expression).ToStringList, + toString: toStringList, }) defs = append(defs, Definition{ Name: "Total", @@ -193,22 +203,19 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Table", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) >= 3 { - mis, isOk := multiIterSpecFromLists(es, this.Parts[2:]) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) >= 3 { + mis, isOk := iterspec.MultiSpecFromLists(es, this.GetParts()[2:]) if isOk { // Simulate evaluation within Block[] - mis.takeVarSnapshot(es) - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) - for mis.cont() { - mis.defineCurrent(es) - // TODO: use ReplacePD for this. We're only replacing - // symbols. Don't need a full Eval. - toReturn.Parts = append(toReturn.Parts, this.Parts[1].DeepCopy().Eval(es)) - es.Debugf("%v\n", toReturn) - mis.next() + mis.TakeVarSnapshot(es) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + for mis.Cont() { + mis.DefineCurrent(es) + toReturn.AppendEx(es.Eval(this.GetPart(1).DeepCopy())) + mis.Next() } - mis.restoreVarSnapshot(es) + mis.RestoreVarSnapshot(es) return toReturn } } @@ -217,23 +224,22 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "ParallelTable", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) >= 3 { - mis, isOk := multiIterSpecFromLists(es, this.Parts[2:]) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) >= 3 { + mis, isOk := iterspec.MultiSpecFromLists(es, this.GetParts()[2:]) if isOk { // Simulate evaluation within Block[] - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) - for mis.cont() { - toReturn.Parts = append(toReturn.Parts, ReplacePD(this.Parts[1].DeepCopy(), es, mis.currentPDManager())) - es.Debugf("%v\n", toReturn) - mis.next() + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + for mis.Cont() { + toReturn.AppendEx(matcher.ReplacePD(this.GetParts()[1].DeepCopy(), es, mis.CurrentPDManager())) + mis.Next() } var wg sync.WaitGroup - for i := 1; i < len(toReturn.Parts); i++ { + for i := 1; i < len(toReturn.GetParts()); i++ { wg.Add(1) - go func (idx int) { + go func(idx int) { defer wg.Done() - toReturn.Parts[idx] = toReturn.Parts[idx].Eval(es) + toReturn.GetParts()[idx] = es.Eval(toReturn.GetParts()[idx]) }(i) } wg.Wait() @@ -245,45 +251,45 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "MemberQ", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - if MemberQ(expr.Parts[1:], this.Parts[2], es) { - return NewSymbol("System`True") + if memberQ(expr.GetParts()[1:], this.GetParts()[2], es) { + return atoms.NewSymbol("System`True") } } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "Cases", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) - pattern := this.Parts[2] - rule, isRule := HeadAssertion(this.Parts[2], "System`Rule") + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + pattern := this.GetParts()[2] + rule, isRule := atoms.HeadAssertion(this.GetParts()[2], "System`Rule") if isRule { - if len(rule.Parts) != 3 { + if len(rule.GetParts()) != 3 { return toReturn } - pattern = rule.Parts[1] + pattern = rule.GetParts()[1] } - for i := 1; i < len(expr.Parts); i++ { - if matchq, pd := IsMatchQ(expr.Parts[i], pattern, EmptyPD(), es); matchq { - toAdd := expr.Parts[i] + for i := 1; i < len(expr.GetParts()); i++ { + if matchq, pd := matcher.IsMatchQ(expr.GetParts()[i], pattern, matcher.EmptyPD(), es); matchq { + toAdd := expr.GetParts()[i] if isRule { - toAdd = ReplacePD(rule.Parts[2], es, pd) + toAdd = matcher.ReplacePD(rule.GetParts()[2], es, pd) } - toReturn.Parts = append(toReturn.Parts, toAdd) + toReturn.AppendEx(toAdd) } } @@ -294,19 +300,19 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "DeleteCases", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - toReturn := NewExpression([]Ex{expr.Parts[0]}) - pattern := this.Parts[2] - for i := 1; i < len(expr.Parts); i++ { - if matchq, _ := IsMatchQ(expr.Parts[i], pattern, EmptyPD(), es); !matchq { - toAdd := expr.Parts[i] - toReturn.Parts = append(toReturn.Parts, toAdd) + toReturn := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) + pattern := this.GetParts()[2] + for i := 1; i < len(expr.GetParts()); i++ { + if matchq, _ := matcher.IsMatchQ(expr.GetParts()[i], pattern, matcher.EmptyPD(), es); !matchq { + toAdd := expr.GetParts()[i] + toReturn.AppendEx(toAdd) } } @@ -317,32 +323,32 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Union", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) == 1 { - return NewExpression([]Ex{NewSymbol("System`List")}) - } - var firstHead Ex = nil - var allParts *Expression = nil - for _, part := range this.Parts[1:] { - expr, isExpr := part.(*Expression) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) == 1 { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + } + var firstHead expreduceapi.Ex + var allParts expreduceapi.ExpressionInterface + for _, part := range this.GetParts()[1:] { + expr, isExpr := part.(expreduceapi.ExpressionInterface) if !isExpr { return this } if firstHead == nil { - firstHead = expr.Parts[0] - allParts = NewExpression([]Ex{firstHead}) - } else if !IsSameQ(firstHead, expr.Parts[0], &es.CASLogger) { + firstHead = expr.GetParts()[0] + allParts = atoms.NewExpression([]expreduceapi.Ex{firstHead}) + } else if !atoms.IsSameQ(firstHead, expr.GetParts()[0]) { return this } - allParts.Parts = append(allParts.Parts, expr.Parts[1:]...) + allParts.AppendExArray(expr.GetParts()[1:]) } sort.Sort(allParts) - toReturn := NewExpression([]Ex{firstHead}) - var lastEx Ex = nil - for _, part := range allParts.Parts[1:] { - if lastEx == nil || !IsSameQ(lastEx, part, &es.CASLogger) { + toReturn := atoms.NewExpression([]expreduceapi.Ex{firstHead}) + var lastEx expreduceapi.Ex + for _, part := range allParts.GetParts()[1:] { + if lastEx == nil || !atoms.IsSameQ(lastEx, part) { lastEx = part - toReturn.Parts = append(toReturn.Parts, part) + toReturn.AppendEx(part) } } @@ -351,36 +357,36 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Complement", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) == 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) == 1 { return this } - var firstHead Ex = nil + var firstHead expreduceapi.Ex exclusions := map[uint64]bool{} - for _, part := range this.Parts[1:] { - expr, isExpr := part.(*Expression) + for _, part := range this.GetParts()[1:] { + expr, isExpr := part.(expreduceapi.ExpressionInterface) if !isExpr { return this } if firstHead == nil { - firstHead = expr.Parts[0] + firstHead = expr.GetParts()[0] continue - } else if !IsSameQ(firstHead, expr.Parts[0], &es.CASLogger) { + } else if !atoms.IsSameQ(firstHead, expr.GetParts()[0]) { return this } - for _, excludedPart := range expr.Parts[1:] { + for _, excludedPart := range expr.GetParts()[1:] { exclusions[hashEx(excludedPart)] = true } } - toReturn := NewExpression([]Ex{firstHead}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{firstHead}) added := map[uint64]bool{} - for _, part := range this.Parts[1].(*Expression).Parts[1:] { + for _, part := range this.GetParts()[1].(expreduceapi.ExpressionInterface).GetParts()[1:] { hash := hashEx(part) _, alreadyAdded := added[hash] _, excluded := exclusions[hash] if !excluded && !alreadyAdded { added[hash] = true - toReturn.Parts = append(toReturn.Parts, part) + toReturn.AppendEx(part) } } sort.Sort(toReturn) @@ -389,17 +395,17 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "PadRight", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - list, n, x, valid := ValidatePadParams(this) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + list, n, x, valid := validatePadParams(this) if !valid { return this } - toReturn := NewExpression([]Ex{list.Parts[0]}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{list.GetParts()[0]}) for i := int64(0); i < n; i++ { - if i >= int64(len(list.Parts)-1) { - toReturn.Parts = append(toReturn.Parts, x) + if i >= int64(len(list.GetParts())-1) { + toReturn.AppendEx(x) } else { - toReturn.Parts = append(toReturn.Parts, list.Parts[i+1]) + toReturn.AppendEx(list.GetParts()[i+1]) } } return toReturn @@ -407,18 +413,18 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "PadLeft", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - list, n, x, valid := ValidatePadParams(this) + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + list, n, x, valid := validatePadParams(this) if !valid { return this } - toReturn := NewExpression([]Ex{list.Parts[0]}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{list.GetParts()[0]}) for i := int64(0); i < n; i++ { - if i < n-int64(len(list.Parts))+1 { - toReturn.Parts = append(toReturn.Parts, x) + if i < n-int64(len(list.GetParts()))+1 { + toReturn.AppendEx(x) } else { - listI := int64(len(list.Parts)) - (n - i) - toReturn.Parts = append(toReturn.Parts, list.Parts[listI]) + listI := int64(len(list.GetParts())) - (n - i) + toReturn.AppendEx(list.GetParts()[listI]) } } return toReturn @@ -426,30 +432,30 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Range", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // I should probably refactor the IterSpec system so that it does not // require being passed a list and a variable of iteration. TODO - iterSpecList := NewExpression([]Ex{NewSymbol("System`List"), NewSymbol("System`$DUMMY")}) - iterSpecList.Parts = append(iterSpecList.Parts, this.Parts[1:]...) - is, isOk := iterSpecFromList(es, iterSpecList) + iterSpecList := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List"), atoms.NewSymbol("System`$DUMMY")}) + iterSpecList.AppendExArray(this.GetParts()[1:]) + is, isOk := iterspec.SpecFromList(es, iterSpecList) if !isOk { return this } - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) - for is.cont() { - toReturn.Parts = append(toReturn.Parts, is.getCurr()) - is.next() + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + for is.Cont() { + toReturn.AppendEx(is.GetCurr()) + is.Next() } return toReturn }, }) defs = append(defs, Definition{ Name: "Part", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) == 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) == 1 { return this } - applied, ok := applyIndex(this.Parts[1], this.Parts[2:], 0) + applied, ok := applyIndex(this.GetParts()[1], this.GetParts()[2:], 0) if !ok { return this } @@ -460,30 +466,30 @@ func GetListDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "All"}) defs = append(defs, Definition{ Name: "Thread", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { - return this.Parts[1] + return this.GetParts()[1] } - newExpr, _ := ThreadExpr(expr) + newExpr, _ := threadExpr(expr) return newExpr }, }) defs = append(defs, Definition{ Name: "Append", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { return this } - res := NewExpression(append([]Ex{}, expr.Parts...)) - res.Parts = append(res.Parts, this.Parts[2]) + res := atoms.NewExpression(append([]expreduceapi.Ex{}, expr.GetParts()...)) + res.AppendEx(this.GetParts()[2]) return res }, }) @@ -492,17 +498,17 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Prepend", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { return this } - res := NewExpression([]Ex{expr.Parts[0]}) - res.Parts = append(res.Parts, this.Parts[2]) - res.Parts = append(res.Parts, expr.Parts[1:]...) + res := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) + res.AppendEx(this.GetParts()[2]) + res.AppendExArray(expr.GetParts()[1:]) return res }, }) @@ -511,21 +517,21 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "DeleteDuplicates", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - toReturn := NewExpression([]Ex{expr.Parts[0]}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) seen := map[uint64]bool{} - for _, orig := range expr.Parts[1:] { + for _, orig := range expr.GetParts()[1:] { hash := hashEx(orig) _, isDupe := seen[hash] if !isDupe { seen[hash] = true - toReturn.Parts = append(toReturn.Parts, orig) + toReturn.AppendEx(orig) } } return toReturn @@ -535,10 +541,10 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Select", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - maxN := MaxInt64 - if len(this.Parts) == 4 { - if asInt, isInt := this.Parts[3].(*Integer); isInt { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + maxN := maxInt64 + if len(this.GetParts()) == 4 { + if asInt, isInt := this.GetParts()[3].(*atoms.Integer); isInt { maxN = asInt.Val.Int64() if maxN < 0 { return this @@ -546,27 +552,30 @@ func GetListDefinitions() (defs []Definition) { } else { return this } - } else if len(this.Parts) != 3 { + } else if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if isExpr { - res := NewExpression([]Ex{expr.Parts[0]}) + res := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) added := int64(0) - for _, part := range expr.Parts[1:] { + for _, part := range expr.GetParts()[1:] { if added >= maxN { break } - pass := (NewExpression([]Ex{ - this.Parts[2], - part, - })).Eval(es) - passSymbol, passIsSymbol := pass.(*Symbol) + pass := + + es.Eval((atoms.NewExpression([]expreduceapi.Ex{ + this.GetParts()[2], + part, + }))) + + passSymbol, passIsSymbol := pass.(*atoms.Symbol) if passIsSymbol { if passSymbol.Name == "System`True" { - res.Parts = append(res.Parts, part) - added += 1 + res.AppendEx(part) + added++ } } } @@ -577,53 +586,56 @@ func GetListDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Scan", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[2].(*Expression) + expr, isExpr := this.GetParts()[2].(expreduceapi.ExpressionInterface) if !isExpr { return this } - for _, part := range expr.Parts[1:] { - res := (NewExpression([]Ex{ - this.Parts[1], - part, - })).Eval(es) + for _, part := range expr.GetParts()[1:] { + res := + + es.Eval((atoms.NewExpression([]expreduceapi.Ex{ + this.GetParts()[1], + part, + }))) + if es.HasThrown() { - return es.thrown + return es.Thrown() } - if asReturn, isReturn := HeadAssertion(res, "System`Return"); isReturn { - if len(asReturn.Parts) < 2 { - return NewSymbol("System`Null") + if asReturn, isReturn := atoms.HeadAssertion(res, "System`Return"); isReturn { + if len(asReturn.GetParts()) < 2 { + return atoms.NewSymbol("System`Null") } - return asReturn.Parts[1] + return asReturn.GetParts()[1] } } - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") }, }) defs = append(defs, Definition{ Name: "Join", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) <= 1 { - return NewHead("System`List") + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) <= 1 { + return atoms.NewHead("System`List") } - res := NewEmptyExpression() - for _, part := range this.Parts[1:] { - expr, isExpr := part.(*Expression) + res := atoms.NewEmptyExpression() + for _, part := range this.GetParts()[1:] { + expr, isExpr := part.(expreduceapi.ExpressionInterface) if !isExpr { return this } - if len(res.Parts) == 0 { - res.appendExArray(expr.Parts) + if len(res.GetParts()) == 0 { + res.AppendExArray(expr.GetParts()) } else { - if !IsSameQ(expr.Parts[0], res.Parts[0], &es.CASLogger) { + if !atoms.IsSameQ(expr.GetParts()[0], res.GetParts()[0]) { return this } - res.appendExArray(expr.Parts[1:]) + res.AppendExArray(expr.GetParts()[1:]) } } return res @@ -646,17 +658,17 @@ func GetListDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "ConstantArray"}) defs = append(defs, Definition{ Name: "Reverse", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { return this } - res := NewExpression([]Ex{expr.Parts[0]}) - for i := len(expr.Parts)-1; i > 0; i-- { - res.Parts = append(res.Parts, expr.Parts[i]) + res := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) + for i := len(expr.GetParts()) - 1; i > 0; i-- { + res.AppendEx(expr.GetParts()[i]) } return res }, diff --git a/expreduce/builtin_manip.go b/expreduce/builtin_manip.go index 47eb5bc..c499e3c 100644 --- a/expreduce/builtin_manip.go +++ b/expreduce/builtin_manip.go @@ -1,32 +1,37 @@ package expreduce -func distribute(e *Expression, built *Expression, res *Expression) { - i := len(built.Parts) - if i >= len(e.Parts) { - res.Parts = append(res.Parts, built) +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func distribute(e expreduceapi.ExpressionInterface, built expreduceapi.ExpressionInterface, res expreduceapi.ExpressionInterface) { + i := len(built.GetParts()) + if i >= len(e.GetParts()) { + res.AppendEx(built) return } shouldDistribute := false - partAsExpr, partIsExpr := e.Parts[i].(*Expression) + partAsExpr, partIsExpr := e.GetParts()[i].(expreduceapi.ExpressionInterface) if partIsExpr { - if hashEx(partAsExpr.Parts[0]) == hashEx(res.Parts[0]) { + if hashEx(partAsExpr.GetParts()[0]) == hashEx(res.GetParts()[0]) { shouldDistribute = true } } if shouldDistribute { - for _, dPart := range partAsExpr.Parts[1:] { - builtCopy := built.ShallowCopy() - builtCopy.appendEx(dPart) + for _, dPart := range partAsExpr.GetParts()[1:] { + builtCopy := atoms.ShallowCopy(built) + builtCopy.AppendEx(dPart) distribute(e, builtCopy, res) } return } - built.Parts = append(built.Parts, e.Parts[i]) + built.AppendEx(e.GetParts()[i]) distribute(e, built, res) return } -func GetManipDefinitions() (defs []Definition) { +func getManipDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Together"}) defs = append(defs, Definition{Name: "Numerator"}) defs = append(defs, Definition{Name: "Denominator"}) @@ -37,17 +42,17 @@ func GetManipDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Distribute", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { - return this.Parts[1] + return this.GetParts()[1] } - res := NewExpression([]Ex{this.Parts[2]}) - firstBuilt := NewExpression([]Ex{expr.Parts[0]}) + res := atoms.NewExpression([]expreduceapi.Ex{this.GetParts()[2]}) + firstBuilt := atoms.NewExpression([]expreduceapi.Ex{expr.GetParts()[0]}) distribute(expr, firstBuilt, res) return res }, diff --git a/expreduce/builtin_matrix.go b/expreduce/builtin_matrix.go index d56559b..d4a40f9 100644 --- a/expreduce/builtin_matrix.go +++ b/expreduce/builtin_matrix.go @@ -1,77 +1,81 @@ package expreduce -import "math/big" +import ( + "math/big" -func dimensions(ex *Expression, level int, cl *CASLogger) []int64 { - head := ex.Parts[0] - dims := []int64{int64(len(ex.Parts) - 1)} + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func dimensions(ex expreduceapi.ExpressionInterface, level int, cl expreduceapi.LoggingInterface) []int64 { + head := ex.GetParts()[0] + dims := []int64{int64(len(ex.GetParts()) - 1)} nextDims := []int64{} - for i := 1; i < len(ex.Parts); i++ { - subHead, isSubHead := headExAssertion(ex.Parts[i], head, cl) + for i := 1; i < len(ex.GetParts()); i++ { + subHead, isSubHead := atoms.HeadExAssertion(ex.GetParts()[i], head, cl) if !isSubHead { return dims - } else { - currDims := dimensions(subHead, level+1, cl) - if i != 1 { - if len(nextDims) > len(currDims) { - nextDims = nextDims[:len(currDims)-1] - } - for i := range nextDims { - if nextDims[i] != currDims[i] { - return dims - } + } + currDims := dimensions(subHead, level+1, cl) + if i != 1 { + if len(nextDims) > len(currDims) { + nextDims = nextDims[:len(currDims)-1] + } + for i := range nextDims { + if nextDims[i] != currDims[i] { + return dims } } - nextDims = currDims } + nextDims = currDims } return append(dims, nextDims...) } -func intSliceToList(ints []int64) Ex { - toReturn := NewExpression([]Ex{ - NewSymbol("System`List"), +func intSliceToList(ints []int64) expreduceapi.Ex { + toReturn := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), }) for _, i := range ints { - toReturn.Parts = append(toReturn.Parts, NewInteger(big.NewInt(i))) + toReturn.AppendEx(atoms.NewInteger(big.NewInt(i))) } return toReturn } // This function assumes that mat is a matrix and that i and j are not out of // bounds. i and j are 1-indexed. -func (mat *Expression) matrix2dGetElem(i, j int64) Ex { - return (mat.Parts[i].(*Expression)).Parts[j] +func matrix2dGetElem(mat expreduceapi.ExpressionInterface, i, j int64) expreduceapi.Ex { + return (mat.GetParts()[i].(expreduceapi.ExpressionInterface)).GetParts()[j] } -func calcIJ(i, j, innerDim int64, a, b *Expression) Ex { - toReturn := NewExpression([]Ex{NewSymbol("System`Plus")}) +func calcIJ(i, j, innerDim int64, a, b expreduceapi.ExpressionInterface) expreduceapi.Ex { + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Plus")}) for pairI := int64(1); pairI <= innerDim; pairI++ { - toAdd := NewExpression([]Ex{NewSymbol("System`Times")}) - toAdd.appendEx(a.matrix2dGetElem(i, pairI)) - toAdd.appendEx(b.matrix2dGetElem(pairI, j)) - toReturn.appendEx(toAdd) + toAdd := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Times")}) + toAdd.AppendEx(matrix2dGetElem(a, i, pairI)) + toAdd.AppendEx(matrix2dGetElem(b, pairI, j)) + toReturn.AppendEx(toAdd) } return toReturn } -func GetMatrixDefinitions() (defs []Definition) { +func getMatrixDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Inverse", Details: "The row-reduce method has not been added yet, but the shortcuts to finding the inverses of matrices up to 3x3 have been added.", }) defs = append(defs, Definition{ Name: "Dimensions", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - expr, isExpr := this.Parts[1].(*Expression) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if !isExpr { - return NewExpression([]Ex{NewSymbol("System`List")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) } - return intSliceToList(dimensions(expr, 0, &es.CASLogger)) + return intSliceToList(dimensions(expr, 0, es.GetLogger())) }, }) defs = append(defs, Definition{ @@ -84,39 +88,39 @@ func GetMatrixDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Dot", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) == 2 { - return this.Parts[1] + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) == 2 { + return this.GetParts()[1] } - if len(this.Parts) != 3 { + if len(this.GetParts()) != 3 { return this } - aIsVector := vectorQ(this.Parts[1]) - bIsVector := vectorQ(this.Parts[2]) + aIsVector := vectorQ(this.GetParts()[1]) + bIsVector := vectorQ(this.GetParts()[2]) if aIsVector && bIsVector { - aVector := this.Parts[1].(*Expression) - bVector := this.Parts[2].(*Expression) - if len(aVector.Parts) != len(bVector.Parts) { + aVector := this.GetParts()[1].(expreduceapi.ExpressionInterface) + bVector := this.GetParts()[2].(expreduceapi.ExpressionInterface) + if len(aVector.GetParts()) != len(bVector.GetParts()) { return this } - vecLen := len(aVector.Parts) - 1 - toReturn := NewExpression([]Ex{NewSymbol("System`Plus")}) + vecLen := len(aVector.GetParts()) - 1 + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Plus")}) for i := 0; i < vecLen; i++ { - toReturn.appendEx(NewExpression([]Ex{ - NewSymbol("System`Times"), - aVector.Parts[i+1], - bVector.Parts[i+1], + toReturn.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + aVector.GetParts()[i+1], + bVector.GetParts()[i+1], })) } return toReturn } - aIsMatrix := matrixQ(this.Parts[1], &es.CASLogger) - bIsMatrix := matrixQ(this.Parts[2], &es.CASLogger) + aIsMatrix := matrixQ(this.GetParts()[1], es.GetLogger()) + bIsMatrix := matrixQ(this.GetParts()[2], es.GetLogger()) if aIsMatrix && bIsMatrix { - aEx := this.Parts[1].(*Expression) - bEx := this.Parts[2].(*Expression) - aDims := dimensions(aEx, 0, &es.CASLogger) - bDims := dimensions(bEx, 0, &es.CASLogger) + aEx := this.GetParts()[1].(expreduceapi.ExpressionInterface) + bEx := this.GetParts()[2].(expreduceapi.ExpressionInterface) + aDims := dimensions(aEx, 0, es.GetLogger()) + bDims := dimensions(bEx, 0, es.GetLogger()) if len(aDims) != 2 || len(bDims) != 2 { return this } @@ -125,14 +129,14 @@ func GetMatrixDefinitions() (defs []Definition) { if aW != bH { return this } - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for i := int64(1); i <= aH; i++ { - row := NewExpression([]Ex{NewSymbol("System`List")}) + row := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for j := int64(1); j <= bW; j++ { //row.appendEx(&Integer{big.NewInt(0)}) - row.appendEx(calcIJ(i, j, aW, aEx, bEx)) + row.AppendEx(calcIJ(i, j, aW, aEx, bEx)) } - toReturn.appendEx(row) + toReturn.AppendEx(row) } return toReturn } @@ -141,26 +145,26 @@ func GetMatrixDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Transpose", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - l, isL := HeadAssertion(this.Parts[1], "System`List") + l, isL := atoms.HeadAssertion(this.GetParts()[1], "System`List") if !isL { return this } - dims := dimensions(l, 0, &es.CASLogger) + dims := dimensions(l, 0, es.GetLogger()) if len(dims) < 2 { return this } h, w := dims[0], dims[1] - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for tI := int64(1); tI <= w; tI++ { - tRow := NewExpression([]Ex{NewSymbol("System`List")}) + tRow := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) for tJ := int64(1); tJ <= h; tJ++ { - tRow.appendEx(l.matrix2dGetElem(tJ, tI)) + tRow.AppendEx(matrix2dGetElem(l, tJ, tI)) } - toReturn.appendEx(tRow) + toReturn.AppendEx(tRow) } return toReturn }, diff --git a/expreduce/builtin_numbertheory.go b/expreduce/builtin_numbertheory.go index 04fafad..6107075 100644 --- a/expreduce/builtin_numbertheory.go +++ b/expreduce/builtin_numbertheory.go @@ -1,8 +1,11 @@ package expreduce import ( - "github.com/kavehmz/prime" "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/kavehmz/prime" ) // Compute the prime factors of a positive n. @@ -33,8 +36,9 @@ func primeFactors(origN *big.Int) (factors []*big.Int) { type factorTally struct { factor *big.Int - power uint64 + power uint64 } + func primeFactorsTallied(n *big.Int) (factorTallies []factorTally) { factors := primeFactors(n) for _, factor := range factors { @@ -49,25 +53,25 @@ func primeFactorsTallied(n *big.Int) (factorTallies []factorTally) { if !added { factorTallies = append(factorTallies, factorTally{ factor: factor, - power: 1, + power: 1, }) } } return } -func GetNumberTheoryDefinitions() (defs []Definition) { +func getNumberTheoryDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "PrimeQ", legacyEvalFn: singleParamQEval(primeQ), }) defs = append(defs, Definition{ Name: "GCD", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { zero := big.NewInt(0) var ints [](*big.Int) - for i := 1; i < len(this.Parts); i++ { - asInt, isInt := this.Parts[i].(*Integer) + for i := 1; i < len(this.GetParts()); i++ { + asInt, isInt := this.GetParts()[i].(*atoms.Integer) if !isInt { return this } @@ -84,49 +88,49 @@ func GetNumberTheoryDefinitions() (defs []Definition) { } } if len(ints) == 0 { - return NewInteger(zero) + return atoms.NewInteger(zero) } gcd := ints[0] for i := 1; i < len(ints); i++ { gcd.GCD(nil, nil, gcd, ints[i]) } - return NewInteger(gcd) + return atoms.NewInteger(gcd) }, }) defs = append(defs, Definition{Name: "LCM"}) defs = append(defs, Definition{ Name: "Mod", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - xi, xIsInt := this.Parts[1].(*Integer) - yi, yIsInt := this.Parts[2].(*Integer) + xi, xIsInt := this.GetParts()[1].(*atoms.Integer) + yi, yIsInt := this.GetParts()[2].(*atoms.Integer) if !xIsInt || !yIsInt { return this } if yi.Val.Cmp(big.NewInt(0)) == 0 { - return NewSymbol("System`Indeterminate") + return atoms.NewSymbol("System`Indeterminate") } m := big.NewInt(0) m.Mod(xi.Val, yi.Val) - return NewInteger(m) + return atoms.NewInteger(m) }, }) defs = append(defs, Definition{ Name: "PrimePi", Usage: "`PrimePi[n]` returns the number of primes less than or equal to `n`.", Attributes: []string{"Listable"}, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } n := int64(0) - asInt, isInt := this.Parts[1].(*Integer) + asInt, isInt := this.GetParts()[1].(*atoms.Integer) if isInt { n = asInt.Val.Int64() } - asFlt, isFlt := this.Parts[1].(*Flt) + asFlt, isFlt := this.GetParts()[1].(*atoms.Flt) if isFlt { n, _ = asFlt.Val.Int64() } @@ -134,14 +138,14 @@ func GetNumberTheoryDefinitions() (defs []Definition) { return this } if n <= 0 { - return NewInteger(big.NewInt(0)) + return atoms.NewInteger(big.NewInt(0)) } if n == 1 { - return NewInteger(big.NewInt(1)) + return atoms.NewInteger(big.NewInt(1)) } // A very inefficient implementation p := prime.Primes(uint64(n)) - return NewInteger(big.NewInt(int64(len(p)))) + return atoms.NewInteger(big.NewInt(int64(len(p)))) }, SimpleExamples: []TestInstruction{ &SameTest{"4", "PrimePi[7]"}, diff --git a/expreduce/builtin_pattern.go b/expreduce/builtin_pattern.go index 4617c1b..23b5f3b 100644 --- a/expreduce/builtin_pattern.go +++ b/expreduce/builtin_pattern.go @@ -1,9 +1,15 @@ package expreduce -import "bytes" +import ( + "bytes" -func ToStringBlankType(repr string, parts []Ex, params ToStringParams) (bool, string) { - if params.form == "FullForm" { + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func toStringBlankType(repr string, parts []expreduceapi.Ex, params expreduceapi.ToStringParams) (bool, string) { + if params.Form == "FullForm" { return false, "" } if len(parts) == 1 { @@ -11,48 +17,47 @@ func ToStringBlankType(repr string, parts []Ex, params ToStringParams) (bool, st } else if len(parts) == 2 { var buffer bytes.Buffer buffer.WriteString(repr) - buffer.WriteString(parts[1].String(params.es)) + buffer.WriteString(parts[1].StringForm(params)) return true, buffer.String() } return false, "" } -func GetPatternDefinitions() (defs []Definition) { +func getPatternDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "MatchQ", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - if res, _ := IsMatchQ(this.Parts[1], this.Parts[2], EmptyPD(), es); res { - return NewSymbol("System`True") - } else { - return NewSymbol("System`False") + if res, _ := matcher.IsMatchQ(this.GetParts()[1], this.GetParts()[2], matcher.EmptyPD(), es); res { + return atoms.NewSymbol("System`True") } + return atoms.NewSymbol("System`False") }, }) defs = append(defs, Definition{ Name: "Pattern", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - if params.form != "InputForm" && params.form != "OutputForm" { + if params.Form != "InputForm" && params.Form != "OutputForm" { return false, "" } var buffer bytes.Buffer - _, blankOk := HeadAssertion(this.Parts[2], "System`Blank") - _, bsOk := HeadAssertion(this.Parts[2], "System`BlankSequence") - _, bnsOk := HeadAssertion(this.Parts[2], "System`BlankNullSequence") + _, blankOk := atoms.HeadAssertion(this.GetParts()[2], "System`Blank") + _, bsOk := atoms.HeadAssertion(this.GetParts()[2], "System`BlankSequence") + _, bnsOk := atoms.HeadAssertion(this.GetParts()[2], "System`BlankNullSequence") if blankOk || bsOk || bnsOk { - buffer.WriteString(this.Parts[1].StringForm(params)) - buffer.WriteString(this.Parts[2].StringForm(params)) + buffer.WriteString(this.GetParts()[1].StringForm(params)) + buffer.WriteString(this.GetParts()[2].StringForm(params)) } else { buffer.WriteString("(") - buffer.WriteString(this.Parts[1].StringForm(params)) + buffer.WriteString(this.GetParts()[1].StringForm(params)) buffer.WriteString(") : (") - buffer.WriteString(this.Parts[2].StringForm(params)) + buffer.WriteString(this.GetParts()[2].StringForm(params)) buffer.WriteString(")") } return true, buffer.String() @@ -60,20 +65,20 @@ func GetPatternDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Blank", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringBlankType("_", this.Parts, params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringBlankType("_", this.GetParts(), params) }, }) defs = append(defs, Definition{ Name: "BlankSequence", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringBlankType("__", this.Parts, params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringBlankType("__", this.GetParts(), params) }, }) defs = append(defs, Definition{ Name: "BlankNullSequence", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringBlankType("___", this.Parts, params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringBlankType("___", this.GetParts(), params) }, }) defs = append(defs, Definition{ @@ -93,22 +98,22 @@ func GetPatternDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "ReplaceList", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - rule, isRule := HeadAssertion(this.Parts[2], "System`Rule") + rule, isRule := atoms.HeadAssertion(this.GetParts()[2], "System`Rule") if !isRule { return this } - res := NewExpression([]Ex{NewSymbol("System`List")}) - mi, cont := NewMatchIter(this.Parts[1], rule.Parts[1], EmptyPD(), es) + res := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + mi, cont := matcher.NewMatchIter(this.GetParts()[1], rule.GetParts()[1], matcher.EmptyPD(), es) for cont { - matchq, newPd, done := mi.next() + matchq, newPd, done := mi.Next() cont = !done if matchq { - res.appendEx(ReplacePD(rule.Parts[2], es, newPd)) + res.AppendEx(matcher.ReplacePD(rule.GetParts()[2], es, newPd)) } } return res @@ -117,15 +122,15 @@ func GetPatternDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Repeated"}) defs = append(defs, Definition{ Name: "Optional", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 2 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 2 { return false, "" } - if params.form != "InputForm" && params.form != "OutputForm" { + if params.Form != "InputForm" && params.Form != "OutputForm" { return false, "" } var buffer bytes.Buffer - buffer.WriteString(this.Parts[1].StringForm(params)) + buffer.WriteString(this.GetParts()[1].StringForm(params)) buffer.WriteString(".") return true, buffer.String() }, diff --git a/expreduce/builtin_plot.go b/expreduce/builtin_plot.go index 3fd6174..b73e5fe 100644 --- a/expreduce/builtin_plot.go +++ b/expreduce/builtin_plot.go @@ -1,6 +1,6 @@ package expreduce -func GetPlotDefinitions() (defs []Definition) { +func getPlotDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Plot"}) return } diff --git a/expreduce/builtin_power.go b/expreduce/builtin_power.go index 47b84cc..f84944a 100644 --- a/expreduce/builtin_power.go +++ b/expreduce/builtin_power.go @@ -1,28 +1,33 @@ package expreduce import ( - "github.com/corywalker/mathbigext" + "fmt" + "math" "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/corywalker/mathbigext" ) -func bigMathFnOneParam(fn func(*big.Float) *big.Float, onlyPos bool) func(*Expression, *EvalState) Ex { - return (func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { +func bigMathFnOneParam(fn func(*big.Float) *big.Float, onlyPos bool) func(expreduceapi.ExpressionInterface, expreduceapi.EvalStateInterface) expreduceapi.Ex { + return (func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - flt, ok := this.Parts[1].(*Flt) + flt, ok := this.GetParts()[1].(*atoms.Flt) if ok { if !onlyPos || flt.Val.Cmp(big.NewFloat(0)) == 1 { - return NewReal(fn(flt.Val)) + return atoms.NewReal(fn(flt.Val)) } } return this }) } -// TODO: move to mathbigext. -func NthRoot(x *big.Int, n *big.Int) *big.Int { +// NthRoot calculates the n'th root of x. TODO: move to mathbigext. +func nthRoot(x *big.Int, n *big.Int) *big.Int { if x.Cmp(big.NewInt(0)) == 0 { return big.NewInt(0) } @@ -57,7 +62,7 @@ func NthRoot(x *big.Int, n *big.Int) *big.Int { } } -func extractPower(x *big.Int, r *Rational) Ex { +func extractPower(x *big.Int, r *atoms.Rational) expreduceapi.Ex { talliedFactors := primeFactorsTallied(x) hasPowerAtLeastTwo := false for _, tf := range talliedFactors { @@ -78,23 +83,23 @@ func extractPower(x *big.Int, r *Rational) Ex { base.Mul(base, tf.factor) } } - toReturn := E(S("Times")) + toReturn := atoms.E(atoms.S("Times")) for power, base := range bases { bigPower := big.NewInt(0) bigPower.SetUint64(power) - thisR := r.DeepCopy().(*Rational) + thisR := r.DeepCopy().(*atoms.Rational) thisR.MulBigI(bigPower) - thisR.needsEval = true - toReturn.appendEx(E( - S("Power"), - NewInteger(base), + thisR.SetNeedsEval(true) + toReturn.AppendEx(atoms.E( + atoms.S("Power"), + atoms.NewInteger(base), thisR, )) } return toReturn } -func RadSimp(radicand *big.Int, index *big.Int) (*big.Int, *big.Int) { +func radSimp(radicand *big.Int, index *big.Int) (*big.Int, *big.Int) { i := big.NewInt(2) pow := big.NewInt(0) mod := big.NewInt(0) @@ -113,32 +118,44 @@ func RadSimp(radicand *big.Int, index *big.Int) (*big.Int, *big.Int) { return nil, nil } -func GetPowerDefinitions() (defs []Definition) { +func getPowerDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Power", Default: "1", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfixAdvanced(this.Parts[1:], "^", "System`Power", false, "", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if this.Len() == 2 { + if atoms.IsSameQ(this.GetPart(2), atoms.NewRational(big.NewInt(1), big.NewInt(2))) { + nextParams := params + nextParams.PreviousHead = "" + if params.Form == "TeXForm" { + return true, fmt.Sprintf("\\sqrt{%v}", this.GetPart(1).StringForm(nextParams)) + } + if params.Form == "InputForm" { + return true, fmt.Sprintf("Sqrt[%v]", this.GetPart(1).StringForm(nextParams)) + } + } + } + return toStringInfixAdvanced(this.GetParts()[1:], "^", "System`Power", false, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - baseInt, baseIsInt := this.Parts[1].(*Integer) - powerInt, powerIsInt := this.Parts[2].(*Integer) - baseFlt, baseIsFlt := this.Parts[1].(*Flt) - powerFlt, powerIsFlt := this.Parts[2].(*Flt) + baseInt, baseIsInt := this.GetParts()[1].(*atoms.Integer) + powerInt, powerIsInt := this.GetParts()[2].(*atoms.Integer) + baseFlt, baseIsFlt := this.GetParts()[1].(*atoms.Flt) + powerFlt, powerIsFlt := this.GetParts()[2].(*atoms.Flt) //baseRat, baseIsRat := this.Parts[1].(*Rational) - powerRat, powerIsRat := this.Parts[2].(*Rational) + powerRat, powerIsRat := this.GetParts()[2].(*atoms.Rational) // Anything raised to the 1st power is itself if powerIsFlt { if powerFlt.Val.Cmp(big.NewFloat(1)) == 0 { - return this.Parts[1] + return this.GetParts()[1] } } else if powerIsInt { if powerInt.Val.Cmp(big.NewInt(1)) == 0 { - return this.Parts[1] + return this.GetParts()[1] } } // Anything raised to the 0th power is 1, with a small exception @@ -156,68 +173,83 @@ func GetPowerDefinitions() (defs []Definition) { } if powerPositivity == 0 && (baseIsInt || baseIsFlt) { if basePositivity == 0 { - return NewSymbol("System`Indeterminate") + return atoms.NewSymbol("System`Indeterminate") } - return NewInteger(big.NewInt(1)) + return atoms.NewInteger(big.NewInt(1)) } if powerPositivity == 1 && basePositivity == 0 { - return this.Parts[1] + return this.GetParts()[1] } if basePositivity == -1 && powerIsFlt { if powerFlt.Val.Cmp(big.NewFloat(-1)) == 0 { if baseIsInt { - return NewReal(mathbigext.Pow(big.NewFloat(0).SetInt(baseInt.Val), powerFlt.Val)) + return atoms.NewReal(mathbigext.Pow(big.NewFloat(0).SetInt(baseInt.Val), powerFlt.Val)) } if baseIsFlt { - return NewReal(mathbigext.Pow(baseFlt.Val, powerFlt.Val)) + return atoms.NewReal(mathbigext.Pow(baseFlt.Val, powerFlt.Val)) } } // TODO(corywalker): Optimize this logic. There should be no // need for Eval-ing expressions. Simply use numerics built-in // to Go. // a^b - // coeff := ((a^2)^(b/2)) + // coeff := ((a^2)^(b/2)) // Precompute shared values. - coeff := E( - S("Power"), - E( - S("Power"), - baseFlt.DeepCopy(), - NewInt(2), - ), - E( - S("Times"), - powerFlt.DeepCopy(), - NewRational(big.NewInt(1), big.NewInt(2)), - ), - ).Eval(es).(*Flt) + coeff := + + es.Eval(atoms.E( + atoms.S("Power"), + atoms.E( + atoms.S("Power"), + baseFlt.DeepCopy(), + atoms.NewInt(2), + ), + atoms.E( + atoms.S("Times"), + powerFlt.DeepCopy(), + atoms.NewRational(big.NewInt(1), big.NewInt(2)), + ), + )).(*atoms.Flt) // inner := b Arg[a] - inner := E( - S("Times"), - powerFlt.DeepCopy(), - E( - S("Arg"), - baseFlt.DeepCopy(), - ), - ).Eval(es).(*Flt) - re := E( - S("Times"), - coeff.DeepCopy(), - E( - S("Cos"), - inner.DeepCopy(), - ), - ).Eval(es).(*Flt) - im := E( - S("Times"), - coeff.DeepCopy(), - E( - S("Sin"), - inner.DeepCopy(), - ), - ).Eval(es).(*Flt) - return NewComplex(re, im) + inner := + + es.Eval(atoms.E( + atoms.S("Times"), + powerFlt.DeepCopy(), + atoms.E( + atoms.S("Arg"), + baseFlt.DeepCopy(), + ), + )).(*atoms.Flt) + re := + + es.Eval(atoms.E( + atoms.S("Times"), + coeff.DeepCopy(), + atoms.E( + atoms.S("Cos"), + inner.DeepCopy(), + ), + )).(*atoms.Flt) + // If the exponent has no fractional part, i.e. should be an integer, then we can say there will be no imaginary component to the result. + // Reduce[Sin[b*Arg[a]] == 0, b, Reals] // FullSimplify + // C[1] \[Element] Integers && a < 0 && (b == 2 C[1] || b == 1 + 2 C[1]) + if powerFlt.Val.IsInt() { + // TODO: We may want to decide this earlier. Figure this out. + return re + } + im := + + es.Eval(atoms.E( + atoms.S("Times"), + coeff.DeepCopy(), + atoms.E( + atoms.S("Sin"), + inner.DeepCopy(), + ), + )).(*atoms.Flt) + return atoms.NewComplex(re, im) } //es.Debugf("Power eval. baseIsInt=%v, powerIsInt=%v", baseIsInt, powerIsInt) @@ -228,33 +260,33 @@ func GetPowerDefinitions() (defs []Definition) { if cmpres == 1 { res := big.NewInt(0) res.Exp(baseInt.Val, powerInt.Val, nil) - return NewInteger(res) + return atoms.NewInteger(res) } else if cmpres == -1 { newbase := big.NewInt(0) absPower := big.NewInt(0) absPower.Abs(powerInt.Val) newbase.Exp(baseInt.Val, absPower, nil) if newbase.Cmp(big.NewInt(1)) == 0 { - return NewInteger(big.NewInt(1)) + return atoms.NewInteger(big.NewInt(1)) } if newbase.Cmp(big.NewInt(-1)) == 0 { - return NewInteger(big.NewInt(-1)) + return atoms.NewInteger(big.NewInt(-1)) } //return NewExpression([]Ex{&Symbol{"System`Power"}, &Integer{newbase}, &Integer{big.NewInt(-1)}}) - return NewExpression([]Ex{NewSymbol("System`Rational"), NewInteger(big.NewInt(1)), NewInteger(newbase)}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Rational"), atoms.NewInteger(big.NewInt(1)), atoms.NewInteger(newbase)}) } else { - return NewExpression([]Ex{NewSymbol("System`Error"), NewString("Unexpected zero power in Power evaluation.")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString("Unexpected zero power in Power evaluation.")}) } } if baseIsFlt && powerIsInt { - return NewReal(mathbigext.Pow(baseFlt.Val, big.NewFloat(0).SetInt(powerInt.Val))) + return atoms.NewReal(mathbigext.Pow(baseFlt.Val, big.NewFloat(0).SetInt(powerInt.Val))) } if baseIsInt && powerIsFlt { - return NewReal(mathbigext.Pow(big.NewFloat(0).SetInt(baseInt.Val), powerFlt.Val)) + return atoms.NewReal(mathbigext.Pow(big.NewFloat(0).SetInt(baseInt.Val), powerFlt.Val)) } if baseIsFlt && powerIsFlt { - return NewReal(mathbigext.Pow(baseFlt.Val, powerFlt.Val)) + return atoms.NewReal(mathbigext.Pow(baseFlt.Val, powerFlt.Val)) } if baseIsInt && powerIsRat { x := baseInt.Val @@ -264,13 +296,13 @@ func GetPowerDefinitions() (defs []Definition) { nPositivity := n.Cmp(big.NewInt(0)) mPositivity := m.Cmp(big.NewInt(0)) if xPositivity >= 0 && - nPositivity == 1 { - root := NthRoot(x, n) + nPositivity == 1 { + root := nthRoot(x, n) if root != nil { if m.Cmp(big.NewInt(1)) == 0 { - return NewInteger(root) + return atoms.NewInteger(root) } - return E(S("Power"), NewInteger(root), NewInteger(m)) + return atoms.E(atoms.S("Power"), atoms.NewInteger(root), atoms.NewInteger(m)) } powerExtracted := extractPower(x, powerRat) if powerExtracted != nil { @@ -280,21 +312,21 @@ func GetPowerDefinitions() (defs []Definition) { if nPositivity == 1 { absX := big.NewInt(0) absX.Abs(x) - extracted, radicand := RadSimp(absX, n) + extracted, radicand := radSimp(absX, n) if extracted != nil { if xPositivity == -1 { radicand.Neg(radicand) } - var coeff Ex = NewInteger(extracted) + var coeff expreduceapi.Ex = atoms.NewInteger(extracted) if mPositivity == -1 { - coeff = NewRational(big.NewInt(1), extracted) + coeff = atoms.NewRational(big.NewInt(1), extracted) } - return E( - S("Times"), + return atoms.E( + atoms.S("Times"), coeff, - E( - S("Power"), - NewInteger(radicand), + atoms.E( + atoms.S("Power"), + atoms.NewInteger(radicand), powerRat, ), ) @@ -336,7 +368,7 @@ func GetPowerDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "PSimplify", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, }) defs = append(defs, Definition{Name: "FactorSquareFree"}) defs = append(defs, Definition{ @@ -345,5 +377,9 @@ func GetPowerDefinitions() (defs []Definition) { }) defs = append(defs, Definition{Name: "Arg"}) defs = append(defs, Definition{Name: "ComplexExpand"}) + defs = append(defs, Definition{ + Name: "Exp", + legacyEvalFn: mathFnOneParam(math.Exp), + }) return } diff --git a/expreduce/builtin_random.go b/expreduce/builtin_random.go index 49d2cbc..b2401c2 100644 --- a/expreduce/builtin_random.go +++ b/expreduce/builtin_random.go @@ -1,20 +1,25 @@ package expreduce -import "math/big" -import "math/rand" +import ( + "math/big" + "math/rand" -func GetRandomDefinitions() (defs []Definition) { + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func getRandomDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "RandomReal", Details: "`SeedRandom[UnixTime[]]` is called automatically upon " + "initialization of Expreduce, so random number sequences will not " + "repeat over subsequent sessions.", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 1 { return this } - return NewReal(big.NewFloat(rand.Float64())) + return atoms.NewReal(big.NewFloat(rand.Float64())) }, }) defs = append(defs, Definition{ @@ -22,15 +27,15 @@ func GetRandomDefinitions() (defs []Definition) { Details: "`SeedRandom[UnixTime[]]` is called automatically upon " + "initialization of Expreduce, so random number sequences will not " + "repeat over subsequent sessions.", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - asInt, isInt := this.Parts[1].(*Integer) + asInt, isInt := this.GetParts()[1].(*atoms.Integer) if isInt { rand.Seed(asInt.Val.Int64()) - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") } return this diff --git a/expreduce/builtin_replacement.go b/expreduce/builtin_replacement.go index 28f18c3..67247b5 100644 --- a/expreduce/builtin_replacement.go +++ b/expreduce/builtin_replacement.go @@ -1,21 +1,27 @@ package expreduce -func getValidRules(ruleArg Ex) (rules []*Expression) { - rulesRule, ok := HeadAssertion(ruleArg, "System`Rule") +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func getValidRules(ruleArg expreduceapi.Ex) (rules []expreduceapi.ExpressionInterface) { + rulesRule, ok := atoms.HeadAssertion(ruleArg, "System`Rule") if !ok { - rulesRule, ok = HeadAssertion(ruleArg, "System`RuleDelayed") + rulesRule, ok = atoms.HeadAssertion(ruleArg, "System`RuleDelayed") } if ok { - return []*Expression{rulesRule} + return []expreduceapi.ExpressionInterface{rulesRule} } // Also handle a list of Rules - asList, isList := HeadAssertion(ruleArg, "System`List") + asList, isList := atoms.HeadAssertion(ruleArg, "System`List") if isList { - for i := 1; i < len(asList.Parts); i++ { - rulesRule, ok := HeadAssertion(asList.Parts[i], "System`Rule") + for i := 1; i < len(asList.GetParts()); i++ { + rulesRule, ok := atoms.HeadAssertion(asList.GetParts()[i], "System`Rule") if !ok { - rulesRule, ok = HeadAssertion(asList.Parts[i], "System`RuleDelayed") + rulesRule, ok = atoms.HeadAssertion(asList.GetParts()[i], "System`RuleDelayed") } if ok { rules = append(rules, rulesRule) @@ -25,18 +31,18 @@ func getValidRules(ruleArg Ex) (rules []*Expression) { return } -func rulesReplaceAll(e Ex, rules []*Expression, es *EvalState) Ex { +func rulesReplaceAll(e expreduceapi.Ex, rules []expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { // TODO: fix the case where ReplaceAll[{x},{x->y,y->z}] returns incorrectly. toReturn := e for _, rule := range rules { - toReturn = ReplaceAll(toReturn, rule, es, EmptyPD(), "") + toReturn = replaceAll(toReturn, rule, es, matcher.EmptyPD(), "") } return toReturn } -func rulesReplace(e Ex, rules []*Expression, es *EvalState) (Ex, bool) { +func rulesReplace(e expreduceapi.Ex, rules []expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { for _, rule := range rules { - res, replaced := Replace(e, rule, es) + res, replaced := replace(e, rule, es) if replaced { return res, true } @@ -44,32 +50,32 @@ func rulesReplace(e Ex, rules []*Expression, es *EvalState) (Ex, bool) { return e, false } -func replaceParts(e Ex, rules []*Expression, part *Expression, es *EvalState) Ex { - expr, isExpr := e.(*Expression) +func replaceParts(e expreduceapi.Ex, rules []expreduceapi.ExpressionInterface, part expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + expr, isExpr := e.(expreduceapi.ExpressionInterface) if !isExpr { return e } - res := E(expr.Parts[0]) - part.Parts = append(part.Parts, NewInt(0)) + res := atoms.E(expr.GetParts()[0]) + part.AppendEx(atoms.NewInt(0)) dirty := false - for i, p := range expr.Parts[1:] { - part.Parts[len(part.Parts)-1] = NewInt(int64(i + 1)) + for i, p := range expr.GetParts()[1:] { + part.GetParts()[len(part.GetParts())-1] = atoms.NewInt(int64(i + 1)) repVal, replaced := rulesReplace(part, rules, es) - if !replaced && len(part.Parts) == 2 { - repVal, replaced = rulesReplace(part.Parts[1], rules, es) + if !replaced && len(part.GetParts()) == 2 { + repVal, replaced = rulesReplace(part.GetParts()[1], rules, es) } if replaced { - res.Parts = append(res.Parts, repVal) + res.AppendEx(repVal) dirty = true } else { newVal := replaceParts(p, rules, part, es) - res.Parts = append(res.Parts, newVal) + res.AppendEx(newVal) if newVal != p { dirty = true } } } - part.Parts = part.Parts[:len(part.Parts)-1] + part.SetParts(part.GetParts()[:len(part.GetParts())-1]) if !dirty { return e } @@ -79,69 +85,72 @@ func replaceParts(e Ex, rules []*Expression, part *Expression, es *EvalState) Ex func getReplacementDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ReplaceAll", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - return ToStringInfixAdvanced(this.Parts[1:], " /. ", "", true, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], " /. ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - rules := getValidRules(this.Parts[2]) + rules := getValidRules(this.GetParts()[2]) if len(rules) == 0 { return this } - return rulesReplaceAll(this.Parts[1], rules, es) + return rulesReplaceAll(this.GetParts()[1], rules, es) }, }) defs = append(defs, Definition{ Name: "Replace", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - rules := getValidRules(this.Parts[2]) + rules := getValidRules(this.GetParts()[2]) if len(rules) == 0 { return this } for _, rule := range rules { - toReturn, replaced := Replace(this.Parts[1], rule, es) + toReturn, replaced := replace(this.GetParts()[1], rule, es) if replaced { return toReturn } } - return this.Parts[1] + return this.GetParts()[1] }, }) defs = append(defs, Definition{ Name: "ReplaceRepeated", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - return ToStringInfixAdvanced(this.Parts[1:], " //. ", "", true, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], " //. ", "", true, "", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } es.Infof("Starting ReplaceRepeated.") isSame := false - oldEx := this.Parts[1] + oldEx := this.GetParts()[1] es.Infof("In ReplaceRepeated. Initial expr: %v", oldEx) for !isSame { - newEx := (NewExpression([]Ex{ - NewSymbol("System`ReplaceAll"), - oldEx, - this.Parts[2], - })).Eval(es) + newEx := + + es.Eval((atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`ReplaceAll"), + oldEx, + this.GetParts()[2], + }))) + es.Infof("In ReplaceRepeated. New expr: %v", newEx) - if IsSameQ(oldEx, newEx, &es.CASLogger) { + if atoms.IsSameQ(oldEx, newEx) { isSame = true } oldEx = newEx @@ -151,49 +160,49 @@ func getReplacementDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Rule", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } delim := " -> " - if params.form == "TeXForm" { + if params.Form == "TeXForm" { delim = "\\to " } - return ToStringInfixAdvanced(this.Parts[1:], delim, "System`Rule", false, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], delim, "System`Rule", false, "", "", params) }, }) defs = append(defs, Definition{ Name: "RuleDelayed", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } delim := " :> " - if params.form == "TeXForm" { + if params.Form == "TeXForm" { delim = ":\\to " } - return ToStringInfixAdvanced(this.Parts[1:], delim, "System`RuleDelayed", false, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], delim, "System`RuleDelayed", false, "", "", params) }, }) defs = append(defs, Definition{ Name: "ReplacePart", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - rules, isList := HeadAssertion(this.Parts[2], "System`List") + rules, isList := atoms.HeadAssertion(this.GetParts()[2], "System`List") if !isList { return this } - exprRules := [](*Expression){} - for _, rulesPart := range rules.Parts[1:] { - rule, isRule := HeadAssertion(rulesPart, "System`Rule") + exprRules := [](expreduceapi.ExpressionInterface){} + for _, rulesPart := range rules.GetParts()[1:] { + rule, isRule := atoms.HeadAssertion(rulesPart, "System`Rule") if !isRule { return this } exprRules = append(exprRules, rule) } - return replaceParts(this.Parts[1], exprRules, E(S("List")), es) + return replaceParts(this.GetParts()[1], exprRules, atoms.E(atoms.S("List")), es) }, }) return diff --git a/expreduce/builtin_rubi.go b/expreduce/builtin_rubi.go index fc20093..e48ac05 100644 --- a/expreduce/builtin_rubi.go +++ b/expreduce/builtin_rubi.go @@ -1,9 +1,9 @@ package expreduce -func GetRubiDefinitions() (defs []Definition) { +func getRubiDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "LoadRubi", - ExpreduceSpecific: true, + expreduceSpecific: true, }) return } diff --git a/expreduce/builtin_simplify.go b/expreduce/builtin_simplify.go index ea8cd80..fb1d674 100644 --- a/expreduce/builtin_simplify.go +++ b/expreduce/builtin_simplify.go @@ -1,6 +1,6 @@ package expreduce -func GetSimplifyDefinitions() (defs []Definition) { +func getSimplifyDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "Simplify"}) defs = append(defs, Definition{Name: "FullSimplify"}) return diff --git a/expreduce/builtin_solve.go b/expreduce/builtin_solve.go index b5464c8..7702f09 100644 --- a/expreduce/builtin_solve.go +++ b/expreduce/builtin_solve.go @@ -1,6 +1,6 @@ package expreduce -func GetSolveDefinitions() (defs []Definition) { +func getSolveDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Solve", Details: "!!! warning \"Under development\"\n" + diff --git a/expreduce/builtin_sort.go b/expreduce/builtin_sort.go index ba63e2a..befbdda 100644 --- a/expreduce/builtin_sort.go +++ b/expreduce/builtin_sort.go @@ -3,21 +3,23 @@ package expreduce import ( "math/big" "sort" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) -func GetSortDefinitions() (defs []Definition) { +func getSortDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Sort", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - exp, ok := this.Parts[1].(*Expression) + exp, ok := this.GetParts()[1].(expreduceapi.ExpressionInterface) if ok { - sortedExp := exp.DeepCopy().(*Expression) - sortedExp.evaledHash = 0 - sortedExp.cachedHash = 0 + sortedExp := exp.DeepCopy().(expreduceapi.ExpressionInterface) + sortedExp.ClearHashes() sort.Sort(sortedExp) return sortedExp } @@ -26,13 +28,13 @@ func GetSortDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Order", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - toreturn := ExOrder(this.Parts[1], this.Parts[2]) - return NewInteger(big.NewInt(toreturn)) + toreturn := atoms.ExOrder(this.GetParts()[1], this.GetParts()[2]) + return atoms.NewInteger(big.NewInt(toreturn)) }, }) return diff --git a/expreduce/builtin_stats.go b/expreduce/builtin_stats.go index 054f619..837b6bc 100644 --- a/expreduce/builtin_stats.go +++ b/expreduce/builtin_stats.go @@ -1,6 +1,6 @@ package expreduce -func GetStatsDefinitions() (defs []Definition) { +func getStatsDefinitions() (defs []Definition) { defs = append(defs, Definition{Name: "NormalDistribution"}) defs = append(defs, Definition{Name: "LogNormalDistribution"}) defs = append(defs, Definition{Name: "PDF"}) diff --git a/expreduce/builtin_string.go b/expreduce/builtin_string.go index 9984426..d484bb3 100644 --- a/expreduce/builtin_string.go +++ b/expreduce/builtin_string.go @@ -1,20 +1,25 @@ package expreduce import ( - "strings" "encoding/base64" + "fmt" + "strings" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/graphics" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) -func GetStringDefinitions() (defs []Definition) { +func getStringDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ToString", // For some reason this is fast for StringJoin[Table["x", {k,2000}]/.List->Sequence] - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - formAsSymbol, formIsSymbol := this.Parts[2].(*Symbol) + formAsSymbol, formIsSymbol := this.GetParts()[2].(*atoms.Symbol) if !formIsSymbol { return this } @@ -24,67 +29,67 @@ func GetStringDefinitions() (defs []Definition) { return this } - context, contextPath := ActualStringFormArgs(es) - stringParams := ToStringParams{ - form: formAsSymbol.Name[7:], - context: context, - contextPath: contextPath, - previousHead: "", - es: es, - } - return NewString(this.Parts[1].StringForm(stringParams)) + context, contextPath := actualStringFormArgs(es) + stringParams := expreduceapi.ToStringParams{ + Form: formAsSymbol.Name[7:], + Context: context, + ContextPath: contextPath, + PreviousHead: "", + Esi: es, + } + return atoms.NewString(this.GetParts()[1].StringForm(stringParams)) }, }) defs = append(defs, Definition{ Name: "StringJoin", - toString: func(this *Expression, params ToStringParams) (bool, string) { - return ToStringInfix(this.Parts[1:], " <> ", "", params) + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + return toStringInfix(this.GetParts()[1:], " <> ", "", params) }, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { toReturn := "" - for _, e := range this.Parts[1:] { - asStr, isStr := e.(*String) + for _, e := range this.GetParts()[1:] { + asStr, isStr := e.(*atoms.String) if !isStr { return this } toReturn += asStr.Val } - return NewString(toReturn) + return atoms.NewString(toReturn) }, }) defs = append(defs, Definition{ Name: "Infix", - toString: (*Expression).ToStringInfix, + toString: toStringInfixFn, }) defs = append(defs, Definition{ Name: "StringLength", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - asStr, isStr := this.Parts[1].(*String) + asStr, isStr := this.GetParts()[1].(*atoms.String) if !isStr { return this } - return NewInt(int64(len(asStr.Val))) + return atoms.NewInt(int64(len(asStr.Val))) }, }) defs = append(defs, Definition{ Name: "StringTake", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - asStr, isStr := this.Parts[1].(*String) + asStr, isStr := this.GetParts()[1].(*atoms.String) if !isStr { return this } - asList, isList := HeadAssertion(this.Parts[2], "System`List") - if !isList || len(asList.Parts) != 3 { + asList, isList := atoms.HeadAssertion(this.GetParts()[2], "System`List") + if !isList || len(asList.GetParts()) != 3 { return this } - sInt, sIsInt := asList.Parts[1].(*Integer) - eInt, eIsInt := asList.Parts[2].(*Integer) + sInt, sIsInt := asList.GetParts()[1].(*atoms.Integer) + eInt, eIsInt := asList.GetParts()[2].(*atoms.Integer) if !sIsInt || !eIsInt { return this } @@ -94,53 +99,63 @@ func GetStringDefinitions() (defs []Definition) { return this } if e < s { - return NewString("") + return atoms.NewString("") } - return NewString(asStr.Val[s : e+1]) + return atoms.NewString(asStr.Val[s : e+1]) }, }) defs = append(defs, Definition{ Name: "StringReplace", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - asStr, isStr := this.Parts[1].(*String) + asStr, isStr := this.GetParts()[1].(*atoms.String) if !isStr { return this } - asRule, isRule := HeadAssertion(this.Parts[2], "System`Rule") - if !isRule || len(asRule.Parts) != 3 { + asRule, isRule := atoms.HeadAssertion(this.GetParts()[2], "System`Rule") + if !isRule || len(asRule.GetParts()) != 3 { return this } - bStr, bIsStr := asRule.Parts[1].(*String) - aStr, aIsStr := asRule.Parts[2].(*String) + bStr, bIsStr := asRule.GetParts()[1].(*atoms.String) + aStr, aIsStr := asRule.GetParts()[2].(*atoms.String) if !bIsStr || !aIsStr { return this } - return NewString(strings.Replace(asStr.Val, bStr.Val, aStr.Val, -1)) + return atoms.NewString(strings.Replace(asStr.Val, bStr.Val, aStr.Val, -1)) }, }) defs = append(defs, Definition{ Name: "ExportString", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 && len(this.GetParts()) != 4 { return this } - asStr, isStr := this.Parts[1].(*String) - if !isStr { - return this - } - formatAsStr, formatIsStr := this.Parts[2].(*String) + formatAsStr, formatIsStr := this.GetParts()[2].(*atoms.String) if !formatIsStr { return this } format := strings.ToLower(formatAsStr.Val) + + if format == "png" { + chartAsPNG, err := graphics.RenderAsPNG(this.GetPart(1)) + if err != nil { + fmt.Printf("Encountered error during PNG render: %v\n", err) + return atoms.NewSymbol("System`$Failed") + } + return atoms.NewString(chartAsPNG) + } + + asStr, isStr := this.GetParts()[1].(*atoms.String) + if !isStr { + return this + } if format == "base64" { encoded := base64.StdEncoding.EncodeToString([]byte(asStr.Val)) - return NewString(encoded + "\n") + return atoms.NewString(encoded + "\n") } - return NewSymbol("System`$Failed") + return atoms.NewSymbol("System`$Failed") }, }) return diff --git a/expreduce/builtin_system.go b/expreduce/builtin_system.go index 2e8cd05..2531391 100644 --- a/expreduce/builtin_system.go +++ b/expreduce/builtin_system.go @@ -1,79 +1,85 @@ package expreduce -import "math/big" -import "time" -import "fmt" -import "os" -import "strings" -import "runtime/pprof" -import "log" -import "io/ioutil" -import "github.com/op/go-logging" -import "flag" +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "math/big" + "os" + "runtime/pprof" + "strings" + "time" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/op/go-logging" +) var mymemprofile = flag.String("mymemprofile", "", "write memory profile to this file") -func hashEx(e Ex) uint64 { +func hashEx(e expreduceapi.Ex) uint64 { return e.Hash() } -func exprToN(es *EvalState, e Ex) Ex { - asInt, isInt := e.(*Integer) +func exprToN(es expreduceapi.EvalStateInterface, e expreduceapi.Ex) expreduceapi.Ex { + asInt, isInt := e.(*atoms.Integer) if isInt { - toReturn, _ := IntegerToFlt(asInt) + toReturn, _ := atoms.IntegerToFlt(asInt) return toReturn } - asRat, isRat := e.(*Rational) + asRat, isRat := e.(*atoms.Rational) if isRat { - toReturn, _ := RationalToFlt(asRat) + toReturn, _ := atoms.RationalToFlt(asRat) return toReturn } - _, isSym := e.(*Symbol) + _, isSym := e.(*atoms.Symbol) if isSym { toReturn, defined, _ := es.GetDef( "System`N", - NewExpression([]Ex{NewSymbol("System`N"), e}), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), e}), ) if defined { return toReturn } } - asExpr, isExpr := e.(*Expression) + asExpr, isExpr := e.(expreduceapi.ExpressionInterface) if isExpr { toReturn, defined, _ := es.GetDef( "System`N", - NewExpression([]Ex{NewSymbol("System`N"), e}), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), e}), ) if defined { return toReturn } - exToReturn := NewEmptyExpression() - for _, part := range asExpr.Parts { + exToReturn := atoms.NewEmptyExpression() + for _, part := range asExpr.GetParts() { toAdd, defined, _ := es.GetDef( "System`N", - NewExpression([]Ex{NewSymbol("System`N"), part}), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`N"), part}), ) if !defined { toAdd = exprToN(es, part) } - exToReturn.Parts = append(exToReturn.Parts, toAdd) + exToReturn.AppendEx(toAdd) } return exToReturn } return e.DeepCopy() } -func TryReadFile(fn Ex, es *EvalState) (string, string, bool) { - pathSym := NewSymbol("System`$Path") +func tryReadFile(fn expreduceapi.Ex, es expreduceapi.EvalStateInterface) (string, string, bool) { + pathSym := atoms.NewSymbol("System`$Path") path, isDef, _ := es.GetDef("System`$Path", pathSym) if !isDef { return "", "", false } - pathL, pathIsList := HeadAssertion(path, "System`List") + pathL, pathIsList := atoms.HeadAssertion(path, "System`List") if !pathIsList { return "", "", false } - filenameString, fnIsStr := fn.(*String) + filenameString, fnIsStr := fn.(*atoms.String) if !fnIsStr { return "", "", false } @@ -89,8 +95,8 @@ func TryReadFile(fn Ex, es *EvalState) (string, string, bool) { } pathsToTry := []string{} - for _, pathEx := range pathL.Parts[1:] { - pathString, pathIsString := pathEx.(*String) + for _, pathEx := range pathL.GetParts()[1:] { + pathString, pathIsString := pathEx.(*atoms.String) if !pathIsString { fmt.Printf("Invalid path: %v\n", pathEx) continue @@ -111,12 +117,12 @@ func TryReadFile(fn Ex, es *EvalState) (string, string, bool) { return "", "", false } -func snagUnique(context string, prefix string, es *EvalState) (string, bool) { +func snagUnique(context string, prefix string, es expreduceapi.EvalStateInterface) (string, bool) { mnExpr, mnIsDef := es.GetSymDef("System`$ModuleNumber") if !mnIsDef { return "", false } - mnInteger, mnIsInt := mnExpr.(*Integer) + mnInteger, mnIsInt := mnExpr.(*atoms.Integer) if !mnIsInt { return "", false } @@ -126,49 +132,48 @@ func snagUnique(context string, prefix string, es *EvalState) (string, bool) { for { toTry := fmt.Sprintf("%v%v%v", context, prefix, mn) if !es.IsDef(toTry) { - es.Define(NewSymbol("System`$ModuleNumber"), NewInteger(big.NewInt(mn+1))) + es.Define(atoms.NewSymbol("System`$ModuleNumber"), atoms.NewInteger(big.NewInt(mn+1))) return toTry, true } - mn += 1 + mn++ } - return "", false } -func applyModuleFn(this *Expression, es *EvalState) (Ex, bool) { +func applyModuleFn(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { // Coarse parsing of arguments. - if len(this.Parts) != 3 { + if len(this.GetParts()) != 3 { return nil, false } - locals, localsIsList := HeadAssertion(this.Parts[1], "System`List") + locals, localsIsList := atoms.HeadAssertion(this.GetParts()[1], "System`List") if !localsIsList { return nil, false } // Parse locals into a struct type parsedLocal struct { - sym *Symbol + sym *atoms.Symbol uniqueName string - setValue Ex + setValue expreduceapi.Ex isSet bool isSetDelayed bool } var parsedLocals []parsedLocal - for _, localEx := range locals.Parts[1:] { + for _, localEx := range locals.GetParts()[1:] { pl := parsedLocal{} symEx := localEx - localSet, localIsSet := HeadAssertion(localEx, "System`Set") + localSet, localIsSet := atoms.HeadAssertion(localEx, "System`Set") pl.isSet = localIsSet - localSetDelayed, localIsSetDelayed := HeadAssertion(localEx, "System`SetDelayed") + localSetDelayed, localIsSetDelayed := atoms.HeadAssertion(localEx, "System`SetDelayed") pl.isSetDelayed = localIsSetDelayed - if localIsSet && len(localSet.Parts) == 3 { - symEx = localSet.Parts[1] - pl.setValue = localSet.Parts[2] + if localIsSet && len(localSet.GetParts()) == 3 { + symEx = localSet.GetParts()[1] + pl.setValue = localSet.GetParts()[2] } - if localIsSetDelayed && len(localSetDelayed.Parts) == 3 { - symEx = localSetDelayed.Parts[1] - pl.setValue = localSetDelayed.Parts[2] + if localIsSetDelayed && len(localSetDelayed.GetParts()) == 3 { + symEx = localSetDelayed.GetParts()[1] + pl.setValue = localSetDelayed.GetParts()[2] } - localSym, localIsSym := symEx.(*Symbol) + localSym, localIsSym := symEx.(*atoms.Symbol) pl.sym = localSym if !localIsSym { return nil, false @@ -183,52 +188,70 @@ func applyModuleFn(this *Expression, es *EvalState) (Ex, bool) { } parsedLocals[i].uniqueName = unique } - toReturn := this.Parts[2] - pm := EmptyPD() + toReturn := this.GetParts()[2] + pm := matcher.EmptyPD() for _, pl := range parsedLocals { if pl.isSet || pl.isSetDelayed { rhs := pl.setValue if pl.isSet { - rhs = rhs.Eval(es) - } - es.defined.Set(pl.uniqueName, Def{ - downvalues: []DownValue{ - DownValue{ - rule: NewExpression([]Ex{ - NewSymbol("System`Rule"), - E(S("HoldPattern"), NewSymbol(pl.uniqueName)), + rhs = es.Eval(rhs) + } + es.GetDefinedMap().Set(pl.uniqueName, expreduceapi.Def{ + Downvalues: []expreduceapi.DownValue{ + expreduceapi.DownValue{ + Rule: atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), + atoms.E(atoms.S("HoldPattern"), atoms.NewSymbol(pl.uniqueName)), rhs, }), }, }, }) } else { - es.defined.Set(pl.uniqueName, Def{}) + es.GetDefinedMap().Set(pl.uniqueName, expreduceapi.Def{}) } - pm.LazyMakeMap() - pm.patternDefined[pl.sym.Name] = NewSymbol(pl.uniqueName) + pm.Define(pl.sym.Name, atoms.NewSymbol(pl.uniqueName)) } - toReturn = ReplacePD(toReturn, es, pm) + toReturn = matcher.ReplacePD(toReturn, es, pm) return toReturn, true } -func GetSystemDefinitions() (defs []Definition) { +func parseOutputStream(outputStreamDef expreduceapi.Ex) (string, int64, bool) { + outputStream, isOutputStream := atoms.HeadAssertion(outputStreamDef, "System`OutputStream") + if !isOutputStream { + return "", -1, false + } + if outputStream.Len() != 2 { + return "", -1, false + } + streamName, ok := outputStream.GetPart(1).(*atoms.String) + if !ok { + return "", -1, false + } + streamIndex, ok := outputStream.GetPart(2).(*atoms.Integer) + if !ok { + return "", -1, false + } + return streamName.GetValue(), streamIndex.Val.Int64(), true +} + +func getSystemDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ExpreduceSetLogging", Details: "Logging output prints to the console. There can be a lot of logging output, especially for more complicated pattern matches. Valid levels are `Debug`, `Info`, `Notice`, `Warning`, `Error`, and `Critical`.", - ExpreduceSpecific: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + expreduceSpecific: true, + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - sym, ok := this.Parts[1].(*Symbol) + sym, ok := this.GetParts()[1].(*atoms.Symbol) if ok { if sym.Name == "System`True" { errorStr := "Invalid level. Must be one of {Debug, Info, Notice}." - levelSym, lsOk := this.Parts[2].(*Symbol) + levelSym, lsOk := this.GetParts()[2].(*atoms.Symbol) if !lsOk { - return NewExpression([]Ex{NewSymbol("System`Error"), NewString(errorStr)}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString(errorStr)}) } if levelSym.Name == "System`Debug" { es.DebugOn(logging.DEBUG) @@ -237,12 +260,12 @@ func GetSystemDefinitions() (defs []Definition) { } else if levelSym.Name == "System`Notice" { es.DebugOn(logging.NOTICE) } else { - return NewExpression([]Ex{NewSymbol("System`Error"), NewString(errorStr)}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString(errorStr)}) } - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") } else if sym.Name == "System`False" { es.DebugOff() - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") } } return this @@ -251,8 +274,8 @@ func GetSystemDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ExpreduceDefinitionTimes", Details: "For timing information to record, debug mode must be enabled through `ExpreduceSetLogging`.", - ExpreduceSpecific: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + expreduceSpecific: true, + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { if *mymemprofile != "" { f, err := os.Create(*mymemprofile) if err != nil { @@ -261,42 +284,42 @@ func GetSystemDefinitions() (defs []Definition) { pprof.WriteHeapProfile(f) f.Close() } - fmt.Println(es.timeCounter.String()) - return NewSymbol("System`Null") + fmt.Println(es.GetTimeCounter().String()) + return atoms.NewSymbol("System`Null") }, }) defs = append(defs, Definition{ Name: "Attributes", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - sym, isSym := this.Parts[1].(*Symbol) + sym, isSym := this.GetParts()[1].(*atoms.Symbol) if !isSym { return this } - def, isDef := es.defined.Get(sym.Name) + def, isDef := es.GetDefinedMap().Get(sym.Name) if isDef { - return def.attributes.toSymList() + return atoms.AttrsToSymList(&def.Attributes) } - return NewExpression([]Ex{NewSymbol("System`List")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) }, }) defs = append(defs, Definition{ Name: "Default", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - sym, isSym := this.Parts[1].(*Symbol) + sym, isSym := this.GetParts()[1].(*atoms.Symbol) if !isSym { return this } - def := sym.Default(&es.defined) + def := sym.Default(es.GetDefinedMap()) if def != nil { return def } @@ -305,72 +328,72 @@ func GetSystemDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Clear", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - for _, arg := range this.Parts[1:] { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + for _, arg := range this.GetParts()[1:] { es.Debugf("arg: %v", arg) - sym, isSym := arg.(*Symbol) + sym, isSym := arg.(*atoms.Symbol) if isSym { es.Clear(sym.Name) } } - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") }, }) defs = append(defs, Definition{ - Name: "Definition", - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 2 { + Name: "Definition", + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 2 { return false, "" } - if params.form != "InputForm" && params.form != "OutputForm" { + if params.Form != "InputForm" && params.Form != "OutputForm" { return false, "" } - sym, ok := this.Parts[1].(*Symbol) + sym, ok := this.GetParts()[1].(*atoms.Symbol) if !ok { return false, "" } - if params.es == nil { + if params.Esi == nil { return true, "Definiton[]" } - def, isd := params.es.defined.Get(sym.Name) + def, isd := params.Esi.GetDefined(sym.Name) if !isd { return true, "Null" } stringParams := params - stringParams.context, stringParams.contextPath = - DefinitionComplexityStringFormArgs() - stringParams.previousHead = "" + stringParams.Context, stringParams.ContextPath = + definitionComplexityStringFormArgs() + stringParams.PreviousHead = "" // To prevent things like "Definition[In]" from exploding: - stringParams.es = nil - return true, def.StringForm(sym, stringParams) + stringParams.Esi = nil + return true, stringForm(&def, sym, stringParams) }, }) defs = append(defs, Definition{ Name: "DownValues", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - sym, ok := this.Parts[1].(*Symbol) + sym, ok := this.GetParts()[1].(*atoms.Symbol) if !ok { return this } - res := NewExpression([]Ex{NewSymbol("System`List")}) - def, isd := es.defined.Get(sym.Name) + res := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + def, isd := es.GetDefinedMap().Get(sym.Name) if !isd { return res } - for _, dv := range def.downvalues { - _, isLhsExpr := dv.rule.Parts[1].(*Expression).Parts[1].(*Expression) - if !isLhsExpr { + for _, dv := range def.Downvalues { + _, isLHSExpr := dv.Rule.GetParts()[1].(expreduceapi.ExpressionInterface).GetParts()[1].(expreduceapi.ExpressionInterface) + if !isLHSExpr { continue } - res.Parts = append(res.Parts, NewExpression([]Ex{ - NewSymbol("System`RuleDelayed"), - dv.rule.Parts[1], - dv.rule.Parts[2], + res.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`RuleDelayed"), + dv.Rule.GetParts()[1], + dv.Rule.GetParts()[2], })) } return res @@ -380,20 +403,20 @@ func GetSystemDefinitions() (defs []Definition) { Name: "Set", Usage: "`lhs = rhs` sets `lhs` to stand for `rhs`.", Attributes: []string{"HoldFirst", "SequenceHold"}, - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - return ToStringInfixAdvanced(this.Parts[1:], " = ", "System`Set", false, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], " = ", "System`Set", false, "", "", params) }, Bootstrap: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - es.Define(this.Parts[1], this.Parts[2]) - return this.Parts[2] + es.Define(this.GetParts()[1], this.GetParts()[2]) + return this.GetParts()[2] }, SimpleExamples: []TestInstruction{ &StringTest{"3", "x=1+2"}, @@ -428,27 +451,27 @@ func GetSystemDefinitions() (defs []Definition) { Name: "SetDelayed", Usage: "`lhs := rhs` sets `lhs` to stand for `rhs`, with `rhs` not being evaluated until it is referenced by `lhs`.", Attributes: []string{"HoldAll", "SequenceHold"}, - toString: func(this *Expression, params ToStringParams) (bool, string) { - if len(this.Parts) != 3 { + toString: func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - return ToStringInfixAdvanced(this.Parts[1:], " := ", "System`SetDelayed", false, "", "", params) + return toStringInfixAdvanced(this.GetParts()[1:], " := ", "System`SetDelayed", false, "", "", params) }, Bootstrap: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 3 { return this } - lhs, lhsIsExpr := this.Parts[1].(*Expression) + lhs, lhsIsExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) if lhsIsExpr { - for i := range lhs.Parts { - lhs.Parts[i] = lhs.Parts[i].Eval(es) + for i := range lhs.GetParts() { + lhs.GetParts()[i] = es.Eval(lhs.GetParts()[i]) } - es.Define(lhs, this.Parts[2]) + es.Define(lhs, this.GetParts()[2]) } - es.Define(this.Parts[1], this.Parts[2]) - return NewSymbol("System`Null") + es.Define(this.GetParts()[1], this.GetParts()[2]) + return atoms.NewSymbol("System`Null") }, SimpleExamples: []TestInstruction{ &TestComment{"`SetDelayed` can be used to define functions:"}, @@ -504,48 +527,28 @@ func GetSystemDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Timing", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } start := time.Now() - res := this.Parts[1].Eval(es) + res := es.Eval(this.GetParts()[1]) elapsed := time.Since(start).Seconds() - return NewExpression([]Ex{NewSymbol("System`List"), NewReal(big.NewFloat(elapsed)), res}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List"), atoms.NewReal(big.NewFloat(elapsed)), res}) }, }) defs = append(defs, Definition{ Name: "Print", - Usage: "`Print[expr1, expr2, ...]` prints the string representation of the expressions to the console and returns `Null`.", Bootstrap: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) < 2 { - return this - } - - context, contextPath := ActualStringFormArgs(es) - stringParams := ToStringParams{ - form: "OutputForm", - context: context, - contextPath: contextPath, - previousHead: "", - es: es, - } - for i := 1; i < len(this.Parts); i++ { - fmt.Printf("%s", this.Parts[i].StringForm(stringParams)) - } - fmt.Printf("\n") - return NewSymbol("System`Null") - }, }) defs = append(defs, Definition{ Name: "MessageName", }) defs = append(defs, Definition{ Name: "Trace", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } @@ -553,26 +556,26 @@ func GetSystemDefinitions() (defs []Definition) { // way. // Put system in trace mode: - es.trace = NewExpression([]Ex{NewSymbol("System`List")}) + es.SetTrace(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")})) // Evaluate first argument in trace mode: - this.Parts[1].Eval(es) - if es.trace != nil && len(es.trace.Parts) > 2 { + es.Eval(this.GetParts()[1]) + if es.GetTrace() != nil && len(es.GetTrace().GetParts()) > 2 { // Take system out of trace mode: - toReturn := es.trace.DeepCopy() - es.trace = nil + toReturn := es.GetTrace().DeepCopy() + es.SetTrace(nil) return toReturn } - es.trace = nil - return NewExpression([]Ex{NewSymbol("System`List")}) + es.SetTrace(nil) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) }, }) defs = append(defs, Definition{ Name: "N", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - return exprToN(es, this.Parts[1]) + return exprToN(es, this.GetParts()[1]) }, }) defs = append(defs, Definition{ @@ -581,68 +584,68 @@ func GetSystemDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ExpreduceFlatFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat"}, }) defs = append(defs, Definition{ Name: "ExpreduceOrderlessFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Orderless"}, }) defs = append(defs, Definition{ Name: "ExpreduceOneIdentityFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"OneIdentity"}, }) defs = append(defs, Definition{ Name: "ExpreduceFlatFn2", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat"}, }) defs = append(defs, Definition{ Name: "ExpreduceFlOrFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat", "Orderless"}, }) defs = append(defs, Definition{ Name: "ExpreduceFlOiFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat", "OneIdentity"}, }) defs = append(defs, Definition{ Name: "ExpreduceFlOrOiFn", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat", "Orderless", "OneIdentity"}, }) defs = append(defs, Definition{ Name: "ExpreduceLikePlus", Default: "0", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Attributes: []string{"Flat", "Listable", "NumericFunction", "OneIdentity", "Orderless"}, }) defs = append(defs, Definition{ Name: "Get", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - fileData, rawPath, ok := TryReadFile(this.Parts[1], es) + fileData, rawPath, ok := tryReadFile(this.GetParts()[1], es) if !ok { - return NewSymbol("System`$Failed") + return atoms.NewSymbol("System`$Failed") } return EvalInterpMany(fileData, rawPath, es) }, }) defs = append(defs, Definition{ Name: "Module", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { res, ok := applyModuleFn(this, es) if !ok { return this @@ -651,36 +654,36 @@ func GetSystemDefinitions() (defs []Definition) { }, }) defs = append(defs, Definition{ - Name: "Block", + Name: "Block", OmitDocumentation: true, }) defs = append(defs, Definition{ Name: "ESameTest", OmitDocumentation: true, - ExpreduceSpecific: true, + expreduceSpecific: true, Bootstrap: true, Attributes: []string{"HoldAll", "SequenceHold"}, }) defs = append(defs, Definition{ Name: "Hash", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } i := big.NewInt(0) - i.SetUint64(hashEx(this.Parts[1])) - return NewInteger(i) + i.SetUint64(hashEx(this.GetParts()[1])) + return atoms.NewInteger(i) }, }) defs = append(defs, Definition{ Name: "ReadList", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - fileData, rawPath, ok := TryReadFile(this.Parts[1], es) + fileData, rawPath, ok := tryReadFile(this.GetParts()[1], es) if !ok { - return NewSymbol("System`$Failed") + return atoms.NewSymbol("System`$Failed") } return ReadList(fileData, rawPath, es) }, @@ -705,8 +708,8 @@ func GetSystemDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Throw", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } es.Throw(this) @@ -715,13 +718,13 @@ func GetSystemDefinitions() (defs []Definition) { }) defs = append(defs, Definition{ Name: "Catch", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - res := this.Parts[1].Eval(es) + res := es.Eval(this.GetParts()[1]) if es.HasThrown() { - toReturn := es.thrown.Parts[1] + toReturn := es.Thrown().GetParts()[1] es.Throw(nil) return toReturn } @@ -731,26 +734,27 @@ func GetSystemDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "ExpreduceMaskNonConditional", OmitDocumentation: true, - ExpreduceSpecific: true, - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + expreduceSpecific: true, + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - return NewExpression([]Ex{ - NewSymbol("System`Hold"), - maskNonConditional(this.Parts[1]), + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Hold"), + maskNonConditional(this.GetParts()[1]), }) + }, }) defs = append(defs, Definition{ Name: "Unique", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) > 3 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) > 3 { return this } prefix := "$" - if len(this.Parts) == 2 { - asStr, isStr := this.Parts[1].(*String) + if len(this.GetParts()) == 2 { + asStr, isStr := this.GetParts()[1].(*atoms.String) if !isStr { return this } @@ -760,45 +764,75 @@ func GetSystemDefinitions() (defs []Definition) { if !ok { log.Fatal("Error snagging unique.") } - return NewSymbol(unique) + return atoms.NewSymbol(unique) }, }) defs = append(defs, Definition{ Name: "Sow", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { fmt.Println("Unsupported call to Sow.") return this } - res := this.Parts[1].Eval(es) - if es.reapSown != nil { - es.reapSown.appendEx(res) + res := es.Eval(this.GetParts()[1]) + if es.GetReapSown() != nil { + es.GetReapSown().AppendEx(res) } return res }, }) defs = append(defs, Definition{ Name: "Reap", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { fmt.Println("Unsupported call to Reap.") return this } - es.reapSown = E(S("List")) - res := this.Parts[1].Eval(es) - res = E(S("List"), res, E(S("List"), es.reapSown)) + es.SetReapSown(atoms.E(atoms.S("List"))) + res := es.Eval(this.GetParts()[1]) + res = atoms.E(atoms.S("List"), res, atoms.E(atoms.S("List"), es.GetReapSown())) // If I set this to nil, Int[((A + B*Cos[x])*(a + b*Sin[x])^-1), x] // will not work for an unknown reason. - es.reapSown = E(S("List")) + es.SetReapSown(atoms.E(atoms.S("List"))) return res }, }) defs = append(defs, Definition{ - Name: "Defer", + Name: "Defer", OmitDocumentation: true, }) defs = append(defs, Definition{Name: "Information"}) defs = append(defs, Definition{Name: "OutputStream"}) - defs = append(defs, Definition{Name: "WriteString"}) + defs = append(defs, Definition{ + Name: "WriteString", + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if this.Len() != 2 { + fmt.Println("Unsupported call to WriteString.") + return this + } + streamName, streamIndex, ok := parseOutputStream(this.GetPart(1)) + if !ok { + fmt.Println("Failed to parse OutputStream.") + return this + } + str, ok := this.GetPart(2).(*atoms.String) + if !ok { + fmt.Println("Failed to convert the second argument of WriteString to a string.") + return this + } + es.GetStreamManager().WriteString(streamName, streamIndex, str.GetValue()) + return atoms.NewSymbol("System`Null") + }, + }) + defs = append(defs, Definition{ + Name: "Streams", + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if this.Len() != 0 { + fmt.Println("Unsupported call to Streams.") + return this + } + return es.GetStreamManager().AsExpr() + }, + }) return } diff --git a/expreduce/builtin_time.go b/expreduce/builtin_time.go index 514161f..5c81a69 100644 --- a/expreduce/builtin_time.go +++ b/expreduce/builtin_time.go @@ -1,27 +1,32 @@ package expreduce -import "math/big" -import "time" +import ( + "math/big" + "time" -func GetTimeDefinitions() (defs []Definition) { + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func getTimeDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "UnixTime", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 1 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 1 { return this } - return NewInteger(big.NewInt(time.Now().UTC().Unix())) + return atoms.NewInteger(big.NewInt(time.Now().UTC().Unix())) }, }) defs = append(defs, Definition{ Name: "Pause", - legacyEvalFn: func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - nInt, nIsInt := this.Parts[1].(*Integer) - nFlt, nIsFlt := this.Parts[1].(*Flt) + nInt, nIsInt := this.GetParts()[1].(*atoms.Integer) + nFlt, nIsFlt := this.GetParts()[1].(*atoms.Flt) if !nIsInt && !nIsFlt { return this } @@ -34,7 +39,7 @@ func GetTimeDefinitions() (defs []Definition) { duration = time.Duration(asFlt * 1000000000) } time.Sleep(duration) - return NewSymbol("System`Null") + return atoms.NewSymbol("System`Null") }, }) return diff --git a/expreduce/builtin_trig.go b/expreduce/builtin_trig.go index 10ab70e..71604fb 100644 --- a/expreduce/builtin_trig.go +++ b/expreduce/builtin_trig.go @@ -1,57 +1,62 @@ package expreduce -import "math/big" -import "math" +import ( + "math" + "math/big" -func mathFnOneParam(fn func(float64) float64) func(*Expression, *EvalState) Ex { - return (func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func mathFnOneParam(fn func(float64) float64) func(expreduceapi.ExpressionInterface, expreduceapi.EvalStateInterface) expreduceapi.Ex { + return (func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - flt, ok := this.Parts[1].(*Flt) + flt, ok := this.GetParts()[1].(*atoms.Flt) if ok { flt64, acc := flt.Val.Float64() if acc == big.Exact { - return NewReal(big.NewFloat(fn(flt64))) + return atoms.NewReal(big.NewFloat(fn(flt64))) } } return this }) } -func GetTrigDefinitions() (defs []Definition) { +func getTrigDefinitions() (defs []Definition) { defs = append(defs, Definition{ Name: "Sin", legacyEvalFn: mathFnOneParam(math.Sin), - toString: simpleTeXToString("sin"), + toString: simpleTeXToString("sin"), }) defs = append(defs, Definition{ Name: "Cos", legacyEvalFn: mathFnOneParam(math.Cos), - toString: simpleTeXToString("cos"), + toString: simpleTeXToString("cos"), }) defs = append(defs, Definition{ Name: "Tan", legacyEvalFn: mathFnOneParam(math.Tan), - toString: simpleTeXToString("tan"), + toString: simpleTeXToString("tan"), }) defs = append(defs, Definition{ Name: "ArcTan", legacyEvalFn: mathFnOneParam(math.Atan), - toString: simpleTeXToString("tan^{-1}"), + toString: simpleTeXToString("tan^{-1}"), }) defs = append(defs, Definition{ Name: "Cot", - legacyEvalFn: mathFnOneParam(func(x float64) float64 {return 1/math.Tan(x)}), - toString: simpleTeXToString("cot"), + legacyEvalFn: mathFnOneParam(func(x float64) float64 { return 1 / math.Tan(x) }), + toString: simpleTeXToString("cot"), }) defs = append(defs, Definition{ - Name: "TrigExpand", + Name: "TrigExpand", OmitDocumentation: true, }) defs = append(defs, Definition{ - Name: "TrigReduce", + Name: "TrigReduce", OmitDocumentation: true, }) return diff --git a/expreduce/cas.go b/expreduce/cas.go deleted file mode 100644 index b8ee5ba..0000000 --- a/expreduce/cas.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:generate go-bindata -pkg expreduce -o resources.go resources/... - -package expreduce - -type ToStringFnType (func(*Expression, ToStringParams) (bool, string)) - -// The interface that fundamental types must implement. -type Ex interface { - Eval(es *EvalState) Ex - // TODO(corywalker): Deprecate this function. All stringification should go - // through StringForm. - String(es *EvalState) string - StringForm(params ToStringParams) string - IsEqual(b Ex, cl *CASLogger) string - DeepCopy() Ex - Copy() Ex - NeedsEval() bool - Hash() uint64 -} diff --git a/expreduce/cas_test.go b/expreduce/cas_test.go index d5ca9ec..f4cba35 100644 --- a/expreduce/cas_test.go +++ b/expreduce/cas_test.go @@ -3,11 +3,15 @@ package expreduce import ( "flag" "fmt" - "github.com/stretchr/testify/assert" "math/big" "regexp" - "testing" "sync" + "testing" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/timecounter" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/stretchr/testify/assert" ) var testmodules = flag.String("testmodules", "", @@ -27,7 +31,7 @@ func TestIncludedModules(t *testing.T) { var testSymEx = regexp.MustCompile(*testsyms) defSets := GetAllDefinitions() numTests := 0 - timeCounter := TimeCounterGroup{} + timeCounter := timecounter.Group{} timeCounter.Init() var mockT testing.T for _, defSet := range defSets { @@ -48,7 +52,7 @@ func TestIncludedModules(t *testing.T) { } EvalInterp(fmt.Sprintf("$Context = \"%s%sTestState`\"", defSet.Name, def.Name), es) def.AnnotateWithDynamic(es) - td := TestDesc{ + td := testDesc{ module: defSet.Name, def: def, } @@ -58,39 +62,39 @@ func TestIncludedModules(t *testing.T) { if *verbosetest { fmt.Println(test) } - test.Run(t, es, td) - i += 1 + test.run(t, es, td) + i++ } for _, test := range def.FurtherExamples { td.desc = fmt.Sprintf("%s.%s #%d", defSet.Name, def.Name, i) if *verbosetest { fmt.Println(test) } - test.Run(t, es, td) - i += 1 + test.run(t, es, td) + i++ } for _, test := range def.Tests { td.desc = fmt.Sprintf("%s.%s #%d", defSet.Name, def.Name, i) if *verbosetest { fmt.Println(test) } - test.Run(t, es, td) - i += 1 + test.run(t, es, td) + i++ } for _, test := range def.KnownFailures { td.desc = fmt.Sprintf("%s.%s #%d", defSet.Name, def.Name, i) if *verbosetest { fmt.Println(test) } - if test.Run(&mockT, es, td) { + if test.run(&mockT, es, td) { fmt.Printf("Previously failing test is now passing: %v\n", test) } - i += 1 + i++ } /*for _, test := range def.KnownDangerous { td.desc = fmt.Sprintf("%s.%s #%d", defSet.Name, def.Name, i) fmt.Printf("Running %v\n", test) - test.Run(t, es, td) + test.run(t, es, td) i += 1 }*/ numTests += i @@ -110,76 +114,82 @@ func TestLowLevel(t *testing.T) { fmt.Println("Testing low-level structs") es := NewEvalState() + stringParams := ActualStringFormArgsFull("InputForm", es) - lhs := NewExpression([]Ex{ - NewSymbol("System`Power"), - NewExpression([]Ex{ - NewSymbol("System`Plus"), - NewSymbol("Global`a"), - NewSymbol("Global`b"), - NewSymbol("Global`c"), + lhs := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Power"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Plus"), + atoms.NewSymbol("Global`a"), + atoms.NewSymbol("Global`b"), + atoms.NewSymbol("Global`c"), }), - NewInt(0), + + atoms.NewInt(0), }) - rule := NewExpression([]Ex{ - NewSymbol("System`Rule"), - NewExpression([]Ex{ - NewSymbol("System`Power"), - NewExpression([]Ex{ - NewSymbol("System`Blank"), + + rule := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Power"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Blank"), }), - NewInt(0), + + atoms.NewInt(0), }), - NewInt(99), + + atoms.NewInt(99), }) + for numi := 0; numi < 700000; numi++ { - Replace(lhs, rule, es) + replace(lhs, rule, es) } // Test basic float functionality - var f *Flt = NewReal(big.NewFloat(5.5)) - assert.Equal(t, "5.5", f.String(es)) - f.Eval(es) - assert.Equal(t, "5.5", f.String(es)) + var f *atoms.Flt = atoms.NewReal(big.NewFloat(5.5)) + assert.Equal(t, "5.5", f.StringForm(stringParams)) + es.Eval(f) + assert.Equal(t, "5.5", f.StringForm(stringParams)) // Test nested addition functionality - var a = NewExpression([]Ex{ - NewSymbol("System`Plus"), - NewExpression([]Ex{ - NewSymbol("System`Plus"), - NewReal(big.NewFloat(80)), - NewReal(big.NewFloat(3)), + var a = atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Plus"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Plus"), + atoms.NewReal(big.NewFloat(80)), + atoms.NewReal(big.NewFloat(3)), }), - NewReal(big.NewFloat(2)), - NewReal(big.NewFloat(2.5)), + atoms.NewReal(big.NewFloat(2)), + atoms.NewReal(big.NewFloat(2.5)), }) // Test equality checking - assert.Equal(t, "EQUAL_TRUE", (NewReal(big.NewFloat(99))).IsEqual(NewReal(big.NewFloat(99)), &es.CASLogger)) - assert.Equal(t, "EQUAL_FALSE", (NewReal(big.NewFloat(99))).IsEqual(NewReal(big.NewFloat(98)), &es.CASLogger)) - assert.Equal(t, "EQUAL_TRUE", (NewSymbol("System`x")).IsEqual(NewSymbol("System`x"), &es.CASLogger)) - assert.Equal(t, "EQUAL_UNK", (NewSymbol("System`x")).IsEqual(NewSymbol("System`X"), &es.CASLogger)) - assert.Equal(t, "EQUAL_UNK", (NewSymbol("System`x")).IsEqual(NewSymbol("System`y"), &es.CASLogger)) + assert.Equal(t, "EQUAL_TRUE", (atoms.NewReal(big.NewFloat(99))).IsEqual(atoms.NewReal(big.NewFloat(99)))) + assert.Equal(t, "EQUAL_FALSE", (atoms.NewReal(big.NewFloat(99))).IsEqual(atoms.NewReal(big.NewFloat(98)))) + assert.Equal(t, "EQUAL_TRUE", (atoms.NewSymbol("System`x")).IsEqual(atoms.NewSymbol("System`x"))) + assert.Equal(t, "EQUAL_UNK", (atoms.NewSymbol("System`x")).IsEqual(atoms.NewSymbol("System`X"))) + assert.Equal(t, "EQUAL_UNK", (atoms.NewSymbol("System`x")).IsEqual(atoms.NewSymbol("System`y"))) // Test evaluation - newa := a.Eval(es) - assert.Equal(t, "87.5", newa.String(es)) + newa := es.Eval(a) + assert.Equal(t, "87.5", newa.StringForm(stringParams)) // Test basic Symbol functionality - var v *Symbol = NewSymbol("System`x") - assert.Equal(t, "x", v.String(es)) - v.Eval(es) - assert.Equal(t, "x", v.String(es)) + var v *atoms.Symbol = atoms.NewSymbol("System`x") + assert.Equal(t, "x", v.StringForm(stringParams)) + es.Eval(v) + assert.Equal(t, "x", v.StringForm(stringParams)) - assert.Equal(t, "(a + b + c + d + e + f)", EasyRun("a + b + c +d +e +f", es)) - assert.Equal(t, "(a*b*c*d*e*f)", EasyRun("a * b * c *d *e *f", es)) + casAssertSame(t, es, "(a + b + c + d + e + f)", "a + b + c +d +e +f") + casAssertSame(t, es, "(a*b*c*d*e*f)", "a * b * c *d *e *f") - CasAssertSame(t, es, "2", "iubjndxuier = 2") - _, containsTest := es.defined.Get("Global`iubjndxuier") + casAssertSame(t, es, "2", "iubjndxuier = 2") + _, containsTest := es.GetDefinedMap().Get("Global`iubjndxuier") assert.True(t, containsTest) es.ClearAll() - _, containsTest = es.defined.Get("Global`iubjndxuier") + _, containsTest = es.GetDefinedMap().Get("Global`iubjndxuier") assert.False(t, containsTest) // Test raw recursion speed @@ -192,11 +202,12 @@ func TestDeepCopy(t *testing.T) { // So that we can print the values. Not very necessary. es := NewEvalState() + stringParams := ActualStringFormArgsFull("InputForm", es) // Test deepcopy - var t1 = NewSymbol("System`x") + var t1 = atoms.NewSymbol("System`x") t2 := *t1 - t3 := t1.DeepCopy().(*Symbol) + t3 := t1.DeepCopy().(*atoms.Symbol) assert.Equal(t, "System`x", t1.Name) assert.Equal(t, "System`x", t2.Name) assert.Equal(t, "System`x", t3.Name) @@ -206,17 +217,17 @@ func TestDeepCopy(t *testing.T) { assert.Equal(t, "y", t2.Name) assert.Equal(t, "z", t3.Name) - var t4 = NewReal(big.NewFloat(2)) + var t4 = atoms.NewReal(big.NewFloat(2)) t5 := *t4 - t6 := t4.DeepCopy().(*Flt) - assert.Equal(t, "2.", t4.String(es)) - assert.Equal(t, "2.", t5.String(es)) - assert.Equal(t, "2.", t6.String(es)) + t6 := t4.DeepCopy().(*atoms.Flt) + assert.Equal(t, "2.", t4.StringForm(stringParams)) + assert.Equal(t, "2.", t5.StringForm(stringParams)) + assert.Equal(t, "2.", t6.StringForm(stringParams)) t5.Val.Add(t5.Val, big.NewFloat(2)) t6.Val.Add(t6.Val, big.NewFloat(3)) - assert.Equal(t, "4.", t4.String(es)) // Because we used the wrong copy method - assert.Equal(t, "4.", t5.String(es)) - assert.Equal(t, "5.", t6.String(es)) + assert.Equal(t, "4.", t4.StringForm(stringParams)) // Because we used the wrong copy method + assert.Equal(t, "4.", t5.StringForm(stringParams)) + assert.Equal(t, "5.", t6.StringForm(stringParams)) } func TestConcurrency(t *testing.T) { @@ -226,18 +237,18 @@ func TestConcurrency(t *testing.T) { es1 := NewEvalState() es2 := NewEvalState() - CasAssertSame(t, es1, "3", "1+2") - CasAssertSame(t, es2, "3", "1+2") + casAssertSame(t, es1, "3", "1+2") + casAssertSame(t, es2, "3", "1+2") var wg sync.WaitGroup // Test concurrent evals on different EvalStates. for i := 0; i < 10; i++ { wg.Add(1) - go func (t *testing.T) { + go func(t *testing.T) { defer wg.Done() esTest := NewEvalState() - CasAssertSame(t, esTest, "3", "1+2") + casAssertSame(t, esTest, "3", "1+2") }(t) } wg.Wait() @@ -245,9 +256,9 @@ func TestConcurrency(t *testing.T) { // Test read-only concurrent evals on the same EvalState. for i := 0; i < 100; i++ { wg.Add(1) - go func (t *testing.T, es *EvalState) { + go func(t *testing.T, es expreduceapi.EvalStateInterface) { defer wg.Done() - CasAssertSame(t, es, "2x", "D[x^2, x]") + casAssertSame(t, es, "2x", "D[x^2, x]") }(t, es1) } wg.Wait() @@ -255,7 +266,7 @@ func TestConcurrency(t *testing.T) { // Test writing concurrent evals on the same EvalState. for i := 0; i < 1000; i++ { wg.Add(1) - go func (t *testing.T, i int, es *EvalState) { + go func(t *testing.T, i int, es expreduceapi.EvalStateInterface) { defer wg.Done() EvalInterp(fmt.Sprintf("testVar := %v", i), es) }(t, i, es1) @@ -265,7 +276,7 @@ func TestConcurrency(t *testing.T) { // Test concurrent MarkSeen. for i := 0; i < 1000; i++ { wg.Add(1) - go func (t *testing.T, i int, es *EvalState) { + go func(t *testing.T, i int, es expreduceapi.EvalStateInterface) { defer wg.Done() es.MarkSeen("uniqueIdentifierForMarkSeen") }(t, i, es1) diff --git a/expreduce/caslogger.go b/expreduce/caslogger.go deleted file mode 100644 index c0670af..0000000 --- a/expreduce/caslogger.go +++ /dev/null @@ -1,82 +0,0 @@ -package expreduce - -import ( - "bytes" - "github.com/op/go-logging" - "os" - "runtime/debug" - "sync" -) - -var format = logging.MustStringFormatter( - `%{color}%{time:15:04:05.000} %{callpath} â–¶ %{id:03x}%{color:reset} %{message}`, -) -var goLoggingMutex = &sync.Mutex{} - -type CASLogger struct { - _log *logging.Logger - leveled logging.LeveledBackend - debugState bool - isProfiling bool -} - -func (this *CASLogger) Debugf(fmt string, args ...interface{}) { - if this.debugState { - //this._log.Debugf(this.Pre() + fmt, args...) - this._log.Debugf(fmt, args...) - } -} - -func (this *CASLogger) Infof(fmt string, args ...interface{}) { - if this.debugState { - //this._log.Infof(this.Pre() + fmt, args...) - this._log.Infof(fmt, args...) - } -} - -func (this *CASLogger) Errorf(fmt string, args ...interface{}) { - this._log.Errorf(fmt, args...) -} - -func (this *CASLogger) DebugOn(level logging.Level) { - this.leveled.SetLevel(level, "") - this.debugState = true - this.SetProfiling(true) -} - -func (this *CASLogger) DebugOff() { - this.leveled.SetLevel(logging.ERROR, "") - this.debugState = false - this.SetProfiling(false) -} - -func (this *CASLogger) DebugState() bool { - return this.debugState -} - -func (this *CASLogger) SetProfiling(profiling bool) { - this.isProfiling = profiling -} - -func (this *CASLogger) Pre() string { - toReturn := "" - if this.leveled.GetLevel("") != logging.ERROR { - depth := (bytes.Count(debug.Stack(), []byte{'\n'}) - 15) / 2 - for i := 0; i < depth; i++ { - toReturn += " " - } - } - return toReturn -} - -func (this *CASLogger) SetUpLogging() { - // go-logging appears to not be thread safe, so we have a mutex when - // configuring the logging. - goLoggingMutex.Lock() - this._log = logging.MustGetLogger("example") - backend := logging.NewLogBackend(os.Stderr, "", 0) - formatter := logging.NewBackendFormatter(backend, format) - this.leveled = logging.AddModuleLevel(formatter) - logging.SetBackend(this.leveled) - goLoggingMutex.Unlock() -} diff --git a/expreduce/definition.go b/expreduce/definition.go index eaa9e6d..faa7b78 100644 --- a/expreduce/definition.go +++ b/expreduce/definition.go @@ -1,54 +1,45 @@ package expreduce -import "strings" +import ( + "strings" -type DownValue struct { - rule *Expression - specificity int -} - -type Def struct { - downvalues []DownValue - attributes Attributes - defaultExpr Ex - - // A function defined here will override downvalues. - legacyEvalFn (func(*Expression, *EvalState) Ex) -} + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) -func (def *Def) StringForm(defSym *Symbol, params ToStringParams) string { +func stringForm(def *expreduceapi.Def, defSym *atoms.Symbol, params expreduceapi.ToStringParams) string { var buffer []string - attrs := def.attributes.toStrings() + attrs := atoms.AttrsToStrings(&def.Attributes) if len(attrs) > 0 { - e := E( - S("Set"), - E( - S("Attributes"), + e := atoms.E( + atoms.S("Set"), + atoms.E( + atoms.S("Attributes"), defSym, ), - def.attributes.toSymList(), + atoms.AttrsToSymList(&def.Attributes), ) buffer = append(buffer, e.StringForm(params)) } - for _, dv := range def.downvalues { - e := E( - S("SetDelayed"), - dv.rule.Parts[1].(*Expression).Parts[1], - dv.rule.Parts[2], + for _, dv := range def.Downvalues { + e := atoms.E( + atoms.S("SetDelayed"), + dv.Rule.GetParts()[1].(expreduceapi.ExpressionInterface).GetParts()[1], + dv.Rule.GetParts()[2], ) buffer = append(buffer, e.StringForm(params)) } - if def.defaultExpr != nil { - e := E( - S("Set"), - E( - S("Default"), + if def.DefaultExpr != nil { + e := atoms.E( + atoms.S("Set"), + atoms.E( + atoms.S("Default"), defSym, ), - def.defaultExpr, + def.DefaultExpr, ) buffer = append(buffer, e.StringForm(params)) } diff --git a/expreduce/definition_map.go b/expreduce/definition_map.go index 4eab457..1c46106 100644 --- a/expreduce/definition_map.go +++ b/expreduce/definition_map.go @@ -1,32 +1,33 @@ package expreduce import ( + "github.com/corywalker/expreduce/pkg/expreduceapi" "github.com/orcaman/concurrent-map" ) -type definitionMap struct { - internalMap cmap.ConcurrentMap +type threadSafeDefinitionMap struct { + internalMap cmap.ConcurrentMap } -func newDefinitionMap() definitionMap { - var dm definitionMap +func newDefinitionMap() *threadSafeDefinitionMap { + var dm threadSafeDefinitionMap dm.internalMap = cmap.New() - return dm + return &dm } -func (dm definitionMap) Set(key string, value Def) { +func (dm threadSafeDefinitionMap) Set(key string, value expreduceapi.Def) { dm.internalMap.Set(key, value) } -func (dm definitionMap) Get(key string) (Def, bool) { +func (dm threadSafeDefinitionMap) Get(key string) (expreduceapi.Def, bool) { if !dm.internalMap.Has(key) { - return Def{}, false + return expreduceapi.Def{}, false } value, ok := dm.internalMap.Get(key) - return value.(Def), ok + return value.(expreduceapi.Def), ok } -func (dm definitionMap) GetDef(key string) Def { +func (dm threadSafeDefinitionMap) GetDef(key string) expreduceapi.Def { value, ok := dm.Get(key) if !ok { panic("Reading missing value in GetDef()!") @@ -34,27 +35,27 @@ func (dm definitionMap) GetDef(key string) Def { return value } -func (dm definitionMap) LockKey(key string) { +func (dm threadSafeDefinitionMap) LockKey(key string) { shard := dm.internalMap.GetShard(key) shard.Lock() } -func (dm definitionMap) UnlockKey(key string) { +func (dm threadSafeDefinitionMap) UnlockKey(key string) { shard := dm.internalMap.GetShard(key) shard.Unlock() } -func (dm definitionMap) CopyDefs() definitionMap { +func (dm threadSafeDefinitionMap) CopyDefs() expreduceapi.DefinitionMap { out := newDefinitionMap() for mapTuple := range dm.internalMap.IterBuffered() { - k, v := mapTuple.Key, mapTuple.Val.(Def) - newDef := Def{} - for _, dv := range v.downvalues { - newDv := DownValue{ - rule: dv.rule.DeepCopy().(*Expression), - specificity: dv.specificity, + k, v := mapTuple.Key, mapTuple.Val.(expreduceapi.Def) + newDef := expreduceapi.Def{} + for _, dv := range v.Downvalues { + newDv := expreduceapi.DownValue{ + Rule: dv.Rule.DeepCopy().(expreduceapi.ExpressionInterface), + Specificity: dv.Specificity, } - newDef.downvalues = append(newDef.downvalues, newDv) + newDef.Downvalues = append(newDef.Downvalues, newDv) } out.Set(k, newDef) } diff --git a/expreduce/easyrun.go b/expreduce/easyrun.go new file mode 100644 index 0000000..0683db5 --- /dev/null +++ b/expreduce/easyrun.go @@ -0,0 +1,56 @@ +package expreduce + +import ( + "bytes" + "fmt" + "strings" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func EvalInterp(src string, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + return es.Eval(parser.Interp(src, es)) +} + +// EasyRun evaluates a string of Expreduce code and returns the result as a +// string. +func EasyRun(in string, es expreduceapi.EvalStateInterface) string { + context, contextPath := actualStringFormArgs(es) + stringParams := expreduceapi.ToStringParams{ + Form: "InputForm", + Context: context, + ContextPath: contextPath, + Esi: es, + } + return EvalInterp(in, es).StringForm(stringParams) +} + +func EvalInterpMany(doc string, fn string, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + buf := bytes.NewBufferString(doc) + var lastExpr expreduceapi.Ex = atoms.NewSymbol("System`Null") + expr, err := parser.InterpBuf(buf, fn, es) + for err == nil { + lastExpr = es.Eval(expr) + expr, err = parser.InterpBuf(buf, fn, es) + } + if !strings.HasSuffix(err.Error(), "unexpected EOF, invalid empty input") { + fmt.Printf("Syntax::sntx: %v.\nWhile parsing: %v\n\n\n", err, buf.String()[:100]) + } + return lastExpr +} + +func ReadList(doc string, fn string, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + buf := bytes.NewBufferString(doc) + l := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + expr, err := parser.InterpBuf(buf, fn, es) + for err == nil { + l.AppendEx(es.Eval(expr)) + expr, err = parser.InterpBuf(buf, fn, es) + } + if !strings.HasSuffix(err.Error(), "unexpected EOF, invalid empty input") { + fmt.Printf("Syntax::sntx: %v.\nWhile parsing: %v\n\n\n", err, buf.String()[:100]) + } + return l +} diff --git a/expreduce/eval.go b/expreduce/eval.go new file mode 100644 index 0000000..d53706e --- /dev/null +++ b/expreduce/eval.go @@ -0,0 +1,436 @@ +package expreduce + +import ( + "flag" + "fmt" + "math/big" + "sort" + "time" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/expreduce/timecounter" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +var printevals = flag.Bool("printevals", false, "") +var checkhashes = flag.Bool("checkhashes", false, "") + +// Eval evaluates an expression and returns the resulting expression. +func (es *EvalState) Eval(expr expreduceapi.Ex) expreduceapi.Ex { + if asExpression, ok := expr.(*atoms.Expression); ok { + return es.evalExpression(asExpression) + } + if asComplex, ok := expr.(*atoms.Complex); ok { + return es.evalComplex(asComplex) + } + if asRational, ok := expr.(*atoms.Rational); ok { + return es.evalRational(asRational) + } + if asSymbol, ok := expr.(*atoms.Symbol); ok { + return es.evalSymbol(asSymbol) + } + // Other atoms do not need any evaluation logic. + return expr +} + +func (es *EvalState) evalComplex(this *atoms.Complex) expreduceapi.Ex { + this.Re = es.Eval(this.Re) + this.Im = es.Eval(this.Im) + if atoms.IsSameQ(this.Im, atoms.NewInt(0)) { + return this.Re + } + this.SetNeedsEval(false) + return this +} + +func (es *EvalState) evalExpression(this *atoms.Expression) expreduceapi.Ex { + var origEx expreduceapi.Ex = this + + lastExHash := uint64(0) + var lastEx expreduceapi.Ex = this + currExHash := hashEx(this) + if currExHash == this.EvaledHash { + return this + } + var currEx expreduceapi.Ex = this + insideDefinition := false + for currExHash != lastExHash { + lastExHash = currExHash + curr, isExpr := currEx.(*atoms.Expression) + if *checkhashes { + if isExpr && curr.EvaledHash != 0 && currExHash != curr.EvaledHash { + fmt.Printf("invalid cache: %v. Used to be %v\n", curr, lastEx) + } + lastEx = currEx + } + + if isExpr && insideDefinition { + retVal, isReturn := tryReturnValue(curr, origEx, es) + if isReturn { + return retVal + } + } + if isExpr && currExHash == curr.EvaledHash { + return curr + } + + if *printevals { + fmt.Printf("Evaluating %v.\n", currEx) + } + // Transition to the right Eval() if this is no longer an Expression + if !isExpr { + toReturn := es.Eval(currEx) + // Handle tracing + if es.GetTrace() != nil && !es.IsFrozen() { + toAppend := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`HoldForm"), + toReturn.DeepCopy(), + }) + + //fmt.Printf("Beginning: appending %v\n", toAppend.StringForm("FullForm")) + es.GetTrace().AppendEx(toAppend) + } + return toReturn + } + + currStr := "" + currHeadStr := "" + started := int64(0) + if es.IsProfiling() { + currStr = curr.StringForm(es.profilingToStringParams) + currHeadStr = curr.GetParts()[0].StringForm(es.profilingToStringParams) + started = time.Now().UnixNano() + } + + // Start by evaluating each argument + headSym, headIsSym := &atoms.Symbol{}, false + attrs := expreduceapi.Attributes{} + if len(curr.GetParts()) > 0 { + headSym, headIsSym = curr.GetParts()[0].(*atoms.Symbol) + } + if headIsSym { + attrs = headSym.Attrs(es.GetDefinedMap()) + } + if attrs.NumericFunction { + propagated, changed := curr.PropagateConditionals() + if changed { + return es.Eval(propagated) + } + } + for i := range curr.GetParts() { + if headIsSym && i == 1 && attrs.HoldFirst { + continue + } + if headIsSym && i > 1 && attrs.HoldRest { + continue + } + if headIsSym && (attrs.HoldAll || attrs.HoldAllComplete) { + continue + } + + // Handle tracing + traceBak := es.GetTrace() + if es.GetTrace() != nil && !es.IsFrozen() { + es.SetTrace(atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")})) + } + oldHash := curr.GetParts()[i].Hash() + //fmt.Println(curr, i) + curr.GetParts()[i] = es.Eval(curr.GetParts()[i]) + if es.HasThrown() { + return es.Thrown() + } + if oldHash != curr.GetParts()[i].Hash() { + curr.CachedHash = 0 + } + if es.GetTrace() != nil && !es.IsFrozen() { + if len(es.GetTrace().GetParts()) > 2 { + // The DeepCopy here doesn't seem to affect anything, but + // should be good to have. + //fmt.Printf("Argument eval: appending %v\n", es.trace.DeepCopy().StringForm("FullForm")) + traceBak.AppendEx(es.GetTrace().DeepCopy()) + } + es.SetTrace(traceBak) + } + } + + // Handle tracing + if es.GetTrace() != nil && !es.IsFrozen() { + toAppend := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`HoldForm"), + currEx.DeepCopy(), + }) + + if !atoms.IsSameQ(es.GetTrace().GetParts()[len(es.GetTrace().GetParts())-1], toAppend) { + //fmt.Printf("Beginning: appending %v\n", toAppend.StringForm("FullForm")) + es.GetTrace().AppendEx(toAppend) + } + } + + // If any of the parts are Sequence, merge them with parts + if headIsSym { + if !attrs.SequenceHold && !attrs.HoldAllComplete { + curr = mergeSequences(curr, es, "System`Sequence", false) + } + } else { + curr = mergeSequences(curr, es, "System`Sequence", false) + } + if !attrs.HoldAllComplete { + curr = mergeSequences(curr, es, "System`Evaluate", true) + } + curr = mergeSequences(curr, es, "System`Unevaluated", false) + // In case curr changed + currEx = curr + + pureFunction, isPureFunction := atoms.HeadAssertion(curr.GetParts()[0], "System`Function") + if headIsSym { + if attrs.Flat { + curr = mergeSequences(curr, es, headSym.Name, false) + } + if attrs.Orderless { + sort.Sort(curr) + curr.CachedHash = 0 + } + if attrs.Listable { + var changed bool + currEx, changed = threadExpr(curr) + if changed { + currExHash = hashEx(currEx) + continue + } + } + headStr := headSym.Name + + legacyEvalFn, hasLegacyEvalFn := (expreduceapi.EvalFnType)(nil), false + if _, inDefined := es.GetDefinedMap().Get(headStr); inDefined { + if es.GetDefinedMap().GetDef(headStr).LegacyEvalFn != nil { + hasLegacyEvalFn = true + legacyEvalFn = es.GetDefinedMap().GetDef(headStr).LegacyEvalFn + } + } + unchanged := true + if hasLegacyEvalFn { + currEx = legacyEvalFn(curr, es) + // TODO: I could potentially have the legacyevalfn return this. + unchanged = atoms.IsSameQ(currEx, curr) + } + if unchanged { + theRes, isDefined, def := es.GetDef(headStr, curr) + if isDefined { + //fmt.Printf("%v, %v, %v\n", headStr, curr, theRes) + es.Infof("Def: %v â–¶ %v â–¶ using %v â–¶ from %s head", currEx, theRes, def, headStr) + currEx = theRes + insideDefinition = true + } + } + } else if isPureFunction { + currEx = evalFunction(pureFunction, es, curr.GetParts()[1:]) + } + currExHash = hashEx(currEx) + + // Handle end of profiling + if es.IsProfiling() { + elapsed := float64(time.Now().UnixNano()-started) / 1000000000 + es.GetTimeCounter().AddTime(timecounter.CounterGroupEvalTime, currStr, elapsed) + es.GetTimeCounter().AddTime(timecounter.CounterGroupHeadEvalTime, currHeadStr, elapsed) + } + } + curr, isExpr := currEx.(*atoms.Expression) + if isExpr { + curr.SetNeedsEval(false) + curr.EvaledHash = currExHash + } + return currEx +} + +func (es *EvalState) evalRational(this *atoms.Rational) expreduceapi.Ex { + if this.Num.Cmp(big.NewInt(0)) == 0 && this.Den.Cmp(big.NewInt(0)) == 0 { + return atoms.NewSymbol("System`Indeterminate") + } + if this.Den.Cmp(big.NewInt(0)) == 0 { + return atoms.NewSymbol("System`ComplexInfinity") + } + if this.Num.Cmp(big.NewInt(0)) == 0 { + return atoms.NewInteger(big.NewInt(0)) + } + negNum := this.Num.Cmp(big.NewInt(0)) == -1 + negDen := this.Den.Cmp(big.NewInt(0)) == -1 + negateRes := negNum != negDen + absNum := big.NewInt(0) + absNum.Abs(this.Num) + absDen := big.NewInt(0) + absDen.Abs(this.Den) + + gcd := big.NewInt(0) + gcd.GCD(nil, nil, absNum, absDen) + absNum.Div(absNum, gcd) + absDen.Div(absDen, gcd) + + if absDen.Cmp(big.NewInt(1)) == 0 { + if !negateRes { + return atoms.NewInteger(absNum) + } + return atoms.NewInteger(absNum.Neg(absNum)) + } + + if !negateRes { + this.Num.Set(absNum) + this.Den.Set(absDen) + this.SetNeedsEval(false) + return this + } + this.Num.Set(absNum.Neg(absNum)) + this.Den.Set(absDen) + this.SetNeedsEval(false) + return this +} + +func (es *EvalState) evalSymbol(this *atoms.Symbol) expreduceapi.Ex { + //definition, isdefined := es.defined[this.Name] + definition, isdefined, _ := es.GetDef(this.Name, this) + if isdefined { + // We must call Eval because, at this point, the expression has broken + // out of the evaluation loop. + toReturn := definition + // To handle the case where we set a variable to itself. + if sym, isSym := definition.(*atoms.Symbol); isSym { + if sym.Name == this.Name { + return toReturn + } + } + toReturn = es.Eval(toReturn) + retVal, isReturn := tryReturnValue(toReturn, nil, es) + if isReturn { + return retVal + } + return toReturn + } + return this +} + +func tryReturnValue(e expreduceapi.Ex, origEx expreduceapi.Ex, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { + if es.IsInterrupted() { + if origEx != nil { + fmt.Println(origEx) + } + return atoms.NewSymbol("System`$Aborted"), true + } + asReturn, isReturn := atoms.HeadAssertion(e, "System`Return") + if !isReturn { + return nil, false + } + if len(asReturn.GetParts()) >= 2 { + return asReturn.GetParts()[1], true + } + return atoms.NewSymbol("System`Null"), true +} + +// Is this causing issues by not creating a copy as we modify? Actually it is +// creating copies. +func mergeSequences(this *atoms.Expression, es expreduceapi.EvalStateInterface, headStr string, shouldEval bool) *atoms.Expression { + encounteredSeq := false + for _, e := range this.GetParts() { + if _, isseq := atoms.HeadAssertion(e, headStr); isseq { + encounteredSeq = true + break + } + } + // Only build a new expression if the expression actually has a sequence + // needing merging. + if !encounteredSeq { + return this + } + + // TODO: I should not be attempting to merge the head if it happens to be + // a Sequence type. This is very similar to the flatten function. Perhaps + // it should be combined. This version is not recursive, and it does not + // accept level depths. It is a specific case of Flatten. + res := atoms.NewEmptyExpression() + for _, e := range this.GetParts() { + seq, isseq := atoms.HeadAssertion(e, headStr) + if isseq { + for _, seqPart := range seq.GetParts()[1:] { + if shouldEval { + res.AppendEx(es.Eval(seqPart)) + } else { + res.AppendEx(seqPart) + } + } + } else { + res.AppendEx(e) + } + } + return res +} + +func evalFunction(this *atoms.Expression, es expreduceapi.EvalStateInterface, args []expreduceapi.Ex) expreduceapi.Ex { + if len(this.GetParts()) == 2 { + toReturn := this.GetParts()[1].DeepCopy() + for i, arg := range args { + toReturn = replaceAll(toReturn, + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Slot"), + atoms.NewInteger(big.NewInt(int64(i + 1))), + }), + + arg, + }), + + es, matcher.EmptyPD(), "System`Function") + } + return toReturn + } else if len(this.GetParts()) == 3 { + repSym, ok := this.GetParts()[1].(*atoms.Symbol) + if !ok { + return this + } + toReturn := this.GetParts()[2].DeepCopy() + toReturn = replaceAll(toReturn, + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), + repSym, + args[0], + }), + + es, matcher.EmptyPD(), "System`Function") + return toReturn + } + return this +} + +func exprReplaceAll(this expreduceapi.ExpressionInterface, r expreduceapi.ExpressionInterface, stopAtHead string, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + es.Debugf("In Expression.ReplaceAll. First trying IsMatchQ(this, r.Parts[1], es).") + es.Debugf("Rule r is: %s", r) + + matchq, matches := matcher.IsMatchQ(this, r.GetParts()[1], matcher.EmptyPD(), es) + if matchq { + es.Debugf("After MatchQ, rule is: %s", r) + es.Debugf("MatchQ succeeded. Returning r.Parts[2]: %s", r.GetParts()[2]) + return matcher.ReplacePD(r.GetParts()[2].DeepCopy(), es, matches) + } + + thisSym, thisSymOk := this.GetParts()[0].(*atoms.Symbol) + lhsExpr, lhsExprOk := r.GetParts()[1].(*atoms.Expression) + if lhsExprOk { + otherSym, otherSymOk := lhsExpr.GetParts()[0].(*atoms.Symbol) + if thisSymOk && otherSymOk { + if thisSym.Name == otherSym.Name { + attrs := thisSym.Attrs(es.GetDefinedMap()) + if attrs.Flat { + return flatReplace(this, lhsExpr, r.GetParts()[2], attrs.Orderless, es) + } + } + } + } + + maybeChanged := atoms.NewEmptyExpression() + for i := range this.GetParts() { + maybeChanged.AppendEx(replaceAll(this.GetParts()[i], r, es, matcher.EmptyPD(), stopAtHead)) + } + if hashEx(maybeChanged) != hashEx(this) { + return maybeChanged + } + return this +} diff --git a/expreduce/evalstate.go b/expreduce/evalstate.go index 1b95c02..ea0434e 100644 --- a/expreduce/evalstate.go +++ b/expreduce/evalstate.go @@ -7,78 +7,101 @@ import ( "os/signal" "strings" "time" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/logging" + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/corywalker/expreduce/expreduce/streammanager" + "github.com/corywalker/expreduce/expreduce/timecounter" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) +// EvalState keeps track of the state of the Expreduce interpreter. It contains +// all definitions and any evaluation bits. type EvalState struct { // Embedded type for logging - CASLogger + logging.CASLogger + + defined expreduceapi.DefinitionMap + trace expreduceapi.ExpressionInterface + NoInit bool + timeCounter timecounter.Group + freeze bool + thrown expreduceapi.ExpressionInterface + reapSown expreduceapi.ExpressionInterface + interrupted bool + toStringFns map[string]expreduceapi.ToStringFnType + profilingToStringParams expreduceapi.ToStringParams + streamManager expreduceapi.StreamManager +} - defined definitionMap - trace *Expression - NoInit bool - timeCounter TimeCounterGroup - freeze bool - thrown *Expression - reapSown *Expression - interrupted bool - toStringFns map[string]ToStringFnType +func (es *EvalState) GetDefined(name string) (expreduceapi.Def, bool) { + return es.GetDefinedMap().Get(name) } -func (this *EvalState) Load(def Definition) { - // TODO: deprecate most of this. We should be using .m files now. - def.Name = this.GetStringDef("System`$Context", "") + def.Name - this.MarkSeen(def.Name) - EvalInterp("$Context = \"Private`\"", this) +func (es *EvalState) GetStringFn(headStr string) (expreduceapi.ToStringFnType, bool) { + fn, ok := es.toStringFns[headStr] + return fn, ok +} + +func (es *EvalState) load(def Definition) { + // TODO: deprecate most of es. We should be using .m files now. + def.Name = es.GetStringDef("System`$Context", "") + def.Name + es.MarkSeen(def.Name) + EvalInterp("$Context = \"Private`\"", es) if len(def.Usage) > 0 { - (NewExpression([]Ex{ - NewSymbol("System`SetDelayed"), - NewExpression([]Ex{ - NewSymbol("System`MessageName"), - NewSymbol(def.Name), - NewString("usage"), + + es.Eval((atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`SetDelayed"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`MessageName"), + atoms.NewSymbol(def.Name), + atoms.NewString("usage"), }), - NewString(def.Usage), - })).Eval(this) + atoms.NewString(def.Usage), + }))) + } - newDef, foundDef := this.defined.Get(def.Name) + newDef, foundDef := es.defined.Get(def.Name) if !foundDef { - newDef = Def{} + newDef = expreduceapi.Def{} } if def.legacyEvalFn != nil { - newDef.legacyEvalFn = def.legacyEvalFn + newDef.LegacyEvalFn = def.legacyEvalFn } protectedAttrs := append(def.Attributes, "Protected") - newDef.attributes = stringsToAttributes(protectedAttrs) + newDef.Attributes = atoms.StringsToAttributes(protectedAttrs) if def.Default != "" { - newDef.defaultExpr = Interp(def.Default, this) + newDef.DefaultExpr = parser.Interp(def.Default, es) } if def.toString != nil { - this.toStringFns[def.Name] = def.toString + es.toStringFns[def.Name] = def.toString } - this.defined.Set(def.Name, newDef) - EvalInterp("$Context = \"System`\"", this) + es.defined.Set(def.Name, newDef) + EvalInterp("$Context = \"System`\"", es) } func (es *EvalState) Init(loadAllDefs bool) { es.defined = newDefinitionMap() - es.toStringFns = make(map[string]ToStringFnType) + es.streamManager = streammanager.NewStreamManager() + es.toStringFns = make(map[string]expreduceapi.ToStringFnType) // These are fundamental symbols that affect even the parsing of // expressions. We must define them before even the bootstrap definitions. - es.Define(NewSymbol("System`$Context"), NewString("System`")) - es.Define(NewSymbol("System`$ContextPath"), NewExpression([]Ex{ - NewSymbol("System`List"), - NewString("System`"), + es.Define(atoms.NewSymbol("System`$Context"), atoms.NewString("System`")) + es.Define(atoms.NewSymbol("System`$ContextPath"), atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), + atoms.NewString("System`"), })) es.timeCounter.Init() es.NoInit = !loadAllDefs if !es.NoInit { // Init modules - // Mark all core builtins as seen in the System context: + // Mark all core builtins as seen in the System Context: es.MarkSeen("System`Symbol") es.MarkSeen("System`Integer") es.MarkSeen("System`Rational") @@ -208,7 +231,7 @@ func (es *EvalState) Init(loadAllDefs bool) { for _, defSet := range GetAllDefinitions() { for _, def := range defSet.Defs { if def.Bootstrap { - es.Load(def) + es.load(def) } } } @@ -216,7 +239,7 @@ func (es *EvalState) Init(loadAllDefs bool) { for _, defSet := range GetAllDefinitions() { for _, def := range defSet.Defs { if !def.Bootstrap { - es.Load(def) + es.load(def) } } fn := fmt.Sprintf("resources/%v.m", defSet.Name) @@ -235,6 +258,8 @@ func (es *EvalState) Init(loadAllDefs bool) { EvalInterp("$Context = \"Global`\"", es) EvalInterp("$ContextPath = Append[$ContextPath, \"Global`\"]", es) EvalInterp("$ExpreduceContextStack = {\"Global`\"}", es) + + es.profilingToStringParams = ActualStringFormArgsFull("InputForm", es) } func NewEvalState() *EvalState { @@ -255,55 +280,48 @@ func NewEvalState() *EvalState { return &es } -func NewEvalStateNoLog(loadAllDefs bool) *EvalState { - var es EvalState - es.Init(loadAllDefs) - es.CASLogger.debugState = false - return &es -} - -func (this *EvalState) IsDef(name string) bool { - _, isd := this.defined.Get(name) +func (es *EvalState) IsDef(name string) bool { + _, isd := es.defined.Get(name) return isd } -func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) { - if !this.IsDef(name) { +func (es *EvalState) GetDef(name string, lhs expreduceapi.Ex) (expreduceapi.Ex, bool, expreduceapi.ExpressionInterface) { + if !es.IsDef(name) { return nil, false, nil } // Special case for checking simple variable definitions like "a = 5". // TODO: Perhaps split out single var values into the Definition to avoid // iterating over every one. - if _, lhsIsSym := lhs.(*Symbol); lhsIsSym { - for _, def := range this.defined.GetDef(name).downvalues { - if hp, hpDef := HeadAssertion(def.rule.Parts[1], "System`HoldPattern"); hpDef { - if len(hp.Parts) == 2 { - if _, symDef := hp.Parts[1].(*Symbol); symDef { - return def.rule.Parts[2], true, def.rule + if _, lhsIsSym := lhs.(*atoms.Symbol); lhsIsSym { + for _, def := range es.defined.GetDef(name).Downvalues { + if hp, hpDef := atoms.HeadAssertion(def.Rule.GetParts()[1], "System`HoldPattern"); hpDef { + if len(hp.GetParts()) == 2 { + if _, symDef := hp.GetParts()[1].(*atoms.Symbol); symDef { + return def.Rule.GetParts()[2], true, def.Rule } } } } return nil, false, nil } - this.Debugf("Inside GetDef(\"%s\",%s)", name, lhs) - for i := range this.defined.GetDef(name).downvalues { - def := this.defined.GetDef(name).downvalues[i].rule + es.Debugf("Inside GetDef(\"%s\",%s)", name, lhs) + for i := range es.defined.GetDef(name).Downvalues { + def := es.defined.GetDef(name).Downvalues[i].Rule defStr, lhsDefStr := "", "" started := int64(0) - if this.isProfiling { - defStr = def.String(this) - lhsDefStr = lhs.String(this) + defStr + if es.IsProfiling() { + defStr = def.StringForm(es.profilingToStringParams) + lhsDefStr = lhs.StringForm(es.profilingToStringParams) + defStr started = time.Now().UnixNano() } - res, replaced := Replace(lhs, def, this) + res, replaced := replace(lhs, def, es) - if this.isProfiling { + if es.IsProfiling() { elapsed := float64(time.Now().UnixNano()-started) / 1000000000 - this.timeCounter.AddTime(CounterGroupDefTime, defStr, elapsed) - this.timeCounter.AddTime(CounterGroupLhsDefTime, lhsDefStr, elapsed) + es.timeCounter.AddTime(timecounter.CounterGroupDefTime, defStr, elapsed) + es.timeCounter.AddTime(timecounter.CounterGroupLHSDefTime, lhsDefStr, elapsed) } if replaced { @@ -313,20 +331,20 @@ func (this *EvalState) GetDef(name string, lhs Ex) (Ex, bool, *Expression) { return nil, false, nil } -func (this *EvalState) GetSymDef(name string) (Ex, bool) { - sym := NewSymbol(name) - symDef, isDef, _ := this.GetDef(name, sym) +func (es *EvalState) GetSymDef(name string) (expreduceapi.Ex, bool) { + sym := atoms.NewSymbol(name) + symDef, isDef, _ := es.GetDef(name, sym) return symDef, isDef } -func (this *EvalState) DefineAttrs(sym *Symbol, rhs Ex) { - attrsList, attrsIsList := HeadAssertion(rhs, "System`List") +func (es *EvalState) defineAttrs(sym *atoms.Symbol, rhs expreduceapi.Ex) { + attrsList, attrsIsList := atoms.HeadAssertion(rhs, "System`List") if !attrsIsList { return } var stringAttrs []string - for _, attrEx := range attrsList.Parts[1:] { - attrSym, attrIsSym := attrEx.(*Symbol) + for _, attrEx := range attrsList.GetParts()[1:] { + attrSym, attrIsSym := attrEx.(*atoms.Symbol) if !attrIsSym { return } @@ -335,61 +353,61 @@ func (this *EvalState) DefineAttrs(sym *Symbol, rhs Ex) { } stringAttrs = append(stringAttrs, attrSym.Name[7:]) } - attrs := stringsToAttributes(stringAttrs) - if !this.IsDef(sym.Name) { - this.defined.Set(sym.Name, Def{}) + attrs := atoms.StringsToAttributes(stringAttrs) + if !es.IsDef(sym.Name) { + es.defined.Set(sym.Name, expreduceapi.Def{}) } - tmp := this.defined.GetDef(sym.Name) - tmp.attributes = attrs - this.defined.Set(sym.Name, tmp) + tmp := es.defined.GetDef(sym.Name) + tmp.Attributes = attrs + es.defined.Set(sym.Name, tmp) } -func (this *EvalState) DefineDownValues(sym *Symbol, rhs Ex) { - dvList, isList := HeadAssertion(rhs, "System`List") +func (es *EvalState) defineDownValues(sym *atoms.Symbol, rhs expreduceapi.Ex) { + dvList, isList := atoms.HeadAssertion(rhs, "System`List") if !isList { fmt.Println("Assignment to DownValues must be List of Rules.") return } - dvs := []DownValue{} + dvs := []expreduceapi.DownValue{} - for _, dvEx := range dvList.Parts[1:] { - rule, isRule := HeadAssertion(dvEx, "System`Rule") + for _, dvEx := range dvList.GetParts()[1:] { + rule, isRule := atoms.HeadAssertion(dvEx, "System`Rule") if !isRule { - rule, isRule = HeadAssertion(dvEx, "System`RuleDelayed") + rule, isRule = atoms.HeadAssertion(dvEx, "System`RuleDelayed") } - if !isRule || len(rule.Parts) != 3 { + if !isRule || len(rule.GetParts()) != 3 { fmt.Println("Assignment to DownValues must be List of Rules.") } - dvs = append(dvs, DownValue{rule: rule}) + dvs = append(dvs, expreduceapi.DownValue{Rule: rule}) } - if !this.IsDef(sym.Name) { - this.defined.Set(sym.Name, Def{}) + if !es.IsDef(sym.Name) { + es.defined.Set(sym.Name, expreduceapi.Def{}) } - tmp := this.defined.GetDef(sym.Name) - tmp.downvalues = dvs - this.defined.Set(sym.Name, tmp) + tmp := es.defined.GetDef(sym.Name) + tmp.Downvalues = dvs + es.defined.Set(sym.Name, tmp) } -func (this *EvalState) MarkSeen(name string) { - if !this.IsDef(name) { - newDef := Def{ - downvalues: []DownValue{}, +func (es *EvalState) MarkSeen(name string) { + if !es.IsDef(name) { + newDef := expreduceapi.Def{ + Downvalues: []expreduceapi.DownValue{}, } - this.defined.Set(name, newDef) + es.defined.Set(name, newDef) } } // Attempts to compute a specificity metric for a rule. Higher specificity rules // should be tried first. -func ruleSpecificity(lhs Ex, rhs Ex, name string, es *EvalState) int { +func ruleSpecificity(lhs expreduceapi.Ex, rhs expreduceapi.Ex, name string, es *EvalState) int { if name == "Rubi`Int" { return 100 } // Special case for single integer arguments. - expr, isExpr := lhs.(*Expression).Parts[1].(*Expression) - if isExpr && len(expr.Parts) == 2 { - if _, isInt := expr.Parts[1].(*Integer); isInt { + expr, isExpr := lhs.(expreduceapi.ExpressionInterface).GetParts()[1].(expreduceapi.ExpressionInterface) + if isExpr && len(expr.GetParts()) == 2 { + if _, isInt := expr.GetParts()[1].(*atoms.Integer); isInt { return 110 } } @@ -398,17 +416,17 @@ func ruleSpecificity(lhs Ex, rhs Ex, name string, es *EvalState) int { // to attempt f[x_Integer] before we attempt f[x_]. If LHSs map to the same // "complexity" score, order then matters. TODO: Create better measure of // complexity (or specificity) - context, contextPath := DefinitionComplexityStringFormArgs() - stringParams := ToStringParams{ - form: "InputForm", - context: context, - contextPath: contextPath, + context, contextPath := definitionComplexityStringFormArgs() + stringParams := expreduceapi.ToStringParams{ + Form: "InputForm", + Context: context, + ContextPath: contextPath, // No need for the EvalState reference. Used for string expansion for // Definition[], which should not be in an actual definition. - es: es, + Esi: es, } specificity := len(lhs.StringForm(stringParams)) - if _, rhsIsCond := HeadAssertion(rhs, "System`Condition"); rhsIsCond { + if _, rhsIsCond := atoms.HeadAssertion(rhs, "System`Condition"); rhsIsCond { // 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. @@ -417,47 +435,47 @@ func ruleSpecificity(lhs Ex, rhs Ex, name string, es *EvalState) int { return specificity } -func (this *EvalState) Define(lhs Ex, rhs Ex) { - if this.IsFrozen() { +func (es *EvalState) Define(lhs expreduceapi.Ex, rhs expreduceapi.Ex) { + if es.IsFrozen() { return } // This function used to require a name as a parameter. Centralize the logic // here. name := "" - LhsSym, ok := lhs.(*Symbol) + lhsSym, ok := lhs.(*atoms.Symbol) if ok { - name = LhsSym.Name + name = lhsSym.Name } - LhsF, ok := lhs.(*Expression) + lhsF, ok := lhs.(expreduceapi.ExpressionInterface) if ok { - headAsSym, headIsSym := LhsF.Parts[0].(*Symbol) + headAsSym, headIsSym := lhsF.GetParts()[0].(*atoms.Symbol) if headIsSym { name = headAsSym.Name if name == "System`Attributes" { - if len(LhsF.Parts) != 2 { + if len(lhsF.GetParts()) != 2 { return } - modifiedSym, modifiedIsSym := LhsF.Parts[1].(*Symbol) + modifiedSym, modifiedIsSym := lhsF.GetParts()[1].(*atoms.Symbol) if !modifiedIsSym { return } - this.DefineAttrs(modifiedSym, rhs) + es.defineAttrs(modifiedSym, rhs) return } else if name == "System`DownValues" { - if len(LhsF.Parts) != 2 { + if len(lhsF.GetParts()) != 2 { return } - modifiedSym, modifiedIsSym := LhsF.Parts[1].(*Symbol) + modifiedSym, modifiedIsSym := lhsF.GetParts()[1].(*atoms.Symbol) if !modifiedIsSym { return } - this.DefineDownValues(modifiedSym, rhs) + es.defineDownValues(modifiedSym, rhs) return } } - _, opExpr, isVerbatimOp := OperatorAssertion(lhs, "System`Verbatim") + _, opExpr, isVerbatimOp := atoms.OperatorAssertion(lhs, "System`Verbatim") if isVerbatimOp { - opSym, opIsSym := opExpr.Parts[1].(*Symbol) + opSym, opIsSym := opExpr.GetParts()[1].(*atoms.Symbol) if opIsSym { name = opSym.Name } @@ -467,123 +485,135 @@ func (this *EvalState) Define(lhs Ex, rhs Ex) { log.Fatalf("Trying to define an invalid lhs: %v", lhs) } - this.Debugf("Inside es.Define(\"%s\",%s,%s)", name, lhs, rhs) - heldLhs := E(S("HoldPattern"), lhs) - if !this.IsDef(name) { - newDef := Def{ - downvalues: []DownValue{ - DownValue{ - rule: NewExpression([]Ex{ - NewSymbol("System`Rule"), heldLhs, rhs, + es.Debugf("Inside es.Define(\"%s\",%s,%s)", name, lhs, rhs) + heldLHS := atoms.E(atoms.S("HoldPattern"), lhs) + if !es.IsDef(name) { + newDef := expreduceapi.Def{ + Downvalues: []expreduceapi.DownValue{ + expreduceapi.DownValue{ + Rule: atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), heldLHS, rhs, }), }, }, } - this.defined.Set(name, newDef) + es.defined.Set(name, newDef) return } // Overwrite identical rules. - for _, dv := range this.defined.GetDef(name).downvalues { - existingRule := dv.rule - existingLhs := existingRule.Parts[1] - if IsSameQ(existingLhs, heldLhs, &this.CASLogger) { - this.defined.LockKey(name) - existingRhsCond := maskNonConditional(existingRule.Parts[2]) - newRhsCond := maskNonConditional(rhs) - if IsSameQ(existingRhsCond, newRhsCond, &this.CASLogger) { - dv.rule.Parts[2] = rhs - this.defined.UnlockKey(name) + for _, dv := range es.defined.GetDef(name).Downvalues { + existingRule := dv.Rule + existingLHS := existingRule.GetParts()[1] + if atoms.IsSameQ(existingLHS, heldLHS) { + es.defined.LockKey(name) + existingRHSCond := maskNonConditional(existingRule.GetParts()[2]) + newRHSCond := maskNonConditional(rhs) + if atoms.IsSameQ(existingRHSCond, newRHSCond) { + dv.Rule.GetParts()[2] = rhs + es.defined.UnlockKey(name) return } - this.defined.UnlockKey(name) + es.defined.UnlockKey(name) } } // Insert into definitions for name. Maintain order of decreasing // complexity. - var tmp = this.defined.GetDef(name) - newSpecificity := ruleSpecificity(heldLhs, rhs, name, this) - for i, dv := range this.defined.GetDef(name).downvalues { - if dv.specificity == 0 { - dv.specificity = ruleSpecificity( - dv.rule.Parts[1], - dv.rule.Parts[2], + var tmp = es.defined.GetDef(name) + newSpecificity := ruleSpecificity(heldLHS, rhs, name, es) + for i, dv := range es.defined.GetDef(name).Downvalues { + if dv.Specificity == 0 { + dv.Specificity = ruleSpecificity( + dv.Rule.GetParts()[1], + dv.Rule.GetParts()[2], name, - this, + es, ) } - if dv.specificity < newSpecificity { - newRule := NewExpression([]Ex{NewSymbol("System`Rule"), heldLhs, rhs}) - tmp.downvalues = append( - tmp.downvalues[:i], + if dv.Specificity < newSpecificity { + newRule := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Rule"), heldLHS, rhs}) + tmp.Downvalues = append( + tmp.Downvalues[:i], append( - []DownValue{DownValue{ - rule: newRule, - specificity: newSpecificity, + []expreduceapi.DownValue{expreduceapi.DownValue{ + Rule: newRule, + Specificity: newSpecificity, }}, - this.defined.GetDef(name).downvalues[i:]..., + es.defined.GetDef(name).Downvalues[i:]..., )..., ) - this.defined.Set(name, tmp) + es.defined.Set(name, tmp) return } } - tmp.downvalues = append(tmp.downvalues, DownValue{rule: NewExpression([]Ex{NewSymbol("System`Rule"), heldLhs, rhs})}) - this.defined.Set(name, tmp) + tmp.Downvalues = append(tmp.Downvalues, expreduceapi.DownValue{Rule: atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Rule"), heldLHS, rhs})}) + es.defined.Set(name, tmp) } -func (this *EvalState) ClearAll() { - this.Init(!this.NoInit) +func (es *EvalState) ClearAll() { + es.Init(!es.NoInit) } -func (this *EvalState) Clear(name string) { - _, ok := this.defined.Get(name) +func (es *EvalState) Clear(name string) { + _, ok := es.defined.Get(name) if ok { - this.defined.Set(name, Def{}) - //delete(this.defined, name) + es.defined.Set(name, expreduceapi.Def{}) + //delete(es.defined, name) } } -func (this *EvalState) GetDefinedSnapshot() definitionMap { - return this.defined.CopyDefs() +func (es *EvalState) GetDefinedSnapshot() expreduceapi.DefinitionMap { + return es.defined.CopyDefs() +} + +func (es *EvalState) GetDefinedMap() expreduceapi.DefinitionMap { + return es.defined +} + +func (es *EvalState) IsFrozen() bool { + return es.freeze +} + +func (es *EvalState) SetFrozen(frozen bool) { + es.freeze = frozen } -func (this *EvalState) IsFrozen() bool { - return this.freeze +func (es *EvalState) IsInterrupted() bool { + return es.interrupted } -func (this *EvalState) SetFrozen(frozen bool) { - this.freeze = frozen +func (es *EvalState) GetLogger() expreduceapi.LoggingInterface { + return &es.CASLogger } -func (this *EvalState) GetStringDef(name string, defaultVal string) string { - nameSym := NewSymbol(name) - def, isDef, _ := this.GetDef(name, nameSym) +func (es *EvalState) GetStringDef(name string, defaultVal string) string { + nameSym := atoms.NewSymbol(name) + def, isDef, _ := es.GetDef(name, nameSym) if !isDef { return defaultVal } - defString, defIsString := def.(*String) + defString, defIsString := def.(*atoms.String) if !defIsString { return defaultVal } return defString.Val } -func (this *EvalState) GetListDef(name string) *Expression { - nameSym := NewSymbol(name) - def, isDef, _ := this.GetDef(name, nameSym) +func (es *EvalState) GetListDef(name string) expreduceapi.ExpressionInterface { + nameSym := atoms.NewSymbol(name) + def, isDef, _ := es.GetDef(name, nameSym) if !isDef { - return NewExpression([]Ex{NewSymbol("System`List")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) } - defList, defIsList := HeadAssertion(def, "System`List") + defList, defIsList := atoms.HeadAssertion(def, "System`List") if !defIsList { - return NewExpression([]Ex{NewSymbol("System`List")}) + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) } return defList } -func (es *EvalState) Throw(e *Expression) { +func (es *EvalState) Throw(e expreduceapi.ExpressionInterface) { es.thrown = e } @@ -591,52 +621,83 @@ func (es *EvalState) HasThrown() bool { return es.thrown != nil } -func (es *EvalState) ProcessTopLevelResult(in Ex, out Ex) Ex { +func (es *EvalState) Thrown() expreduceapi.ExpressionInterface { + return es.thrown +} + +func (es *EvalState) GetTrace() expreduceapi.ExpressionInterface { + return es.trace +} + +func (es *EvalState) SetTrace(newTrace expreduceapi.ExpressionInterface) { + es.trace = newTrace +} + +func (es *EvalState) GetReapSown() expreduceapi.ExpressionInterface { + return es.reapSown +} + +func (es *EvalState) SetReapSown(ex expreduceapi.ExpressionInterface) { + es.reapSown = ex +} + +func (es *EvalState) GetTimeCounter() *timecounter.Group { + return &es.timeCounter +} + +func (es *EvalState) ProcessTopLevelResult(in expreduceapi.Ex, out expreduceapi.Ex) expreduceapi.Ex { theRes := out if es.HasThrown() { fmt.Printf("Throw::nocatch: %v returned to top level but uncaught.\n\n", es.thrown) - theRes = NewExpression([]Ex{ - NewSymbol("System`Hold"), + theRes = atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Hold"), es.thrown, }) + // Clear exception es.Throw(nil) } else { es.interrupted = false } thisLine, _ := es.GetSymDef("System`$Line") - E(S("SetDelayed"), E(S("In"), thisLine), in).Eval(es) - E(S("Set"), E(S("Out"), thisLine), theRes).Eval(es) + es.Eval(atoms.E(atoms.S("SetDelayed"), atoms.E(atoms.S("In"), thisLine), in)) + es.Eval(atoms.E(atoms.S("Set"), atoms.E(atoms.S("Out"), thisLine), theRes)) prePrintFn, hasPrePrint := es.GetSymDef("System`$PrePrint") if hasPrePrint { - theRes = E(prePrintFn, theRes).Eval(es) + theRes = es.Eval(atoms.E(prePrintFn, theRes)) } - E(S("Increment"), S("$Line")).Eval(es) + es.Eval(atoms.E(atoms.S("Increment"), atoms.S("$Line"))) return theRes } -func maskNonConditional(e Ex) Ex { - var res Ex = NewSymbol("System`ExpreduceNonConditional") - if asHead, isHead := HeadAssertion(e, "System`Condition"); isHead { - res = NewExpression([]Ex{ - NewSymbol("System`Condition"), - maskNonConditional(asHead.Parts[1]), - asHead.Parts[2], +func maskNonConditional(e expreduceapi.Ex) expreduceapi.Ex { + var res expreduceapi.Ex = atoms.NewSymbol("System`ExpreduceNonConditional") + if asHead, isHead := atoms.HeadAssertion(e, "System`Condition"); isHead { + res = atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Condition"), + maskNonConditional(asHead.GetParts()[1]), + asHead.GetParts()[2], }) + } heads := []string{"System`With", "System`Module"} for _, head := range heads { - if asHead, isHead := HeadAssertion(e, head); isHead { - if len(asHead.Parts) == 3 { - if _, hasCond := HeadAssertion(asHead.Parts[2], "System`Condition"); hasCond { - res = NewExpression([]Ex{ - NewSymbol(head), - asHead.Parts[1], - maskNonConditional(asHead.Parts[2]), + if asHead, isHead := atoms.HeadAssertion(e, head); isHead { + if len(asHead.GetParts()) == 3 { + if _, hasCond := atoms.HeadAssertion(asHead.GetParts()[2], "System`Condition"); hasCond { + res = atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol(head), + asHead.GetParts()[1], + maskNonConditional(asHead.GetParts()[2]), }) + } } } } return res } + +func (es *EvalState) GetStreamManager() expreduceapi.StreamManager { + return es.streamManager +} diff --git a/expreduce/ex_complex.go b/expreduce/ex_complex.go deleted file mode 100644 index 92605cd..0000000 --- a/expreduce/ex_complex.go +++ /dev/null @@ -1,135 +0,0 @@ -package expreduce - -import "fmt" -import "hash/fnv" -import "encoding/binary" - -type Complex struct { - Re Ex - Im Ex - needsEval bool -} - -func (this *Complex) Eval(es *EvalState) Ex { - this.Re = this.Re.Eval(es) - this.Im = this.Im.Eval(es) - if IsSameQ(this.Im, NewInt(0), &es.CASLogger) { - return this.Re - } - this.needsEval = false - return this -} - -func (this *Complex) StringForm(p ToStringParams) string { - if p.form == "FullForm" { - return fmt.Sprintf("Complex[%v, %v]", this.Re, this.Im) - } - p.previousHead = "System`Plus" - return fmt.Sprintf("(%v + %v*I)", this.Re.StringForm(p), this.Im.StringForm(p)) -} - -func (this *Complex) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{ - form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Complex) IsEqual(other Ex, cl *CASLogger) string { - otherConv, otherIsComplex := other.(*Complex) - if !otherIsComplex { - return "EQUAL_FALSE" - } - if (this.Re.IsEqual(otherConv.Re, cl) != "EQUAL_TRUE") || (this.Im.IsEqual(otherConv.Im, cl) != "EQUAL_TRUE") { - return "EQUAL_FALSE" - } - return "EQUAL_TRUE" -} - -func (this *Complex) DeepCopy() Ex { - return &Complex{this.Re.DeepCopy(), this.Im.DeepCopy(), this.needsEval} -} - -func (this *Complex) Copy() Ex { - return this.DeepCopy() -} - -func (this *Complex) NeedsEval() bool { - return this.needsEval -} - -func NewComplex(r Ex, i Ex) *Complex { - return &Complex{r, i, true} -} - -func (this *Complex) Hash() uint64 { - h := fnv.New64a() - h.Write([]byte{82, 226, 223, 39, 113, 26, 149, 249}) - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, this.Re.Hash()) - h.Write(b) - binary.LittleEndian.PutUint64(b, this.Im.Hash()) - h.Write(b) - return h.Sum64() -} - -func (this *Complex) addReal(e Ex) { - a, _ := computeNumericPart(FoldFnAdd, E(S("Dummy"), this.Re, e)) - this.Re = a - this.needsEval = true -} - -func (this *Complex) AddI(i *Integer) { - this.addReal(i) -} - -func (this *Complex) AddF(f *Flt) { - this.addReal(f) -} - -func (this *Complex) AddR(r *Rational) { - this.addReal(r) -} - -func (this *Complex) AddC(c *Complex) { - a, _ := computeNumericPart(FoldFnAdd, E(S("Dummy"), this.Re, c.Re)) - b, _ := computeNumericPart(FoldFnAdd, E(S("Dummy"), this.Im, c.Im)) - this.Re = a - this.Im = b - this.needsEval = true -} - -func (this *Complex) mulReal(e Ex) { - a, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), this.Re, e)) - b, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), this.Im, e)) - this.Re = a - this.Im = b - this.needsEval = true -} - -func (this *Complex) MulI(i *Integer) { - this.mulReal(i) -} - -func (this *Complex) MulF(f *Flt) { - this.mulReal(f) -} - -func (this *Complex) MulR(r *Rational) { - this.mulReal(r) -} - -func (this *Complex) MulC(c *Complex) { - // HoldPattern[Complex[x_, y_]*Complex[u_, v_]*rest___] -> Complex[x*u + (y*v)*(-1), x*v + y*u]*rest) - // This is ugly. Need to refactor. - // Perhaps create "Calculator" utility?? - // TODO(corywalker) Remove the definition that this implements in code. - a, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), this.Re, c.Re)) - b, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), NewInt(-1), this.Im, c.Im)) - cc, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), this.Re, c.Im)) - d, _ := computeNumericPart(FoldFnMul, E(S("Dummy"), this.Im, c.Re)) - e, _ := computeNumericPart(FoldFnAdd, E(S("Dummy"), a, b)) - f, _ := computeNumericPart(FoldFnAdd, E(S("Dummy"), cc, d)) - this.Re = e - this.Im = f - this.needsEval = true -} diff --git a/expreduce/ex_expression.go b/expreduce/ex_expression.go deleted file mode 100644 index 89330ad..0000000 --- a/expreduce/ex_expression.go +++ /dev/null @@ -1,608 +0,0 @@ -package expreduce - -import "bytes" -import "math/big" -import "sort" -import "fmt" -import "encoding/binary" -import "time" -import "flag" -import "hash/fnv" -import "sync/atomic" - -var printevals = flag.Bool("printevals", false, "") -var checkhashes = flag.Bool("checkhashes", false, "") - -type Expression struct { - Parts []Ex - needsEval bool - correctlyInstantiated bool - evaledHash uint64 - cachedHash uint64 -} - -// Deprecated in favor of headExAssertion -func HeadAssertion(ex Ex, head string) (*Expression, bool) { - expr, isExpr := ex.(*Expression) - if isExpr { - sym, isSym := expr.Parts[0].(*Symbol) - if isSym { - if sym.Name == head { - return expr, true - } - } - } - return nil, false -} - -func headExAssertion(ex Ex, head Ex, cl *CASLogger) (*Expression, bool) { - expr, isExpr := ex.(*Expression) - if isExpr { - if IsSameQ(head, expr.Parts[0], cl) { - return expr, true - } - } - return nil, false -} - -func OperatorAssertion(ex Ex, opHead string) (*Expression, *Expression, bool) { - expr, isExpr := ex.(*Expression) - if isExpr { - headExpr, headIsExpr := expr.Parts[0].(*Expression) - if headIsExpr { - sym, isSym := headExpr.Parts[0].(*Symbol) - if isSym { - if sym.Name == opHead { - return expr, headExpr, true - } - } - } - } - return nil, nil, false -} - -func tryReturnValue(e Ex, origEx Ex, es *EvalState) (Ex, bool) { - if es.interrupted { - if origEx != nil { - fmt.Println(origEx) - } - return NewSymbol("System`$Aborted"), true - } - asReturn, isReturn := HeadAssertion(e, "System`Return") - if !isReturn { - return nil, false - } - if len(asReturn.Parts) >= 2 { - return asReturn.Parts[1], true - } - return NewSymbol("System`Null"), true -} - -// Is this causing issues by not creating a copy as we modify? Actually it is -// creating copies. -func (this *Expression) mergeSequences(es *EvalState, headStr string, shouldEval bool) *Expression { - encounteredSeq := false - for _, e := range this.Parts { - if _, isseq := HeadAssertion(e, headStr); isseq { - encounteredSeq = true - break - } - } - // Only build a new expression if the expression actually has a sequence - // needing merging. - if !encounteredSeq { - return this - } - - // TODO: I should not be attempting to merge the head if it happens to be - // a Sequence type. This is very similar to the flatten function. Perhaps - // it should be combined. This version is not recursive, and it does not - // accept level depths. It is a specific case of Flatten. - res := NewEmptyExpression() - for _, e := range this.Parts { - seq, isseq := HeadAssertion(e, headStr) - if isseq { - for _, seqPart := range seq.Parts[1:] { - if shouldEval { - res.Parts = append(res.Parts, seqPart.Eval(es)) - } else { - res.Parts = append(res.Parts, seqPart) - } - } - } else { - res.Parts = append(res.Parts, e) - } - } - return res -} - -func (this *Expression) propagateConditionals() (*Expression, bool) { - foundCond := false - for _, e := range this.Parts[1:] { - if cond, isCond := HeadAssertion(e, "System`ConditionalExpression"); isCond { - if len(cond.Parts) == 3 { - foundCond = true - break - } - } - } - if foundCond{ - resEx := E(this.Parts[0]) - resCond := E(S("And")) - for _, e := range this.Parts[1:] { - if cond, isCond := HeadAssertion(e, "System`ConditionalExpression"); isCond { - if len(cond.Parts) == 3 { - resEx.appendEx(cond.Parts[1].DeepCopy()) - resCond.appendEx(cond.Parts[2].DeepCopy()) - continue - } - } - resEx.appendEx(e.DeepCopy()) - } - return E(S("ConditionalExpression"), resEx, resCond), true - } - return this, false -} - -func (this *Expression) Eval(es *EvalState) Ex { - var origEx Ex = this - - lastExHash := uint64(0) - var lastEx Ex = this - currExHash := hashEx(this) - if currExHash == this.evaledHash { - return this - } - var currEx Ex = this - insideDefinition := false - for currExHash != lastExHash { - lastExHash = currExHash - curr, isExpr := currEx.(*Expression) - if *checkhashes { - if isExpr && curr.evaledHash != 0 && currExHash != curr.evaledHash { - fmt.Printf("invalid cache: %v. Used to be %v\n", curr, lastEx) - } - lastEx = currEx - } - - if isExpr && insideDefinition { - retVal, isReturn := tryReturnValue(curr, origEx, es) - if isReturn { - return retVal - } - } - if isExpr && currExHash == curr.evaledHash { - return curr - } - - if *printevals { - fmt.Printf("Evaluating %v.\n", currEx) - } - // Transition to the right Eval() if this is no longer an Expression - if !isExpr { - toReturn := currEx.Eval(es) - // Handle tracing - if es.trace != nil && !es.IsFrozen() { - toAppend := NewExpression([]Ex{ - NewSymbol("System`HoldForm"), - toReturn.DeepCopy(), - }) - - //fmt.Printf("Beginning: appending %v\n", toAppend.StringForm("FullForm")) - es.trace.Parts = append( - es.trace.Parts, - toAppend, - ) - } - return toReturn - } - - currStr := "" - currHeadStr := "" - started := int64(0) - if es.isProfiling { - currStr = curr.String(es) - currHeadStr = curr.Parts[0].String(es) - started = time.Now().UnixNano() - } - - // Start by evaluating each argument - headSym, headIsSym := &Symbol{}, false - attrs := Attributes{} - if len(curr.Parts) > 0 { - headSym, headIsSym = curr.Parts[0].(*Symbol) - } - if headIsSym { - attrs = headSym.Attrs(&es.defined) - } - if attrs.NumericFunction { - propagated, changed := curr.propagateConditionals() - if changed { - return propagated.Eval(es) - } - } - for i := range curr.Parts { - if headIsSym && i == 1 && attrs.HoldFirst { - continue - } - if headIsSym && i > 1 && attrs.HoldRest { - continue - } - if headIsSym && (attrs.HoldAll || attrs.HoldAllComplete) { - continue - } - - // Handle tracing - traceBak := es.trace - if es.trace != nil && !es.IsFrozen() { - es.trace = NewExpression([]Ex{NewSymbol("System`List")}) - } - oldHash := curr.Parts[i].Hash() - //fmt.Println(curr, i) - curr.Parts[i] = curr.Parts[i].Eval(es) - if es.HasThrown() { - return es.thrown - } - if oldHash != curr.Parts[i].Hash() { - curr.cachedHash = 0 - } - if es.trace != nil && !es.IsFrozen() { - if len(es.trace.Parts) > 2 { - // The DeepCopy here doesn't seem to affect anything, but - // should be good to have. - //fmt.Printf("Argument eval: appending %v\n", es.trace.DeepCopy().StringForm("FullForm")) - traceBak.Parts = append(traceBak.Parts, es.trace.DeepCopy()) - } - es.trace = traceBak - } - } - - // Handle tracing - if es.trace != nil && !es.IsFrozen() { - toAppend := NewExpression([]Ex{ - NewSymbol("System`HoldForm"), - currEx.DeepCopy(), - }) - - if !IsSameQ(es.trace.Parts[len(es.trace.Parts)-1], toAppend, &es.CASLogger) { - //fmt.Printf("Beginning: appending %v\n", toAppend.StringForm("FullForm")) - es.trace.Parts = append( - es.trace.Parts, - toAppend, - ) - } - } - - // If any of the parts are Sequence, merge them with parts - if headIsSym { - if !attrs.SequenceHold && !attrs.HoldAllComplete { - curr = curr.mergeSequences(es, "System`Sequence", false) - } - } else { - curr = curr.mergeSequences(es, "System`Sequence", false) - } - if !attrs.HoldAllComplete { - curr = curr.mergeSequences(es, "System`Evaluate", true) - } - curr = curr.mergeSequences(es, "System`Unevaluated", false) - // In case curr changed - currEx = curr - - pureFunction, isPureFunction := HeadAssertion(curr.Parts[0], "System`Function") - if headIsSym { - if attrs.Flat { - curr = curr.mergeSequences(es, headSym.Name, false) - } - if attrs.Orderless { - sort.Sort(curr) - curr.cachedHash = 0 - } - if attrs.Listable { - changed := false - currEx, changed = ThreadExpr(curr) - if changed { - currExHash = hashEx(currEx) - continue - } - } - headStr := headSym.Name - - legacyEvalFn, hasLegacyEvalFn := (func(*Expression, *EvalState) Ex)(nil), false - if _, inDefined := es.defined.Get(headStr); inDefined { - if es.defined.GetDef(headStr).legacyEvalFn != nil { - hasLegacyEvalFn = true - legacyEvalFn = es.defined.GetDef(headStr).legacyEvalFn - } - } - unchanged := true - if hasLegacyEvalFn { - currEx = legacyEvalFn(curr, es) - // TODO: I could potentially have the legacyevalfn return this. - unchanged = IsSameQ(currEx, curr, &es.CASLogger) - } - if unchanged { - theRes, isDefined, def := es.GetDef(headStr, curr) - if isDefined { - //fmt.Printf("%v, %v, %v\n", headStr, curr, theRes) - es.Infof("Def: %v â–¶ %v â–¶ using %v â–¶ from %s head", currEx, theRes, def, headStr) - currEx = theRes - insideDefinition = true - } - } - } else if isPureFunction { - currEx = pureFunction.EvalFunction(es, curr.Parts[1:]) - } - currExHash = hashEx(currEx) - - // Handle end of profiling - if es.isProfiling { - elapsed := float64(time.Now().UnixNano()-started) / 1000000000 - es.timeCounter.AddTime(CounterGroupEvalTime, currStr, elapsed) - es.timeCounter.AddTime(CounterGroupHeadEvalTime, currHeadStr, elapsed) - } - } - curr, isExpr := currEx.(*Expression) - if isExpr { - curr.needsEval = false - curr.evaledHash = currExHash - } - return currEx -} - -func (this *Expression) EvalFunction(es *EvalState, args []Ex) Ex { - if len(this.Parts) == 2 { - toReturn := this.Parts[1].DeepCopy() - for i, arg := range args { - toReturn = ReplaceAll(toReturn, - NewExpression([]Ex{ - NewSymbol("System`Rule"), - NewExpression([]Ex{ - NewSymbol("System`Slot"), - NewInteger(big.NewInt(int64(i + 1))), - }), - - arg, - }), - - es, EmptyPD(), "System`Function") - } - return toReturn - } else if len(this.Parts) == 3 { - repSym, ok := this.Parts[1].(*Symbol) - if !ok { - return this - } - toReturn := this.Parts[2].DeepCopy() - toReturn = ReplaceAll(toReturn, - NewExpression([]Ex{ - NewSymbol("System`Rule"), - repSym, - args[0], - }), - - es, EmptyPD(), "System`Function") - return toReturn - } - return this -} - -func (this *Expression) ReplaceAll(r *Expression, stopAtHead string, es *EvalState) Ex { - es.Debugf("In Expression.ReplaceAll. First trying IsMatchQ(this, r.Parts[1], es).") - es.Debugf("Rule r is: %s", r) - - matchq, matches := IsMatchQ(this, r.Parts[1], EmptyPD(), es) - if matchq { - es.Debugf("After MatchQ, rule is: %s", r) - es.Debugf("MatchQ succeeded. Returning r.Parts[2]: %s", r.Parts[2]) - return ReplacePD(r.Parts[2].DeepCopy(), es, matches) - } - - thisSym, thisSymOk := this.Parts[0].(*Symbol) - lhsExpr, lhsExprOk := r.Parts[1].(*Expression) - if lhsExprOk { - otherSym, otherSymOk := lhsExpr.Parts[0].(*Symbol) - if thisSymOk && otherSymOk { - if thisSym.Name == otherSym.Name { - attrs := thisSym.Attrs(&es.defined) - if attrs.Flat { - return FlatReplace(this, lhsExpr, r.Parts[2], attrs.Orderless, es) - } - } - } - } - - maybeChanged := NewEmptyExpression() - for i := range this.Parts { - maybeChanged.Parts = append(maybeChanged.Parts, ReplaceAll(this.Parts[i], r, es, EmptyPD(), stopAtHead)) - } - if hashEx(maybeChanged) != hashEx(this) { - return maybeChanged - } - return this -} - -func (this *Expression) StringForm(params ToStringParams) string { - headAsSym, isHeadSym := this.Parts[0].(*Symbol) - fullForm := false - if isHeadSym && !fullForm { - res, ok := "", false - headStr := headAsSym.Name - toStringFn, hasToStringFn := params.es.toStringFns[headStr] - if hasToStringFn { - ok, res = toStringFn(this, params) - } - if ok { - return res - } - } - - if len(this.Parts) == 2 && isHeadSym && ( - headAsSym.Name == "System`InputForm" || - headAsSym.Name == "System`FullForm" || - headAsSym.Name == "System`TraditionalForm" || - headAsSym.Name == "System`TeXForm" || - headAsSym.Name == "System`StandardForm" || - headAsSym.Name == "System`OutputForm") { - mutatedParams := params - mutatedParams.form = headAsSym.Name[7:] - return this.Parts[1].StringForm(mutatedParams) - } - - // Default printing format - var buffer bytes.Buffer - buffer.WriteString(this.Parts[0].StringForm(params)) - buffer.WriteString("[") - params.previousHead = "" - for i, e := range this.Parts { - if i == 0 { - continue - } - buffer.WriteString(e.StringForm(params)) - if i != len(this.Parts)-1 { - buffer.WriteString(", ") - } - } - buffer.WriteString("]") - return buffer.String() -} - -func (this *Expression) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{ - form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Expression) IsEqual(otherEx Ex, cl *CASLogger) string { - other, ok := otherEx.(*Expression) - if !ok { - return "EQUAL_UNK" - } - - if len(this.Parts) != len(other.Parts) { - return "EQUAL_UNK" - } - for i := range this.Parts { - res := this.Parts[i].IsEqual(other.Parts[i], cl) - switch res { - case "EQUAL_FALSE": - return "EQUAL_UNK" - case "EQUAL_TRUE": - case "EQUAL_UNK": - return "EQUAL_UNK" - } - } - return "EQUAL_TRUE" -} - -func (this *Expression) DeepCopy() Ex { - var thiscopy = NewEmptyExpression() - for i := range this.Parts { - thiscopy.Parts = append(thiscopy.Parts, this.Parts[i].DeepCopy()) - } - thiscopy.needsEval = this.needsEval - thiscopy.correctlyInstantiated = this.correctlyInstantiated - thiscopy.evaledHash = this.evaledHash - thiscopy.cachedHash = this.cachedHash - return thiscopy -} - -func (this *Expression) ShallowCopy() *Expression { - var thiscopy = NewEmptyExpression() - thiscopy.Parts = append([]Ex{}, this.Parts...) - thiscopy.needsEval = this.needsEval - thiscopy.correctlyInstantiated = this.correctlyInstantiated - thiscopy.evaledHash = this.evaledHash - thiscopy.cachedHash = this.cachedHash - return thiscopy -} - -func (this *Expression) Copy() Ex { - var thiscopy = NewEmptyExpressionOfLength(len(this.Parts)) - for i := range this.Parts { - thiscopy.Parts[i] = this.Parts[i].Copy() - } - thiscopy.needsEval = this.needsEval - thiscopy.correctlyInstantiated = this.correctlyInstantiated - thiscopy.evaledHash = this.evaledHash - thiscopy.cachedHash = this.cachedHash - return thiscopy -} - -// Implement the sort.Interface -func (this *Expression) Len() int { - return len(this.Parts) - 1 -} - -func (this *Expression) Less(i, j int) bool { - return ExOrder(this.Parts[i+1], this.Parts[j+1]) == 1 -} - -func (this *Expression) Swap(i, j int) { - this.Parts[j+1], this.Parts[i+1] = this.Parts[i+1], this.Parts[j+1] -} - -func (this *Expression) appendEx(e Ex) { - this.Parts = append(this.Parts, e) -} - -func (this *Expression) appendExArray(e []Ex) { - this.Parts = append(this.Parts, e...) -} - -func (this *Expression) NeedsEval() bool { - return this.needsEval -} - -func (this *Expression) Hash() uint64 { - if atomic.LoadUint64(&this.cachedHash) > 0 { - return this.cachedHash - } - h := fnv.New64a() - h.Write([]byte{72, 5, 244, 86, 5, 210, 69, 30}) - b := make([]byte, 8) - for _, part := range this.Parts { - binary.LittleEndian.PutUint64(b, part.Hash()) - h.Write(b) - } - atomic.StoreUint64(&this.cachedHash, h.Sum64()) - return h.Sum64() -} - -func (this *Expression) HeadStr() string { - sym, isSym := this.Parts[0].(*Symbol) - if isSym { - return sym.Name - } - return "" -} - -func NewExpression(parts []Ex) *Expression { - return &Expression{ - Parts: parts, - needsEval: true, - correctlyInstantiated: true, - } -} - -func E(parts ...Ex) *Expression { - return NewExpression(parts) -} - -func NewHead(head string) *Expression { - return NewExpression([]Ex{NewSymbol(head)}) -} - -func NewEmptyExpression() *Expression { - return &Expression{ - needsEval: true, - correctlyInstantiated: true, - } -} - -func NewEmptyExpressionOfLength(n int) *Expression { - return &Expression{ - Parts: make([]Ex, n), - needsEval: true, - correctlyInstantiated: true, - } -} diff --git a/expreduce/ex_integer.go b/expreduce/ex_integer.go deleted file mode 100644 index 2cf4d22..0000000 --- a/expreduce/ex_integer.go +++ /dev/null @@ -1,105 +0,0 @@ -package expreduce - -import "fmt" -import "math/big" -import "hash/fnv" - -// Integer numbers represented by big.Int -type Integer struct { - Val *big.Int - cachedHash uint64 -} - -func (f *Integer) Eval(es *EvalState) Ex { - return f -} - -/*func (f *Integer) StringForm(params ToStringParams) string { - return fmt.Sprintf("%d", f.Val) -}*/ - -func (i *Integer) StringForm(params ToStringParams) string { - if i.Val.Cmp(big.NewInt(0)) < 0 { - if needsParens("System`Times", params.previousHead) { - if params.form == "TeXForm" { - return fmt.Sprintf("{(%d)}", i.Val) - } - return fmt.Sprintf("(%d)", i.Val) - } - } - return fmt.Sprintf("%d", i.Val) -} - -func (this *Integer) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Integer) IsEqual(other Ex, cl *CASLogger) string { - otherConv, ok := other.(*Integer) - if !ok { - otherFlt, ok := other.(*Flt) - if ok { - thisAsFlt := big.NewFloat(0) - thisAsFlt.SetInt(this.Val) - if thisAsFlt.Cmp(otherFlt.Val) == 0 { - return "EQUAL_TRUE" - } - } - return "EQUAL_UNK" - } - if this.Val.Cmp(otherConv.Val) != 0 { - return "EQUAL_FALSE" - } - return "EQUAL_TRUE" -} - -func (this *Integer) DeepCopy() Ex { - tmp := big.NewInt(0) - tmp.Set(this.Val) - return &Integer{Val: tmp, cachedHash: this.cachedHash} -} - -func (this *Integer) Copy() Ex { - return this -} - -func (this *Integer) NeedsEval() bool { - return false -} - -func NewInteger(i *big.Int) *Integer { - return &Integer{Val: i} -} - -func NewInt(i int64) *Integer { - return NewInteger(big.NewInt(i)) -} - -func (this *Integer) Hash() uint64 { - if this.cachedHash > 0 { - return this.cachedHash - } - h := fnv.New64a() - h.Write([]byte{242, 99, 84, 113, 102, 46, 118, 94}) - bytes, _ := this.Val.MarshalText() - h.Write(bytes) - this.cachedHash = h.Sum64() - return h.Sum64() -} - -func (this *Integer) AsBigFloat() *big.Float { - newfloat := big.NewFloat(0) - newfloat.SetInt(this.Val) - return newfloat -} - -func (this *Integer) AddI(i *Integer) { - this.Val.Add(this.Val, i.Val) - this.cachedHash = 0 -} - -func (this *Integer) MulI(i *Integer) { - this.Val.Mul(this.Val, i.Val) - this.cachedHash = 0 -} diff --git a/expreduce/ex_rational.go b/expreduce/ex_rational.go deleted file mode 100644 index 7088ed9..0000000 --- a/expreduce/ex_rational.go +++ /dev/null @@ -1,157 +0,0 @@ -package expreduce - -import "fmt" -import "math/big" -import "hash/fnv" - -type Rational struct { - Num *big.Int - Den *big.Int - needsEval bool -} - -func (this *Rational) Eval(es *EvalState) Ex { - if this.Num.Cmp(big.NewInt(0)) == 0 && this.Den.Cmp(big.NewInt(0)) == 0 { - return NewSymbol("System`Indeterminate") - } - if this.Den.Cmp(big.NewInt(0)) == 0 { - return NewSymbol("System`ComplexInfinity") - } - if this.Num.Cmp(big.NewInt(0)) == 0 { - return NewInteger(big.NewInt(0)) - } - negNum := this.Num.Cmp(big.NewInt(0)) == -1 - negDen := this.Den.Cmp(big.NewInt(0)) == -1 - negateRes := negNum != negDen - absNum := big.NewInt(0) - absNum.Abs(this.Num) - absDen := big.NewInt(0) - absDen.Abs(this.Den) - - gcd := big.NewInt(0) - gcd.GCD(nil, nil, absNum, absDen) - absNum.Div(absNum, gcd) - absDen.Div(absDen, gcd) - - if absDen.Cmp(big.NewInt(1)) == 0 { - if !negateRes { - return NewInteger(absNum) - } else { - return NewInteger(absNum.Neg(absNum)) - } - } - - if !negateRes { - this.Num.Set(absNum) - this.Den.Set(absDen) - this.needsEval = false - return this - } - this.Num.Set(absNum.Neg(absNum)) - this.Den.Set(absDen) - this.needsEval = false - return this -} - -func (this *Rational) StringForm(params ToStringParams) string { - if params.form == "FullForm" { - return fmt.Sprintf("Rational[%d, %d]", this.Num, this.Den) - } - if params.form == "TeXForm" { - return fmt.Sprintf("\\frac{%d}{%d}", this.Num, this.Den) - } - if needsParens("System`Times", params.previousHead) { - return fmt.Sprintf("(%d/%d)", this.Num, this.Den) - } - return fmt.Sprintf("%d/%d", this.Num, this.Den) -} - -func (this *Rational) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Rational) IsEqual(other Ex, cl *CASLogger) string { - otherConv, otherIsRational := other.(*Rational) - if !otherIsRational { - return "EQUAL_FALSE" - } - // Assume rational already simplified - if (this.Num.Cmp(otherConv.Num) != 0) || (this.Den.Cmp(otherConv.Den) != 0) { - return "EQUAL_FALSE" - } - return "EQUAL_TRUE" -} - -func (this *Rational) DeepCopy() Ex { - tmpn := big.NewInt(0) - tmpn.Set(this.Num) - tmpd := big.NewInt(0) - tmpd.Set(this.Den) - return &Rational{tmpn, tmpd, this.needsEval} -} - -func (this *Rational) Copy() Ex { - return this.DeepCopy() -} - -func (this *Rational) AsBigRat() *big.Rat { - res := big.NewRat(1, 1) - return res.SetFrac(this.Num, this.Den) -} - -func (this *Rational) NeedsEval() bool { - return this.needsEval -} - -func NewRational(n *big.Int, d *big.Int) *Rational { - return &Rational{n, d, true} -} - -func (this *Rational) Hash() uint64 { - h := fnv.New64a() - h.Write([]byte{90, 82, 214, 51, 52, 7, 7, 33}) - nBytes, _ := this.Num.MarshalText() - h.Write(nBytes) - dBytes, _ := this.Den.MarshalText() - h.Write(dBytes) - return h.Sum64() -} - -func (this *Rational) AsBigFloat() *big.Float { - num := big.NewFloat(0) - den := big.NewFloat(0) - newquo := big.NewFloat(0) - num.SetInt(this.Num) - den.SetInt(this.Den) - newquo.Quo(num, den) - return newquo -} - -func (this *Rational) AddI(i *Integer) { - tmp := big.NewInt(0) - tmp.Mul(i.Val, this.Den) - this.Num.Add(this.Num, tmp) -} - -func (this *Rational) AddR(r *Rational) { - tmp := big.NewInt(0) - // lastrNum/lastrDen + theratNum/theratDen // Together - tmp.Mul(this.Den, r.Num) - this.Den.Mul(this.Den, r.Den) - this.Num.Mul(this.Num, r.Den) - this.Num.Add(this.Num, tmp) -} - -func (this *Rational) MulI(i *Integer) { - this.Num.Mul(this.Num, i.Val) -} - -func (this *Rational) MulBigI(i *big.Int) { - this.Num.Mul(this.Num, i) -} - -func (this *Rational) MulR(r *Rational) { - this.Num.Mul(this.Num, r.Num) - this.Den.Mul(this.Den, r.Den) -} diff --git a/expreduce/ex_real.go b/expreduce/ex_real.go deleted file mode 100644 index ab72a78..0000000 --- a/expreduce/ex_real.go +++ /dev/null @@ -1,129 +0,0 @@ -package expreduce - -import "fmt" -import "math/big" -import "bytes" -import "hash/fnv" -import "strings" - -// Floating point numbers represented by big.Float -type Flt struct { - Val *big.Float -} - -func (f *Flt) Eval(es *EvalState) Ex { - return f -} - -func (f *Flt) StringForm(params ToStringParams) string { - var buffer bytes.Buffer - useParens := false - if f.Val.Cmp(big.NewFloat(0)) < 0 { - if needsParens("System`Times", params.previousHead) { - useParens = true - if params.form == "TeXForm" { - buffer.WriteString("{") - } - buffer.WriteString("(") - } - } - buffer.WriteString(fmt.Sprintf("%.6g", f.Val)) - if bytes.IndexRune(buffer.Bytes(), '.') == -1 { - buffer.WriteString(".") - } - if useParens { - buffer.WriteString(")") - if params.form == "TeXForm" { - buffer.WriteString("}") - } - } - return buffer.String() -} - -func (this *Flt) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Flt) IsEqual(other Ex, cl *CASLogger) string { - otherConv, ok := other.(*Flt) - if !ok { - otherInteger, ok := other.(*Integer) - if ok { - otherAsFlt := big.NewFloat(0) - otherAsFlt.SetInt(otherInteger.Val) - if otherAsFlt.Cmp(this.Val) == 0 { - return "EQUAL_TRUE" - } - } - return "EQUAL_UNK" - } - thisStr := fmt.Sprintf("%.14g", this.Val) - otherStr := fmt.Sprintf("%.14g", otherConv.Val) - if strings.Compare(thisStr, otherStr) != 0 { - return "EQUAL_FALSE" - } - return "EQUAL_TRUE" -} - -func (this *Flt) DeepCopy() Ex { - tmp := big.NewFloat(0) - tmp.Copy(this.Val) - return NewReal(tmp) -} - -func (this *Flt) Copy() Ex { - return this.DeepCopy() -} - -func IntegerToFlt(i *Integer) (*Flt, bool) { - newfloat := big.NewFloat(0) - newfloat.SetInt(i.Val) - return NewReal(newfloat), true -} - -func RationalToFlt(r *Rational) (*Flt, bool) { - newfloat := big.NewFloat(0) - newfloat.SetRat(r.AsBigRat()) - return NewReal(newfloat), true -} - -func (this *Flt) NeedsEval() bool { - return false -} - -func (this *Flt) Hash() uint64 { - h := fnv.New64a() - h.Write([]byte{195, 244, 76, 249, 227, 115, 88, 251}) - bytes, _ := this.Val.MarshalText() - h.Write(bytes) - return h.Sum64() -} - -func (this *Flt) AddI(i *Integer) { - this.Val.Add(this.Val, i.AsBigFloat()) -} - -func (this *Flt) AddR(r *Rational) { - this.Val.Add(this.Val, r.AsBigFloat()) -} - -func (this *Flt) AddF(f *Flt) { - this.Val.Add(this.Val, f.Val) -} - -func (this *Flt) MulI(i *Integer) { - this.Val.Mul(this.Val, i.AsBigFloat()) -} - -func (this *Flt) MulR(r *Rational) { - this.Val.Mul(this.Val, r.AsBigFloat()) -} - -func (this *Flt) MulF(f *Flt) { - this.Val.Mul(this.Val, f.Val) -} - -func NewReal(v *big.Float) *Flt { - return &Flt{v} -} diff --git a/expreduce/ex_string.go b/expreduce/ex_string.go deleted file mode 100644 index a13aa7f..0000000 --- a/expreduce/ex_string.go +++ /dev/null @@ -1,61 +0,0 @@ -package expreduce - -import "fmt" -import "hash/fnv" - -type String struct { - Val string -} - -func (this *String) Eval(es *EvalState) Ex { - return this -} - -func (this *String) StringForm(params ToStringParams) string { - if (params.form == "OutputForm" || - params.form == "TraditionalForm" || - params.form == "StandardForm") { - return fmt.Sprintf("%v", this.Val) - } - return fmt.Sprintf("\"%v\"", this.Val) -} - -func (this *String) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *String) IsEqual(other Ex, cl *CASLogger) string { - otherConv, ok := other.(*String) - if !ok { - return "EQUAL_FALSE" - } - if this.Val != otherConv.Val { - return "EQUAL_FALSE" - } - return "EQUAL_TRUE" -} - -func (this *String) DeepCopy() Ex { - thiscopy := *this - return &thiscopy -} - -func (this *String) Copy() Ex { - return this.DeepCopy() -} - -func (this *String) NeedsEval() bool { - return false -} - -func (this *String) Hash() uint64 { - h := fnv.New64a() - h.Write([]byte{102, 206, 57, 172, 207, 100, 198, 133}) - h.Write([]byte(this.Val)) - return h.Sum64() -} - -func NewString(v string) *String { - return &String{v} -} diff --git a/expreduce/ex_symbol.go b/expreduce/ex_symbol.go deleted file mode 100644 index 7ba6876..0000000 --- a/expreduce/ex_symbol.go +++ /dev/null @@ -1,314 +0,0 @@ -package expreduce - -import "fmt" -import "strings" -import "sort" -import "hash/fnv" - -// Symbols are defined by a string-based name -type Symbol struct { - Name string - cachedHash uint64 -} - -func (this *Symbol) Eval(es *EvalState) Ex { - //definition, isdefined := es.defined[this.Name] - definition, isdefined, _ := es.GetDef(this.Name, this) - if isdefined { - // We must call Eval because, at this point, the expression has broken - // out of the evaluation loop. - toReturn := definition - // To handle the case where we set a variable to itself. - if sym, isSym := definition.(*Symbol); isSym { - if sym.Name == this.Name { - return toReturn - } - } - toReturn = toReturn.Eval(es) - retVal, isReturn := tryReturnValue(toReturn, nil, es) - if isReturn { - return retVal - } - return toReturn - } - return this -} - -func formatSymName(name string, params ToStringParams) string { - if params.form == "TeXForm" { - if name == "E" { - return "e" - } - if name == "Pi" { - return "\\pi" - } - if name == "Infinity" { - return "\\infty" - } - if len(name) > 1 { - return fmt.Sprintf("\\text{%v}", name) - } - } - return fmt.Sprintf("%v", name) -} - -func (this *Symbol) StringForm(params ToStringParams) string { - if len(this.Name) == 0 { - return "" - } - if strings.HasPrefix(this.Name, params.context.Val) { - return formatSymName(this.Name[len(params.context.Val):], params) - } - for _, pathPart := range params.contextPath.Parts[1:] { - path := pathPart.(*String).Val - if strings.HasPrefix(this.Name, path) { - return formatSymName(this.Name[len(path):], params) - } - } - return formatSymName(this.Name, params) -} - -func (this *Symbol) String(es *EvalState) string { - context, contextPath := DefaultStringFormArgs() - return this.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es}) -} - -func (this *Symbol) IsEqual(other Ex, cl *CASLogger) string { - otherConv, ok := other.(*Symbol) - if !ok { - return "EQUAL_UNK" - } - if this.Name == "System`False" && otherConv.Name == "System`True" { - return "EQUAL_FALSE" - } - if this.Name == "System`True" && otherConv.Name == "System`False" { - return "EQUAL_FALSE" - } - if this.Name != otherConv.Name { - return "EQUAL_UNK" - } - return "EQUAL_TRUE" -} - -func (this *Symbol) DeepCopy() Ex { - thiscopy := *this - return &thiscopy -} - -func (this *Symbol) Copy() Ex { - return this -} - -// Functions for working with the attributes of symbols: -type Attributes struct { - Orderless bool - Flat bool - OneIdentity bool - Listable bool - Constant bool - NumericFunction bool - Protected bool - Locked bool - ReadProtected bool - HoldFirst bool - HoldRest bool - HoldAll bool - HoldAllComplete bool - NHoldFirst bool - NHoldRest bool - NHoldAll bool - SequenceHold bool - Temporary bool - Stub bool -} - -func (this *Symbol) Attrs(dm *definitionMap) Attributes { - def, isDef := (*dm).Get(this.Name) - if !isDef { - return Attributes{} - } - return def.attributes -} - -func (this *Symbol) Default(dm *definitionMap) Ex { - def, isDef := (*dm).Get(this.Name) - if !isDef { - return nil - } - return def.defaultExpr -} - -func stringsToAttributes(strings []string) Attributes { - attrs := Attributes{} - for _, s := range strings { - if s == "Orderless" { - attrs.Orderless = true - } - if s == "Flat" { - attrs.Flat = true - } - if s == "OneIdentity" { - attrs.OneIdentity = true - } - if s == "Listable" { - attrs.Listable = true - } - if s == "Constant" { - attrs.Constant = true - } - if s == "NumericFunction" { - attrs.NumericFunction = true - } - if s == "Protected" { - attrs.Protected = true - } - if s == "Locked" { - attrs.Locked = true - } - if s == "ReadProtected" { - attrs.ReadProtected = true - } - if s == "HoldFirst" { - attrs.HoldFirst = true - } - if s == "HoldRest" { - attrs.HoldRest = true - } - if s == "HoldAll" { - attrs.HoldAll = true - } - if s == "HoldAllComplete" { - attrs.HoldAllComplete = true - } - if s == "NHoldFirst" { - attrs.NHoldFirst = true - } - if s == "NHoldRest" { - attrs.NHoldRest = true - } - if s == "NHoldAll" { - attrs.NHoldAll = true - } - if s == "SequenceHold" { - attrs.SequenceHold = true - } - if s == "Temporary" { - attrs.Temporary = true - } - if s == "Stub" { - attrs.Stub = true - } - } - return attrs -} - -func (this *Attributes) toStrings() []string { - var strings []string - if this.Orderless { - strings = append(strings, "Orderless") - } - if this.Flat { - strings = append(strings, "Flat") - } - if this.OneIdentity { - strings = append(strings, "OneIdentity") - } - if this.Listable { - strings = append(strings, "Listable") - } - if this.Constant { - strings = append(strings, "Constant") - } - if this.NumericFunction { - strings = append(strings, "NumericFunction") - } - if this.Protected { - strings = append(strings, "Protected") - } - if this.Locked { - strings = append(strings, "Locked") - } - if this.ReadProtected { - strings = append(strings, "ReadProtected") - } - if this.HoldFirst { - strings = append(strings, "HoldFirst") - } - if this.HoldRest { - strings = append(strings, "HoldRest") - } - if this.HoldAll { - strings = append(strings, "HoldAll") - } - if this.HoldAllComplete { - strings = append(strings, "HoldAllComplete") - } - if this.NHoldFirst { - strings = append(strings, "NHoldFirst") - } - if this.NHoldRest { - strings = append(strings, "NHoldRest") - } - if this.NHoldAll { - strings = append(strings, "NHoldAll") - } - if this.SequenceHold { - strings = append(strings, "SequenceHold") - } - if this.Temporary { - strings = append(strings, "Temporary") - } - if this.Stub { - strings = append(strings, "Stub") - } - - sort.Strings(strings) - return strings -} - -func (this *Attributes) toSymList() *Expression { - toReturn := E(S("List")) - for _, s := range this.toStrings() { - toReturn.appendEx(S(s)) - } - return toReturn -} - -func (this *Symbol) NeedsEval() bool { - return false -} - -func (this *Symbol) Hash() uint64 { - if this.cachedHash > 0 { - return this.cachedHash - } - h := fnv.New64a() - h.Write([]byte{107, 10, 247, 23, 33, 221, 163, 156}) - h.Write([]byte(this.Name)) - this.cachedHash = h.Sum64() - return h.Sum64() -} - -func ContainsSymbol(e Ex, name string) bool { - asSym, isSym := e.(*Symbol) - if isSym { - return asSym.Name == name - } - asExpr, isExpr := e.(*Expression) - if isExpr { - for _, part := range asExpr.Parts { - if ContainsSymbol(part, name) { - return true - } - } - } - return false -} - -func NewSymbol(name string) *Symbol { - return &Symbol{Name: name} -} - -func S(name string) Ex { - return NewSymbol("System`" + name) -} diff --git a/expreduce/graphics/graphics.go b/expreduce/graphics/graphics.go new file mode 100644 index 0000000..f5d4ab4 --- /dev/null +++ b/expreduce/graphics/graphics.go @@ -0,0 +1,200 @@ +package graphics + +import ( + "bytes" + "errors" + "fmt" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" + chart "github.com/wcharczuk/go-chart" + "github.com/wcharczuk/go-chart/drawing" +) + +func listToPoint(expr expreduceapi.Ex) (float64, float64, error) { + list, isList := atoms.HeadAssertion(expr, "System`List") + if !isList { + return 0, 0, fmt.Errorf("expected point to be list") + } + if list.Len() != 2 { + return 0, 0, fmt.Errorf("points should be of length 2") + } + xFlt, xIsFlt := list.GetPart(1).(*atoms.Flt) + yFlt, yIsFlt := list.GetPart(2).(*atoms.Flt) + if !xIsFlt || !yIsFlt { + return 0, 0, fmt.Errorf("point coordinates should be floats") + } + x, _ := xFlt.Val.Float64() + y, _ := yFlt.Val.Float64() + return x, y, nil +} + +func renderLine(graph *chart.Chart, line *atoms.Expression, style *chart.Style) error { + if line.Len() != 1 { + return fmt.Errorf("expected Line to have one argument, but it has %v arguments", line.Len()) + } + points, ok := atoms.HeadAssertion(line.GetPart(1), "System`List") + if !ok { + return errors.New("expected a nested list") + } + + series := chart.ContinuousSeries{} + series.Style = *style + for _, pointExpr := range points.GetParts()[1:] { + x, y, err := listToPoint(pointExpr) + if err != nil { + return err + } + series.XValues = append(series.XValues, x) + series.YValues = append(series.YValues, y) + } + graph.Series = append(graph.Series, series) + return nil +} + +func setColor(colorExpr *atoms.Expression, color *drawing.Color) error { + if colorExpr.Len() != 3 { + return fmt.Errorf("expected an RGBColor with 3 arguments") + } + for i := 0; i < 3; i++ { + asFlt, isFlt := colorExpr.GetPart(i + 1).(*atoms.Flt) + if !isFlt { + return fmt.Errorf("the RGBColor should have floating point arguments") + } + fltVal, _ := asFlt.Val.Float32() + intVal := uint8(fltVal * 255) + switch i { + case 0: + color.R = intVal + case 1: + color.G = intVal + case 2: + color.B = intVal + } + } + color.A = 255 + return nil +} + +func setOpacity(opacityExpr *atoms.Expression, color *drawing.Color) error { + if opacityExpr.Len() != 1 { + return fmt.Errorf("expected an Opacity with 1 argument") + } + asFlt, isFlt := opacityExpr.GetPart(1).(*atoms.Flt) + if !isFlt { + return fmt.Errorf("the Opacity should have a floating point argument") + } + fltVal, _ := asFlt.Val.Float32() + intVal := uint8(fltVal * 255) + color.A = intVal + return nil +} + +func setAbsoluteThickness(thicknessExpr *atoms.Expression, thickness *float64) error { + if thicknessExpr.Len() != 1 { + return fmt.Errorf("expected an AbsoluteThickness with 1 argument") + } + asFlt, isFlt := thicknessExpr.GetPart(1).(*atoms.Flt) + if !isFlt { + return fmt.Errorf("the AbsoluteThickness should have a floating point argument") + } + fltVal, _ := asFlt.Val.Float64() + *thickness = fltVal + return nil +} + +func setDirective(style *chart.Style, dir expreduceapi.Ex) error { + rgbColor, isRgbColor := atoms.HeadAssertion(dir, "System`RGBColor") + if isRgbColor { + err := setColor(rgbColor, &style.StrokeColor) + return err + } + opacity, isOpacity := atoms.HeadAssertion(dir, "System`Opacity") + if isOpacity { + err := setOpacity(opacity, &style.StrokeColor) + return err + } + thickness, isThickness := atoms.HeadAssertion(dir, "System`AbsoluteThickness") + if isThickness { + err := setAbsoluteThickness(thickness, &style.StrokeWidth) + return err + } + fmt.Printf("Skipping over unknown directive: %v\n", dir) + return nil +} + +func renderPrimitive(graph *chart.Chart, primitive expreduceapi.Ex, style *chart.Style) error { + line, isLine := atoms.HeadAssertion(primitive, "System`Line") + list, isList := atoms.HeadAssertion(primitive, "System`List") + directive, isDirective := atoms.HeadAssertion(primitive, "System`Directive") + if isList { + newStyle := *style + for _, subPrimitive := range list.GetParts()[1:] { + err := renderPrimitive(graph, subPrimitive, &newStyle) + if err != nil { + return err + } + } + } else if isDirective { + for _, directivePart := range directive.GetParts()[1:] { + err := setDirective(style, directivePart) + if err != nil { + return err + } + } + } else if isLine { + err := renderLine(graph, line, style) + if err != nil { + return err + } + } else { + fmt.Printf("Skipping over primitive: %v\n", primitive) + } + return nil +} + +// Render renders the Graphics[] object provided in expr. +func Render(expr expreduceapi.Ex) (chart.Chart, error) { + graph := chart.Chart{ + Width: 360, + Height: 220, + XAxis: chart.XAxis{ + Style: chart.StyleShow(), + }, + YAxis: chart.YAxis{ + Style: chart.StyleShow(), + }, + } + + graphics, ok := atoms.HeadAssertion(expr, "System`Graphics") + if !ok { + return graph, fmt.Errorf("trying to render a non-Graphics[] expression: %v", expr) + } + + if graphics.Len() < 1 { + return graph, errors.New("the Graphics[] expression must have at least one argument") + } + + style := chart.Style{ + Show: true, + StrokeColor: drawing.ColorBlack, + } + renderPrimitive(&graph, graphics.GetPart(1), &style) + + return graph, nil +} + +// RenderAsPNG renders the Graphics[] object provided in expr as a PNG. +func RenderAsPNG(expr expreduceapi.Ex) (string, error) { + graph, err := Render(expr) + if err != nil { + return "", err + } + + buffer := bytes.NewBuffer([]byte{}) + err = graph.Render(chart.PNG, buffer) + if err != nil { + return "", err + } + return buffer.String(), nil +} diff --git a/expreduce/interp.go b/expreduce/interp.go deleted file mode 100644 index 2c618a7..0000000 --- a/expreduce/interp.go +++ /dev/null @@ -1,568 +0,0 @@ -package expreduce - -import ( - "bytes" - "fmt" - "github.com/cznic/wl" - "go/token" - "log" - "math/big" - "strings" -) - -var inequalityOps = map[string]bool{ - "System`Equal": true, - "System`Unequal": true, - "System`Less": true, - "System`LessEqual": true, - "System`Greater": true, - "System`GreaterEqual": true, -} - -func convertToInequality(expr *Expression) *Expression { - res := E(S("Inequality")) - for i, e := range expr.Parts[1:] { - if i != 0 { - res.appendEx(expr.Parts[0]) - } - res.appendEx(e) - } - return res -} - -func fullyAssoc(op string, lhs Ex, rhs Ex) Ex { - _, opIsIneq := inequalityOps[op] - if opIsIneq { - lhsEx, lhsIsEx := lhs.(*Expression) - if lhsIsEx { - lhsHead := lhsEx.HeadStr() - _, lhsIsIneq := inequalityOps[lhsHead] - lhsIsIneq = lhsIsIneq || lhsHead == "System`Inequality" - if lhsIsIneq && op != lhsHead { - res := lhsEx - if lhsHead != "System`Inequality" { - res = convertToInequality(lhsEx) - } - res.appendEx(NewSymbol(op)) - res.appendEx(rhs) - return res - } - } - } - opExpr, isOp := HeadAssertion(lhs, op) - if isOp { - opExpr.Parts = append(opExpr.Parts, rhs) - return opExpr - } - return NewExpression([]Ex{NewSymbol(op), lhs, rhs}) -} - -func removeParens(ex Ex) { - expr, isExpr := ex.(*Expression) - if isExpr { - for i := range expr.Parts { - parens, isParens := NewEmptyExpression(), true - for isParens { - parens, isParens = HeadAssertion(expr.Parts[i], "Internal`Parens") - if isParens { - expr.Parts[i] = parens.Parts[1] - } - } - removeParens(expr.Parts[i]) - } - } - return -} - -func addContextAndDefine(e Ex, context string, contextPath []string, es *EvalState) { - if sym, isSym := e.(*Symbol); isSym { - if !strings.Contains(sym.Name, "`") { - for _, toTry := range contextPath { - if es.IsDef(toTry + sym.Name) { - sym.Name = toTry + sym.Name - return - } - } - sym.Name = context + sym.Name - } - es.MarkSeen(sym.Name) - } - expr, isExpr := e.(*Expression) - if isExpr { - for _, part := range expr.Parts { - addContextAndDefine(part, context, contextPath, es) - } - } -} - -func parsePattern(buf string) Ex { - delim := "_" - blankType := NewSymbol("System`Blank") - if strings.Contains(buf, "___") { - delim = "___" - blankType = NewSymbol("System`BlankNullSequence") - } else if strings.Contains(buf, "__") { - delim = "__" - blankType = NewSymbol("System`BlankSequence") - } - parts := strings.Split(buf, delim) - if len(parts) == 1 { - return NewExpression([]Ex{NewSymbol("System`Pattern"), NewSymbol(parts[0]), NewExpression([]Ex{blankType})}) - } - if len(parts) == 2 { - if parts[0] == "" { - if parts[1] == "" { - return NewExpression([]Ex{blankType}) - } else if delim == "_" && parts[1] == "." { - return NewExpression([]Ex{NewSymbol("System`Optional"), NewExpression([]Ex{blankType})}) - } - return NewExpression([]Ex{blankType, NewSymbol(parts[1])}) - } else { - if parts[1] == "" { - return NewExpression([]Ex{NewSymbol("System`Pattern"), NewSymbol(parts[0]), NewExpression([]Ex{blankType})}) - } else if delim == "_" && parts[1] == "." { - return NewExpression([]Ex{NewSymbol("System`Optional"), NewExpression([]Ex{NewSymbol("System`Pattern"), NewSymbol(parts[0]), NewExpression([]Ex{blankType})})}) - } - return NewExpression([]Ex{NewSymbol("System`Pattern"), NewSymbol(parts[0]), NewExpression([]Ex{blankType, NewSymbol(parts[1])})}) - } - } - return NewExpression([]Ex{NewSymbol("System`Error"), NewString("Pattern parse error.")}) -} - -var unicodeRedefineMap = map[string]string{ - "Ï€": "Pi", -} - -func ParserTokenConv(tk wl.Token) Ex { - switch tk.Rune { - case wl.IDENT: - redefined, isRedefined := unicodeRedefineMap[tk.Val] - if isRedefined { - return NewSymbol(redefined) - } - return NewSymbol(tk.Val) - case wl.INT: - base := 10 - tmpi := big.NewInt(0) - _, ok := tmpi.SetString(tk.Val, base) - if !ok { - log.Fatal("Failed in integer parsing.") - } - return NewInteger(tmpi) - case wl.FLOAT: - tmpf := big.NewFloat(0) - _, ok := tmpf.SetString(tk.Val) - if !ok { - log.Fatal("Failed in float parsing.") - } - return NewReal(tmpf) - case wl.STRING: - return NewString(tk.Val) - case wl.PATTERN: - return parsePattern(tk.Val) - case wl.SLOT: - tmpi := big.NewInt(1) - if tk.Val != "#" { - _, ok := tmpi.SetString(tk.Val[1:], 10) - if !ok { - log.Fatal("Failed in integer parsing.") - } - } - return NewExpression([]Ex{ - NewSymbol("System`Slot"), - NewInteger(tmpi), - }) - - default: - log.Fatalf("System`UnParsedToken") - } - log.Fatalf("System`UnParsedToken") - return nil -} - -func ParserTagConv(tag *wl.Tag) Ex { - return ParserTokenConv(tag.Token) -} - -func ParserExprListConv(l *wl.ExprList) (res []Ex) { - for l != nil { - if l.Expression != nil { - res = append(res, ParserExprConv(l.Expression)) - } else { - res = append(res, ParserTokenConv(l.Token)) - } - l = l.ExprList - } - return -} - -// TODO: the following maps are tightly coupled to the parser generation in -// cznic/wl. Small modifications to wl might change all these values. Fix this -// situation. - -var terminals = map[wl.ExpressionCase]bool{ - wl.ExpressionFloat: true, // FLOAT - wl.ExpressionIdent: true, // IDENT - wl.ExpressionInteger: true, // INT - wl.ExpressionPattern: true, // PATTERN - wl.ExpressionSlot: true, // SLOT - wl.ExpressionString: true, // STRING -} - -var unaryOps = map[wl.ExpressionCase]string{ - 13: "Not", - 115: "Factorial", - 117: "Function", - 15: "Plus", - 23: "Increment", - 25: "Decrement", - 0: "PreIncrement", - 1: "PreDecrement", -} - -var binaryOps = map[wl.ExpressionCase]string{ - wl.ExpressionAssign: "Set", - 39: "SetDelayed", - 33: "ReplaceRepeated", - 31: "ReplaceAll", - 27: "Rule", - 40: "RuleDelayed", - 134: "Power", - 130: "PatternTest", - 36: "Condition", - 52: "Apply", - 38: "Map", - 24: "AddTo", - 26: "SubtractFrom", - 78: "Element", -} - -var fullyAssocOps = map[wl.ExpressionCase]string{ - 125: "CompoundExpression", - wl.ExpressionAdd: "Plus", - wl.ExpressionMul: "Times", - wl.ExpressionEq: "Equal", - wl.ExpressionNe: "Unequal", - 47: "SameQ", - 45: "UnsameQ", - 44: "StringJoin", - wl.ExpressionLt: "Less", - wl.ExpressionLe: "LessEqual", - wl.ExpressionGt: "Greater", - 48: "GreaterEqual", - wl.ExpressionLOr: "Or", - wl.ExpressionLAnd: "And", - 121: "Dot", - wl.ExpressionOr: "Alternatives", - 42: "Span", -} - -var headsToTokens = map[string]int{ - "System`Alternatives": 124, - "System`And": 57347, - "System`Apply": 57348, - "System`CompoundExpression": 59, - "System`Condition": 57359, - "System`Dot": 46, - "System`Equal": 57380, - "System`Factorial": 33, - "System`Function": 38, - "System`Greater": 62, - "System`GreaterEqual": 57388, - "System`Less": 60, - "System`LessEqual": 57399, - "System`Map": 57401, - "System`Not": 33, - "System`Or": 57412, - "System`PatternTest": 63, - "System`Plus": 43, - "System`Power": 94, - "System`ReplaceAll": 57428, - "System`ReplaceRepeated": 57429, - "System`Rule": 57433, - "System`RuleDelayed": 57434, - "System`SameQ": 57435, - "System`Set": 61, - "System`SetDelayed": 57436, - "System`Span": 57439, - "System`StringJoin": 57445, - "System`Times": 42, - "System`Unequal": 57462, - "System`UnsameQ": 57464, -} - -func ParserExprConv(expr *wl.Expression) Ex { - if _, ok := terminals[expr.Case]; ok { - return ParserTokenConv(expr.Token) - } - if head, ok := binaryOps[expr.Case]; ok { - return NewExpression([]Ex{ - NewSymbol("System`" + head), - ParserExprConv(expr.Expression), - ParserExprConv(expr.Expression2), - }) - } - if head, ok := fullyAssocOps[expr.Case]; ok { - return fullyAssoc( - "System`"+head, - ParserExprConv(expr.Expression), - ParserExprConv(expr.Expression2), - ) - } - if head, ok := unaryOps[expr.Case]; ok { - return NewExpression([]Ex{ - NewSymbol("System`" + head), - ParserExprConv(expr.Expression), - }) - } - - // Special handling. - switch expr.Case { - case 124: - return fullyAssoc( - "System`CompoundExpression", - ParserExprConv(expr.Expression), - NewSymbol("System`Null"), - ) - case 123: - // TODO(corywalker): Fix parsing of "a + a_:5 + a". It should contain - // the expression Optional[a_, 5]. - e := ParserExprConv(expr.Expression) - head := "System`Pattern" - if _, isPat := HeadAssertion(e, "System`Pattern"); isPat { - head = "System`Optional" - } - return NewExpression([]Ex{ - NewSymbol(head), - e, - ParserExprConv(expr.Expression2), - }) - case wl.ExpressionMessageName: - return NewExpression([]Ex{ - NewSymbol("System`MessageName"), - ParserTokenConv(expr.Token), - NewString(ParserTagConv(expr.Tag).(*Symbol).Name), - }) - case 132: // a[] - return NewExpression([]Ex{ - ParserExprConv(expr.Expression), - }) - case 133: // a[b] - e := NewExpression([]Ex{ - ParserExprConv(expr.Expression), - }) - e.appendExArray(ParserExprListConv(expr.ExprList)) - return e - case 17: // {} - return NewExpression([]Ex{ - NewSymbol("System`List"), - }) - case 18: // {a} - e := NewExpression([]Ex{ - NewSymbol("System`List"), - }) - e.appendExArray(ParserExprListConv(expr.ExprList)) - return e - case 14: // (a) - // Internal`Parens are a placeholder to prevent fullyAssoc from - // translating "(x==2) == (x==2)" to "x == 2 == (x == 2)" - return NewExpression([]Ex{ - NewSymbol("Internal`Parens"), - ParserExprConv(expr.Expression), - }) - case 54: // a[[b]] - e := NewExpression([]Ex{ - NewSymbol("System`Part"), - ParserExprConv(expr.Expression), - }) - e.appendExArray(ParserExprListConv(expr.ExprList)) - return e - case 16: - e := ParserExprConv(expr.Expression) - if integer, isInteger := e.(*Integer); isInteger { - return NewInteger(integer.Val.Neg(integer.Val)) - } else if flt, isFlt := e.(*Flt); isFlt { - return NewReal(flt.Val.Neg(flt.Val)) - } - return NewExpression([]Ex{ - NewSymbol("System`Times"), - e, - NewInteger(big.NewInt(-1)), - }) - case 122: - return NewExpression([]Ex{ - NewSymbol("System`Times"), - ParserExprConv(expr.Expression), - NewExpression([]Ex{ - NewSymbol("System`Power"), - ParserExprConv(expr.Expression2), - NewInteger(big.NewInt(-1)), - }), - }) - case 120: - return fullyAssoc( - "System`Plus", - ParserExprConv(expr.Expression), - NewExpression([]Ex{ - NewSymbol("System`Times"), - ParserExprConv(expr.Expression2), - NewInteger(big.NewInt(-1)), - }), - ) - case 32: - return NewExpression([]Ex{ - ParserExprConv(expr.Expression2), - ParserExprConv(expr.Expression), - }) - case 131: - return NewExpression([]Ex{ - ParserExprConv(expr.Expression), - ParserExprConv(expr.Expression2), - }) - case 53: - return NewExpression([]Ex{ - NewSymbol("System`Apply"), - ParserExprConv(expr.Expression), - ParserExprConv(expr.Expression2), - E(S("List"), NewInt(1)), - }) - case 35: - set := ParserExprConv(expr.Expression2).(*Expression) - head := "System`TagSet" - if _, isDelayed := HeadAssertion(set, "System`SetDelayed"); isDelayed { - head = "System`TagSetDelayed" - } - e := NewExpression([]Ex{ - NewSymbol(head), - ParserExprConv(expr.Expression), - set.Parts[1], - set.Parts[2], - }) - return e - case 137: - return NewExpression([]Ex{ - NewExpression([]Ex{ - NewSymbol("System`Derivative"), - NewInt(1), - }), - ParserExprConv(expr.Expression), - }) - case 11: - return NewExpression([]Ex{ - NewSymbol("System`Sqrt"), - ParserExprConv(expr.Expression), - }) - case wl.ExpressionInfo: - return E( - S("Information"), - ParserTagConv(expr.Tag), - ) - case wl.ExpressionInfoShort: - return E( - S("Information"), - ParserTagConv(expr.Tag), - E(S("Rule"), S("LongForm"), S("False")), - ) - case 145: - if expr.Token.Val == "%" { - return E( - S("Out"), - E(S("Plus"), S("$Line"), NewInt(-1)), - ) - } else if expr.Token.Val == "%%" { - return E( - S("Out"), - E(S("Plus"), S("$Line"), NewInt(-2)), - ) - } - } - log.Fatalf("System`UnParsed: %+v %+v %+v", expr.Token, expr.Case, expr) - return nil -} - -func InterpBuf(buf *bytes.Buffer, fn string, es *EvalState) (Ex, error) { - // TODO(corywalker): use the interactive mode for proper newline handling. - in, err := wl.NewInput(buf, true) - if err != nil { - panic(err) - } - expr, err := in.ParseExpression(token.NewFileSet().AddFile(fn, -1, 1e6)) - if err != nil { - return NewSymbol("System`Null"), err - } - parsed := ParserExprConv(expr) - //fmt.Println(parsed) - - // Remove outer parens - parens, isParens := NewEmptyExpression(), true - for isParens { - parens, isParens = HeadAssertion(parsed, "Internal`Parens") - if isParens { - parsed = parens.Parts[1] - } - } - // Remove inner parens - removeParens(parsed) - - context := es.GetStringDef("System`$Context", "") - contextPathEx := es.GetListDef("System`$ContextPath") - contextPath := []string{} - for _, pathPart := range contextPathEx.Parts[1:] { - contextPath = append(contextPath, pathPart.(*String).Val) - } - addContextAndDefine(parsed, context, contextPath, es) - return parsed, nil -} - -func Interp(src string, es *EvalState) Ex { - buf := bytes.NewBufferString(src) - expr, err := InterpBuf(buf, "nofile", es) - if err != nil { - fmt.Printf("Syntax::sntx: %v.\n\n\n", err) - return NewSymbol("System`Null") - } - return expr -} - -func EvalInterp(src string, es *EvalState) Ex { - return Interp(src, es).Eval(es) -} - -func EvalInterpMany(doc string, fn string, es *EvalState) Ex { - buf := bytes.NewBufferString(doc) - var lastExpr Ex = NewSymbol("System`Null") - expr, err := InterpBuf(buf, fn, es) - for err == nil { - lastExpr = expr.Eval(es) - expr, err = InterpBuf(buf, fn, es) - } - if !strings.HasSuffix(err.Error(), "unexpected EOF, invalid empty input") { - fmt.Printf("Syntax::sntx: %v.\nWhile parsing: %v\n\n\n", err, buf.String()[:100]) - } - return lastExpr -} - -func ReadList(doc string, fn string, es *EvalState) Ex { - buf := bytes.NewBufferString(doc) - l := NewExpression([]Ex{NewSymbol("System`List")}) - expr, err := InterpBuf(buf, fn, es) - for err == nil { - l.appendEx(expr.Eval(es)) - expr, err = InterpBuf(buf, fn, es) - } - if !strings.HasSuffix(err.Error(), "unexpected EOF, invalid empty input") { - fmt.Printf("Syntax::sntx: %v.\nWhile parsing: %v\n\n\n", err, buf.String()[:100]) - } - return l -} - -func EasyRun(src string, es *EvalState) string { - context, contextPath := ActualStringFormArgs(es) - stringParams := ToStringParams{ - form: "InputForm", - context: context, - contextPath: contextPath, - es: es, - } - return EvalInterp(src, es).StringForm(stringParams) -} diff --git a/expreduce/interp_test.go b/expreduce/interp_test.go index 2bd3203..5a1ed01 100644 --- a/expreduce/interp_test.go +++ b/expreduce/interp_test.go @@ -2,8 +2,10 @@ package expreduce import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/stretchr/testify/assert" ) func TestInterp(t *testing.T) { @@ -11,62 +13,63 @@ func TestInterp(t *testing.T) { es := NewEvalState() - CasAssertSame(t, es, "2*x", "2x") - CasAssertSame(t, es, "2*x+5*y", "2x+5y") - CasAssertSame(t, es, "2*x+5*y", "2 x+5 y") - CasAssertSame(t, es, "2*x+5*foo[x]", "2x+5foo[x]") - CasAssertSame(t, es, "2*x+5*foo[x]", "2x+5 foo[x]") + casAssertSame(t, es, "2*x", "2x") + casAssertSame(t, es, "2*x+5*y", "2x+5y") + casAssertSame(t, es, "2*x+5*y", "2 x+5 y") + casAssertSame(t, es, "2*x+5*foo[x]", "2x+5foo[x]") + casAssertSame(t, es, "2*x+5*foo[x]", "2x+5 foo[x]") - CasAssertSame(t, es, "{x, x, g[x], g[x]}", "{f[f[x]], f[x], g[f[x]], f[g[f[x]]]} //. f[xmatch_] -> xmatch") - CasAssertSame(t, es, "foo[{x, x, g[x], g[x]}]", "{f[f[x]], f[x], g[f[x]], f[g[f[x]]]} //. f[xmatch_] -> xmatch // foo") - CasAssertSame(t, es, "3[P[1[2]]]", "P@1@2//3") + casAssertSame(t, es, "{x, x, g[x], g[x]}", "{f[f[x]], f[x], g[f[x]], f[g[f[x]]]} //. f[xmatch_] -> xmatch") + casAssertSame(t, es, "foo[{x, x, g[x], g[x]}]", "{f[f[x]], f[x], g[f[x]], f[g[f[x]]]} //. f[xmatch_] -> xmatch // foo") + casAssertSame(t, es, "3[P[1[2]]]", "P@1@2//3") // TODO: Currently does not work: - //CasAssertSame(t, es, "(x^2)*y", "x^2 y") + //casAssertSame(t, es, "(x^2)*y", "x^2 y") // Test Slots - CasAssertSame(t, es, "Slot[1]", "#") - CasAssertSame(t, es, "Slot[2]", "#2") - CasAssertSame(t, es, "3*Slot[2]", "3#2") + casAssertSame(t, es, "Slot[1]", "#") + casAssertSame(t, es, "Slot[2]", "#2") + casAssertSame(t, es, "3*Slot[2]", "3#2") // Test PatternTest - CasAssertSame(t, es, "PatternTest[a,b]", "a?b") - //CasAssertSame(t, es, "PatternTest[foo[a], bar][b]", "foo[a]?bar[b]") - CasAssertSame(t, es, "PatternTest[foo[a], bar[b]]", "foo[a]?(bar[b])") - CasAssertSame(t, es, "PatternTest[Pattern[a, Blank[Integer]], NumberQ]", "a_Integer?NumberQ") - CasAssertSame(t, es, "PatternTest[Pattern[a, Blank[Integer]], Function[Divisible[Slot[1], 7]]]", "a_Integer?(Function[Divisible[#, 7]])") + casAssertSame(t, es, "PatternTest[a,b]", "a?b") + //casAssertSame(t, es, "PatternTest[foo[a], bar][b]", "foo[a]?bar[b]") + casAssertSame(t, es, "PatternTest[foo[a], bar[b]]", "foo[a]?(bar[b])") + casAssertSame(t, es, "PatternTest[Pattern[a, Blank[Integer]], NumberQ]", "a_Integer?NumberQ") + casAssertSame(t, es, "PatternTest[Pattern[a, Blank[Integer]], Function[Divisible[Slot[1], 7]]]", "a_Integer?(Function[Divisible[#, 7]])") // Test precedence of equality, rules, and ReplaceAll - CasAssertSame(t, es, "Hold[ReplaceAll[Equal[1, 2], Rule[2, Equal[3, x]]]]", "Hold[1 == 2 /. 2 -> 3 == x]") + casAssertSame(t, es, "Hold[ReplaceAll[Equal[1, 2], Rule[2, Equal[3, x]]]]", "Hold[1 == 2 /. 2 -> 3 == x]") // Test Condition - CasAssertSame(t, es, "Condition[a,b]", "a/;b") - CasAssertSame(t, es, "Hold[Condition[a,b]]", "Hold[a/;b]") - //CasAssertSame(t, es, "Hold[CompoundExpression[Condition[a,b],Condition[a,b]]]", "Hold[a/;b ; a/;b]") - CasAssertSame(t, es, "Hold[Condition[List[Pattern[x, Blank[]], Pattern[x, Blank[]]], Equal[Plus[x, x], 2]]]", "Hold[{x_,x_}/;x+x==2]") - CasAssertSame(t, es, "Hold[SetDelayed[foo[Pattern[x, Blank[]]], Condition[bar[x], Equal[x, 0]]]]", "Hold[foo[x_] := bar[x] /; x == 0]") - CasAssertSame(t, es, "Hold[ReplaceAll[List[5, 0, -5], Rule[Condition[Pattern[y, Blank[]], Equal[y, 0]], z]]]", "Hold[{5, 0, -5} /. y_ /; y == 0 -> z]") + casAssertSame(t, es, "Condition[a,b]", "a/;b") + casAssertSame(t, es, "Hold[Condition[a,b]]", "Hold[a/;b]") + //casAssertSame(t, es, "Hold[CompoundExpression[Condition[a,b],Condition[a,b]]]", "Hold[a/;b ; a/;b]") + casAssertSame(t, es, "Hold[Condition[List[Pattern[x, Blank[]], Pattern[x, Blank[]]], Equal[Plus[x, x], 2]]]", "Hold[{x_,x_}/;x+x==2]") + casAssertSame(t, es, "Hold[SetDelayed[foo[Pattern[x, Blank[]]], Condition[bar[x], Equal[x, 0]]]]", "Hold[foo[x_] := bar[x] /; x == 0]") + casAssertSame(t, es, "Hold[ReplaceAll[List[5, 0, -5], Rule[Condition[Pattern[y, Blank[]], Equal[y, 0]], z]]]", "Hold[{5, 0, -5} /. y_ /; y == 0 -> z]") // Test MessageName - CasAssertSame(t, es, "Hold[MessageName[a,\"b\"]]", "Hold[a::b]") - CasAssertSame(t, es, "MessageName[a,\"b\"]", "a::b") + casAssertSame(t, es, "Hold[MessageName[a,\"b\"]]", "Hold[a::b]") + casAssertSame(t, es, "MessageName[a,\"b\"]", "a::b") // Test StringJoin - CasAssertSame(t, es, "StringJoin[\"a\", \" world\", \"hi\"]", "\"a\" <> \" world\" <> \"hi\"") + casAssertSame(t, es, "StringJoin[\"a\", \" world\", \"hi\"]", "\"a\" <> \" world\" <> \"hi\"") // Test Not and Factorial - CasAssertSame(t, es, "Factorial[a]", "a!") - CasAssertSame(t, es, "Not[a]", "!a") - CasAssertSame(t, es, "Factorial[a]*b", "a!b") + casAssertSame(t, es, "Factorial[a]", "a!") + casAssertSame(t, es, "Not[a]", "!a") + casAssertSame(t, es, "Factorial[a]*b", "a!b") // Test Optional and Pattern // Currently disabled because issue #79 - //CasAssertSame(t, es, "Plus[a,Pattern[a,5]]", "a + a : 5") - //CasAssertSame(t, es, "Plus[a,Optional[Pattern[a,Blank[]],5]]", "a + a_ : 5") - //CasAssertSame(t, es, "Plus[Times[2,a],Optional[Pattern[a,Blank[]],5]]", "a + a_ : 5 + a") + //casAssertSame(t, es, "Plus[a,Pattern[a,5]]", "a + a : 5") + //casAssertSame(t, es, "Plus[a,Optional[Pattern[a,Blank[]],5]]", "a + a_ : 5") + //casAssertSame(t, es, "Plus[Times[2,a],Optional[Pattern[a,Blank[]],5]]", "a + a_ : 5 + a") // Test newline handling - assert.Equal(t, "CompoundExpression[a, b]", Interp("a;b\n", es).String(es)) - //assert.Equal(t, "Sequence[a, b]", Interp("a\nb\n", es).String(es)) - assert.Equal(t, "(c = a*b)", Interp("c = (a\nb)\n", es).String(es)) - assert.Equal(t, "(c = a*b)", Interp("c = (a\n\nb)\n", es).String(es)) + stringParams := ActualStringFormArgsFull("InputForm", es) + assert.Equal(t, "CompoundExpression[a, b]", parser.Interp("a;b\n", es).StringForm(stringParams)) + //assert.Equal(t, "Sequence[a, b]", parser.Interp("a\nb\n", es).StringForm(stringParams)) + assert.Equal(t, "c = a*b", parser.Interp("c = (a\nb)\n", es).StringForm(stringParams)) + assert.Equal(t, "c = a*b", parser.Interp("c = (a\n\nb)\n", es).StringForm(stringParams)) } diff --git a/expreduce/iterspec.go b/expreduce/iterspec.go deleted file mode 100644 index c8fbc34..0000000 --- a/expreduce/iterspec.go +++ /dev/null @@ -1,261 +0,0 @@ -package expreduce - -import "math/big" - -type iterSpec interface { - // Should be called before every iteration: - reset() - next() - cont() bool - getCurr() Ex - getI() Ex - getIName() string -} - -type iterSpecRange struct { - i Ex - iName string - iMin Ex - iMax Ex - step Ex - curr Ex - es *EvalState -} - -type iterSpecList struct { - i Ex - iName string - pos int - list *Expression -} - -func tryIterParam(e Ex) (Ex, bool) { - if _, isInt := e.(*Integer); isInt { - return e, true - } - if _, isReal := e.(*Flt); isReal { - return e, true - } - if _, isRat := e.(*Rational); isRat { - return e, true - } - if _, isComp := e.(*Complex); isComp { - return e, true - } - return nil, false -} - -func iterSpecFromList(es *EvalState, listEx Ex) (iterSpec, bool) { - isr := &iterSpecRange{} - isr.es = es - isl := &iterSpecList{} - - listEx = evalIterSpecCandidate(es, listEx) - list, isList := HeadAssertion(listEx, "System`List") - if isList { - iOk, iMinOk, iMaxOk, stepOk := false, false, false, false - if len(list.Parts) > 2 { - iAsSymbol, iIsSymbol := list.Parts[1].(*Symbol) - if iIsSymbol { - iOk = true - isr.i, isl.i = iAsSymbol, iAsSymbol - isr.iName, isl.iName = iAsSymbol.Name, iAsSymbol.Name - } - iAsExpression, iIsExpression := list.Parts[1].(*Expression) - if iIsExpression { - headAsSymbol, headIsSymbol := iAsExpression.Parts[0].(*Symbol) - if headIsSymbol { - iOk = true - isr.i, isl.i = iAsExpression, iAsExpression - isr.iName, isl.iName = headAsSymbol.Name, headAsSymbol.Name - } - } - } - if len(list.Parts) == 3 { - isr.iMin, iMinOk = NewInteger(big.NewInt(1)), true - isr.iMax, iMaxOk = tryIterParam(list.Parts[2]) - isr.step, stepOk = NewInteger(big.NewInt(1)), true - } else if len(list.Parts) == 4 { - isr.iMin, iMinOk = tryIterParam(list.Parts[2]) - isr.iMax, iMaxOk = tryIterParam(list.Parts[3]) - isr.step, stepOk = NewInteger(big.NewInt(1)), true - } else if len(list.Parts) == 5 { - isr.iMin, iMinOk = tryIterParam(list.Parts[2]) - isr.iMax, iMaxOk = tryIterParam(list.Parts[3]) - isr.step, stepOk = tryIterParam(list.Parts[4]) - } - if iOk && iMinOk && iMaxOk && stepOk { - isr.reset() - return isr, true - } - - // Conversion to iterSpecRange failed. Try iterSpecList. - iterListOk := false - if len(list.Parts) == 3 { - isl.list, iterListOk = HeadAssertion(list.Parts[2], "System`List") - } - if iOk && iterListOk { - isl.reset() - return isl, true - } - } - return isr, false -} - -func (this *iterSpecRange) reset() { - //this.curr = this.iMin - this.curr = E(S("Plus"), this.iMin, E(S("Times"), NewInt(0), this.step)).Eval(this.es) -} - -func (this *iterSpecRange) next() { - this.curr = E(S("Plus"), this.curr, this.step).Eval(this.es) -} - -func (this *iterSpecRange) cont() bool { - return ExOrder(this.curr, this.iMax) >= 0 -} - -func (this *iterSpecRange) getCurr() Ex { - return this.curr -} - -func (this *iterSpecRange) getI() Ex { - return this.i -} - -func (this *iterSpecRange) getIName() string { - return this.iName -} - -func (this *iterSpecList) reset() { - this.pos = 1 -} - -func (this *iterSpecList) next() { - this.pos++ -} - -func (this *iterSpecList) cont() bool { - return this.pos < len(this.list.Parts) -} - -func (this *iterSpecList) getCurr() Ex { - return this.list.Parts[this.pos] -} - -func (this *iterSpecList) getI() Ex { - return this.i -} - -func (this *iterSpecList) getIName() string { - return this.iName -} - -type multiIterSpec struct { - iSpecs []iterSpec - origDefs []Ex - isOrigDefs []bool - shouldCont bool -} - -func multiIterSpecFromLists(es *EvalState, lists []Ex) (mis multiIterSpec, isOk bool) { - // Retrieve variables of iteration - mis.shouldCont = true - for i := range lists { - is, isOk := iterSpecFromList(es, lists[i]) - if !isOk { - return mis, false - } - mis.iSpecs = append(mis.iSpecs, is) - mis.shouldCont = mis.shouldCont && is.cont() - } - return mis, true -} - -func (this *multiIterSpec) next() { - for i := len(this.iSpecs) - 1; i >= 0; i-- { - this.iSpecs[i].next() - if this.iSpecs[i].cont() { - return - } - this.iSpecs[i].reset() - } - this.shouldCont = false -} - -func (this *multiIterSpec) cont() bool { - return this.shouldCont -} - -func (this *multiIterSpec) takeVarSnapshot(es *EvalState) { - this.origDefs = make([]Ex, len(this.iSpecs)) - this.isOrigDefs = make([]bool, len(this.iSpecs)) - for i := range this.iSpecs { - this.origDefs[i], this.isOrigDefs[i], _ = es.GetDef(this.iSpecs[i].getIName(), this.iSpecs[i].getI()) - } -} - -func (this *multiIterSpec) restoreVarSnapshot(es *EvalState) { - for i := range this.iSpecs { - if this.isOrigDefs[i] { - es.Define(this.iSpecs[i].getI(), this.origDefs[i]) - } else { - es.Clear(this.iSpecs[i].getIName()) - } - } -} - -func (this *multiIterSpec) defineCurrent(es *EvalState) { - for i := range this.iSpecs { - es.Define(this.iSpecs[i].getI(), this.iSpecs[i].getCurr()) - } -} - -func (this *multiIterSpec) currentPDManager() *PDManager { - pm := &PDManager{make(map[string]Ex)} - for i := range this.iSpecs { - pm.patternDefined[this.iSpecs[i].getIName()] = this.iSpecs[i].getCurr() - } - return pm -} - -func (this *Expression) evalIterationFunc(es *EvalState, init Ex, op string) Ex { - if len(this.Parts) >= 3 { - mis, isOk := multiIterSpecFromLists(es, this.Parts[2:]) - if isOk { - // Simulate evaluation within Block[] - mis.takeVarSnapshot(es) - var toReturn Ex = init - for mis.cont() { - mis.defineCurrent(es) - toReturn = (NewExpression([]Ex{NewSymbol(op), toReturn, this.Parts[1].DeepCopy().Eval(es)})).Eval(es) - mis.next() - } - mis.restoreVarSnapshot(es) - return toReturn - } - } - return this -} - -func evalIterSpecCandidate(es *EvalState, cand Ex) Ex { - // Special handling for Lists, which might have variables of iteration in - // them. - list, isList := HeadAssertion(cand, "System`List") - if isList { - toReturn := NewExpression([]Ex{NewSymbol("System`List")}) - for i := 1; i < len(list.Parts); i++ { - toAdd := list.Parts[i].DeepCopy() - // Do not evaluate the variable of iteration. Even if "n" is - // defined already, we just want it to be "n". - if i != 1 { - toAdd = toAdd.Eval(es) - } - toReturn.Parts = append(toReturn.Parts, toAdd) - } - return toReturn - } - // We should attempt to evaluate all non-Lists, since we expect them to not - // have any variables of iteration in them. - return cand.Eval(es) -} diff --git a/expreduce/iterspec/iterspec.go b/expreduce/iterspec/iterspec.go new file mode 100644 index 0000000..38ab66a --- /dev/null +++ b/expreduce/iterspec/iterspec.go @@ -0,0 +1,267 @@ +package iterspec + +import ( + "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type IterSpec interface { + // Should be called before every iteration: + reset() + Next() + Cont() bool + GetCurr() expreduceapi.Ex + getI() expreduceapi.Ex + getIName() string +} + +type iterSpecRange struct { + i expreduceapi.Ex + iName string + iMin expreduceapi.Ex + iMax expreduceapi.Ex + step expreduceapi.Ex + curr expreduceapi.Ex + es expreduceapi.EvalStateInterface +} + +type iterSpecList struct { + i expreduceapi.Ex + iName string + pos int + list expreduceapi.ExpressionInterface +} + +func tryIterParam(e expreduceapi.Ex) (expreduceapi.Ex, bool) { + if _, isInt := e.(*atoms.Integer); isInt { + return e, true + } + if _, isReal := e.(*atoms.Flt); isReal { + return e, true + } + if _, isRat := e.(*atoms.Rational); isRat { + return e, true + } + if _, isComp := e.(*atoms.Complex); isComp { + return e, true + } + return nil, false +} + +func SpecFromList(es expreduceapi.EvalStateInterface, listEx expreduceapi.Ex) (IterSpec, bool) { + isr := &iterSpecRange{} + isr.es = es + isl := &iterSpecList{} + + listEx = evalIterSpecCandidate(es, listEx) + list, isList := atoms.HeadAssertion(listEx, "System`List") + if isList { + iOk, iMinOk, iMaxOk, stepOk := false, false, false, false + if len(list.GetParts()) > 2 { + iAsSymbol, iIsSymbol := list.GetParts()[1].(*atoms.Symbol) + if iIsSymbol { + iOk = true + isr.i, isl.i = iAsSymbol, iAsSymbol + isr.iName, isl.iName = iAsSymbol.Name, iAsSymbol.Name + } + iAsExpression, iIsExpression := list.GetParts()[1].(expreduceapi.ExpressionInterface) + if iIsExpression { + headAsSymbol, headIsSymbol := iAsExpression.GetParts()[0].(*atoms.Symbol) + if headIsSymbol { + iOk = true + isr.i, isl.i = iAsExpression, iAsExpression + isr.iName, isl.iName = headAsSymbol.Name, headAsSymbol.Name + } + } + } + if len(list.GetParts()) == 3 { + isr.iMin, iMinOk = atoms.NewInteger(big.NewInt(1)), true + isr.iMax, iMaxOk = tryIterParam(list.GetParts()[2]) + isr.step, stepOk = atoms.NewInteger(big.NewInt(1)), true + } else if len(list.GetParts()) == 4 { + isr.iMin, iMinOk = tryIterParam(list.GetParts()[2]) + isr.iMax, iMaxOk = tryIterParam(list.GetParts()[3]) + isr.step, stepOk = atoms.NewInteger(big.NewInt(1)), true + } else if len(list.GetParts()) == 5 { + isr.iMin, iMinOk = tryIterParam(list.GetParts()[2]) + isr.iMax, iMaxOk = tryIterParam(list.GetParts()[3]) + isr.step, stepOk = tryIterParam(list.GetParts()[4]) + } + if iOk && iMinOk && iMaxOk && stepOk { + isr.reset() + return isr, true + } + + // Conversion to iterSpecRange failed. Try iterSpecList. + iterListOk := false + if len(list.GetParts()) == 3 { + isl.list, iterListOk = atoms.HeadAssertion(list.GetParts()[2], "System`List") + } + if iOk && iterListOk { + isl.reset() + return isl, true + } + } + return isr, false +} + +func (isr *iterSpecRange) reset() { + //isr.curr = isr.iMin + isr.curr = isr.es.Eval(atoms.E(atoms.S("Plus"), isr.iMin, atoms.E(atoms.S("Times"), atoms.NewInt(0), isr.step))) +} + +func (isr *iterSpecRange) Next() { + isr.curr = isr.es.Eval(atoms.E(atoms.S("Plus"), isr.curr, isr.step)) +} + +func (isr *iterSpecRange) Cont() bool { + return atoms.ExOrder(isr.curr, isr.iMax) >= 0 +} + +func (isr *iterSpecRange) GetCurr() expreduceapi.Ex { + return isr.curr +} + +func (isr *iterSpecRange) getI() expreduceapi.Ex { + return isr.i +} + +func (isr *iterSpecRange) getIName() string { + return isr.iName +} + +func (isl *iterSpecList) reset() { + isl.pos = 1 +} + +func (isl *iterSpecList) Next() { + isl.pos++ +} + +func (isl *iterSpecList) Cont() bool { + return isl.pos < len(isl.list.GetParts()) +} + +func (isl *iterSpecList) GetCurr() expreduceapi.Ex { + return isl.list.GetParts()[isl.pos] +} + +func (isl *iterSpecList) getI() expreduceapi.Ex { + return isl.i +} + +func (isl *iterSpecList) getIName() string { + return isl.iName +} + +type MultiIterSpec struct { + iSpecs []IterSpec + origDefs []expreduceapi.Ex + isOrigDefs []bool + shouldCont bool +} + +func MultiSpecFromLists(es expreduceapi.EvalStateInterface, lists []expreduceapi.Ex) (mis MultiIterSpec, isOk bool) { + // Retrieve variables of iteration + mis.shouldCont = true + for i := range lists { + is, isOk := SpecFromList(es, lists[i]) + if !isOk { + return mis, false + } + mis.iSpecs = append(mis.iSpecs, is) + mis.shouldCont = mis.shouldCont && is.Cont() + } + return mis, true +} + +func (mis *MultiIterSpec) Next() { + for i := len(mis.iSpecs) - 1; i >= 0; i-- { + mis.iSpecs[i].Next() + if mis.iSpecs[i].Cont() { + return + } + mis.iSpecs[i].reset() + } + mis.shouldCont = false +} + +func (mis *MultiIterSpec) Cont() bool { + return mis.shouldCont +} + +func (mis *MultiIterSpec) TakeVarSnapshot(es expreduceapi.EvalStateInterface) { + mis.origDefs = make([]expreduceapi.Ex, len(mis.iSpecs)) + mis.isOrigDefs = make([]bool, len(mis.iSpecs)) + for i := range mis.iSpecs { + mis.origDefs[i], mis.isOrigDefs[i], _ = es.GetDef(mis.iSpecs[i].getIName(), mis.iSpecs[i].getI()) + } +} + +func (mis *MultiIterSpec) RestoreVarSnapshot(es expreduceapi.EvalStateInterface) { + for i := range mis.iSpecs { + if mis.isOrigDefs[i] { + es.Define(mis.iSpecs[i].getI(), mis.origDefs[i]) + } else { + es.Clear(mis.iSpecs[i].getIName()) + } + } +} + +func (mis *MultiIterSpec) DefineCurrent(es expreduceapi.EvalStateInterface) { + for i := range mis.iSpecs { + es.Define(mis.iSpecs[i].getI(), mis.iSpecs[i].GetCurr()) + } +} + +func (mis *MultiIterSpec) CurrentPDManager() *matcher.PDManager { + pm := matcher.EmptyPD() + for i := range mis.iSpecs { + pm.Define(mis.iSpecs[i].getIName(), mis.iSpecs[i].GetCurr()) + } + return pm +} + +func EvalIterationFunc(expr expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface, init expreduceapi.Ex, op string) expreduceapi.Ex { + if len(expr.GetParts()) >= 3 { + mis, isOk := MultiSpecFromLists(es, expr.GetParts()[2:]) + if isOk { + // Simulate evaluation within Block[] + mis.TakeVarSnapshot(es) + var toReturn expreduceapi.Ex = init + for mis.Cont() { + mis.DefineCurrent(es) + toReturn = es.Eval((atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol(op), toReturn, es.Eval(expr.GetParts()[1].DeepCopy())}))) + mis.Next() + } + mis.RestoreVarSnapshot(es) + return toReturn + } + } + return expr +} + +func evalIterSpecCandidate(es expreduceapi.EvalStateInterface, cand expreduceapi.Ex) expreduceapi.Ex { + // Special handling for Lists, which might have variables of iteration in + // them. + list, isList := atoms.HeadAssertion(cand, "System`List") + if isList { + toReturn := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + for i := 1; i < len(list.GetParts()); i++ { + toAdd := list.GetParts()[i].DeepCopy() + // Do not evaluate the variable of iteration. Even if "n" is + // defined already, we just want it to be "n". + if i != 1 { + toAdd = es.Eval(toAdd) + } + toReturn.AppendEx(toAdd) + } + return toReturn + } + // We should attempt to evaluate all non-Lists, since we expect them to not + // have any variables of iteration in them. + return es.Eval(cand) +} diff --git a/expreduce/logging/caslogger.go b/expreduce/logging/caslogger.go new file mode 100644 index 0000000..ff73ee8 --- /dev/null +++ b/expreduce/logging/caslogger.go @@ -0,0 +1,84 @@ +package logging + +import ( + "os" + "sync" + + gologging "github.com/op/go-logging" +) + +var format = gologging.MustStringFormatter( + `%{color}%{time:15:04:05.000} %{callpath} â–¶ %{id:03x}%{color:reset} %{message}`, +) +var goLoggingMutex = &sync.Mutex{} + +// CASLogger keeps track of logging state for the language. +type CASLogger struct { + _log *gologging.Logger + leveled gologging.LeveledBackend + debugState bool + isProfiling bool +} + +// Debugf logs a debug-level message. +func (cl *CASLogger) Debugf(fmt string, args ...interface{}) { + if cl.debugState { + //cl._log.Debugf(cl.pre() + fmt, args...) + cl._log.Debugf(fmt, args...) + } +} + +// Infof logs an info-level message. +func (cl *CASLogger) Infof(fmt string, args ...interface{}) { + if cl.debugState { + //cl._log.Infof(cl.pre() + fmt, args...) + cl._log.Infof(fmt, args...) + } +} + +// Errorf logs an error-level message. +func (cl *CASLogger) Errorf(fmt string, args ...interface{}) { + cl._log.Errorf(fmt, args...) +} + +// DebugOn turns on debug features. +func (cl *CASLogger) DebugOn(level gologging.Level) { + cl.leveled.SetLevel(level, "") + cl.debugState = true + cl.SetProfiling(true) +} + +// DebugOff turns off debug features. +func (cl *CASLogger) DebugOff() { + cl.leveled.SetLevel(gologging.ERROR, "") + cl.debugState = false + cl.SetProfiling(false) +} + +// SetDebugState turns the ability to log off and on. +func (cl *CASLogger) SetDebugState(newState bool) { + cl.debugState = newState +} + +// IsProfiling returns if the interpreter should be profiling. +func (cl *CASLogger) IsProfiling() bool { + return cl.isProfiling +} + +// SetProfiling sets if the interpreter should be profiling. +func (cl *CASLogger) SetProfiling(profiling bool) { + cl.isProfiling = profiling +} + +// SetUpLogging initializes this logging state. +func (cl *CASLogger) SetUpLogging() { + // go-logging appears to not be thread safe, so we have a mutex when + // configuring the logging. + goLoggingMutex.Lock() + cl._log = gologging.MustGetLogger("example") + backend := gologging.NewLogBackend(os.Stderr, "", 0) + formatter := gologging.NewBackendFormatter(backend, format) + cl.leveled = gologging.AddModuleLevel(formatter) + gologging.SetBackend(cl.leveled) + goLoggingMutex.Unlock() +} diff --git a/expreduce/allocations.go b/expreduce/matcher/allocations.go similarity index 92% rename from expreduce/allocations.go rename to expreduce/matcher/allocations.go index d056bbb..aedfe7a 100644 --- a/expreduce/allocations.go +++ b/expreduce/matcher/allocations.go @@ -1,4 +1,11 @@ -package expreduce +package matcher + +func min(x, y int) int { + if x < y { + return x + } + return y +} type allocIterState struct { currForm int @@ -36,14 +43,14 @@ func (ai *allocIter) next() bool { // TODO: clean up this code and determine if we ever need to handle // an optional form without a startI == 0 and endI == 1. if ai.forms[p.currForm].isOptional { - for i := ai.forms[p.currForm].startI; i <= Min(ai.forms[p.currForm].endI, p.remaining); i++ { + for i := ai.forms[p.currForm].startI; i <= min(ai.forms[p.currForm].endI, p.remaining); i++ { if p.remaining-i >= 0 { ai.stack = append(ai.stack, allocIterState{ p.currForm + 1, p.remaining - i, i}) } } } else { - for i := Min(ai.forms[p.currForm].endI, p.remaining); i >= ai.forms[p.currForm].startI; i-- { + for i := min(ai.forms[p.currForm].endI, p.remaining); i >= ai.forms[p.currForm].startI; i-- { if p.remaining-i >= 0 { ai.stack = append(ai.stack, allocIterState{ p.currForm + 1, p.remaining - i, i}) @@ -55,7 +62,7 @@ func (ai *allocIter) next() bool { return false } -func NewAllocIter(l int, forms []parsedForm) allocIter { +func newAllocIter(l int, forms []parsedForm) allocIter { ai := allocIter{} ai.forms = forms ai.alloc = make([]int, len(forms)) @@ -172,7 +179,7 @@ func (asi *assnIter) next() bool { return false } -func NewAssnIter(l int, forms []parsedForm, formMatches [][]bool, orderless bool) assnIter { +func newAssnIter(l int, forms []parsedForm, formMatches [][]bool, orderless bool) assnIter { asi := assnIter{} asi.forms = forms asi.assnData = make([]int, l) @@ -182,7 +189,7 @@ func NewAssnIter(l int, forms []parsedForm, formMatches [][]bool, orderless bool asi.taken = make([]bool, l) asi.formMatches = formMatches - asi.ai = NewAllocIter(len(asi.assnData), asi.forms) + asi.ai = newAllocIter(len(asi.assnData), asi.forms) for i := range asi.assnData { asi.assnData[i] = i } diff --git a/expreduce/allocations_test.go b/expreduce/matcher/allocations_test.go similarity index 89% rename from expreduce/allocations_test.go rename to expreduce/matcher/allocations_test.go index fe9dd8b..1be82e1 100644 --- a/expreduce/allocations_test.go +++ b/expreduce/matcher/allocations_test.go @@ -1,9 +1,10 @@ -package expreduce +package matcher import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func newPf(startI int, endI int) parsedForm { @@ -32,7 +33,7 @@ func TestAllocations(t *testing.T) { newPf(0, 1), newPf(0, 99999), } - ai := NewAllocIter(4, forms) + ai := newAllocIter(4, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{1, 0, 3}, ai.alloc) assert.Equal(t, true, ai.next()) @@ -47,7 +48,7 @@ func TestAllocations(t *testing.T) { newPf(1, 1), newPf(0, 99999), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{1, 3}, ai.alloc) assert.Equal(t, false, ai.next()) @@ -57,7 +58,7 @@ func TestAllocations(t *testing.T) { newPf(1, 1), newPf(0, 99999), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{1, 1, 2}, ai.alloc) assert.Equal(t, false, ai.next()) @@ -69,7 +70,7 @@ func TestAllocations(t *testing.T) { } forms[0].isOptional = true forms[1].isOptional = true - ai = NewAllocIter(3, forms) + ai = newAllocIter(3, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{1, 1, 1}, ai.alloc) assert.Equal(t, true, ai.next()) @@ -85,7 +86,7 @@ func TestAllocations(t *testing.T) { newPf(1, 1), newPf(0, 99999), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{0, 1, 3}, ai.alloc) assert.Equal(t, true, ai.next()) @@ -99,7 +100,7 @@ func TestAllocations(t *testing.T) { forms = []parsedForm{ newPf(0, 99999), } - ai = NewAllocIter(0, forms) + ai = newAllocIter(0, forms) assert.Equal(t, true, ai.next()) assert.Equal(t, []int{0}, ai.alloc) assert.Equal(t, false, ai.next()) @@ -107,28 +108,28 @@ func TestAllocations(t *testing.T) { forms = []parsedForm{ newPf(1, 99999), } - ai = NewAllocIter(0, forms) + ai = newAllocIter(0, forms) assert.Equal(t, false, ai.next()) // Impossible configuration. Should return false immediately. forms = []parsedForm{ newPf(5, 5), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, false, ai.next()) // Impossible configuration. Should return false immediately. forms = []parsedForm{ newPf(1, 1), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, false, ai.next()) // Impossible configuration. Should return false immediately. forms = []parsedForm{ newPf(5, 0), } - ai = NewAllocIter(4, forms) + ai = newAllocIter(4, forms) assert.Equal(t, false, ai.next()) forms = []parsedForm{ @@ -136,7 +137,7 @@ func TestAllocations(t *testing.T) { newPf(1, 1), newPf(0, 999999), } - ai = NewAllocIter(800000, forms) + ai = newAllocIter(800000, forms) num := 0 for num = 0; ai.next(); num++ { } @@ -150,7 +151,7 @@ func TestAllocations(t *testing.T) { newPf(1, 1), newPf(0, 999999), } - ai = NewAllocIter(1400, forms) + ai = newAllocIter(1400, forms) for num = 0; ai.next(); num++ { } assert.Equal(t, 979300, num) @@ -176,7 +177,7 @@ func TestAssignments(t *testing.T) { newPf(0, 99999), } nComps := 3 - ai := NewAssnIter(nComps, forms, allMatch(nComps, len(forms)), true) + ai := newAssnIter(nComps, forms, allMatch(nComps, len(forms)), true) assert.Equal(t, true, ai.next()) assert.Equal(t, [][]int{{}, {0}, {1, 2}}, ai.assns) assert.Equal(t, true, ai.next()) @@ -197,7 +198,7 @@ func TestAssignments(t *testing.T) { assert.Equal(t, [][]int{{2}, {1}, {0}}, ai.assns) assert.Equal(t, false, ai.next()) - ai = NewAssnIter(nComps, forms, allMatch(nComps, len(forms)), false) + ai = newAssnIter(nComps, forms, allMatch(nComps, len(forms)), false) assert.Equal(t, true, ai.next()) assert.Equal(t, [][]int{{}, {0}, {1, 2}}, ai.assns) assert.Equal(t, true, ai.next()) @@ -216,7 +217,7 @@ func TestAssignments(t *testing.T) { {false, true, false}, {true, true, true}, } - ai = NewAssnIter(nComps, forms, formMatches, true) + ai = newAssnIter(nComps, forms, formMatches, true) assert.Equal(t, true, ai.next()) assert.Equal(t, [][]int{{0}, {1}, {2}}, ai.assns) assert.Equal(t, true, ai.next()) @@ -232,7 +233,7 @@ func TestAssignments(t *testing.T) { {true, true, true}, {true, false, false}, } - ai = NewAssnIter(nComps, forms, formMatches, true) + ai = newAssnIter(nComps, forms, formMatches, true) assert.Equal(t, true, ai.next()) assert.Equal(t, [][]int{{1, 2}, {0}}, ai.assns) assert.Equal(t, false, ai.next()) @@ -246,14 +247,14 @@ func TestAssignments(t *testing.T) { newPf(0, 999999), } nComps = 1400 - ai = NewAssnIter(nComps, forms, allMatch(nComps, len(forms)), false) + ai = newAssnIter(nComps, forms, allMatch(nComps, len(forms)), false) num := 0 for num = 0; ai.next(); num++ { } assert.Equal(t, 979300, num) nComps = 8 - ai = NewAssnIter(nComps, forms, allMatch(nComps, len(forms)), true) + ai = newAssnIter(nComps, forms, allMatch(nComps, len(forms)), true) for num = 0; ai.next(); num++ { } assert.Equal(t, 40824, num) diff --git a/expreduce/matcher/blank.go b/expreduce/matcher/blank.go new file mode 100644 index 0000000..c56fab5 --- /dev/null +++ b/expreduce/matcher/blank.go @@ -0,0 +1,107 @@ +package matcher + +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func isBlankTypeOnly(e expreduceapi.Ex) bool { + asPattern, patternOk := atoms.HeadAssertion(e, "System`Pattern") + if patternOk { + _, blankOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`Blank") + _, bsOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`BlankSequence") + _, bnsOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`BlankNullSequence") + if blankOk || bsOk || bnsOk { + return true + } + } + _, blankOk := atoms.HeadAssertion(e, "System`Blank") + _, bsOk := atoms.HeadAssertion(e, "System`BlankSequence") + _, bnsOk := atoms.HeadAssertion(e, "System`BlankNullSequence") + if blankOk || bsOk || bnsOk { + return true + } + return false +} + +func isBlankTypeCapturing(e expreduceapi.Ex, target expreduceapi.Ex, head expreduceapi.Ex, pm *PDManager, cl expreduceapi.LoggingInterface) (bool, *PDManager) { + // Similar to IsBlankType, but will capture target into es.patternDefined + // if there is a valid match. + asPattern, patternOk := atoms.HeadAssertion(e, "System`Pattern") + if patternOk { + asBlank, blankOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`Blank") + asBS, bsOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`BlankSequence") + asBNS, bnsOk := atoms.HeadAssertion(asPattern.GetParts()[2], "System`BlankNullSequence") + if blankOk || bsOk || bnsOk { + parts := []expreduceapi.Ex{} + if blankOk { + parts = asBlank.GetParts() + } else if bsOk { + parts = asBS.GetParts() + } else if bnsOk { + parts = asBNS.GetParts() + } + //if len(parts) < 2 { + //return true, pm + //} + cl.Debugf("%v %v", parts, len(parts)) + var matchesHead bool + if len(parts) < 2 { + matchesHead = true + } else { + matchesHead = atoms.IsSameQ(head, parts[1]) + } + cl.Debugf("%v", matchesHead) + if matchesHead { + sAsSymbol, sAsSymbolOk := asPattern.GetParts()[1].(*atoms.Symbol) + if sAsSymbolOk { + // TODO: we should handle matches with BlankSequences + // differently here. + toMatch, ispd := pm.patternDefined[sAsSymbol.Name] + if !ispd { + toMatch = target + pm.lazyMakeMap() + pm.patternDefined[sAsSymbol.Name] = target + } + if !atoms.IsSameQ(toMatch, target) { + return false, pm + } + } + return true, pm + } + return false, pm + } + } + asBlank, blankOk := atoms.HeadAssertion(e, "System`Blank") + asBS, bsOk := atoms.HeadAssertion(e, "System`BlankSequence") + asBNS, bnsOk := atoms.HeadAssertion(e, "System`BlankNullSequence") + if blankOk || bsOk || bnsOk { + parts := []expreduceapi.Ex{} + if blankOk { + parts = asBlank.GetParts() + } else if bsOk { + parts = asBS.GetParts() + } else if bnsOk { + parts = asBNS.GetParts() + } + if len(parts) < 2 { + return true, pm + } + return atoms.IsSameQ(head, parts[1]), pm + } + return false, pm +} + +func blankNullSequenceToBlank(bns expreduceapi.ExpressionInterface) expreduceapi.ExpressionInterface { + if len(bns.GetParts()) < 2 { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Blank")}) + } + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Blank"), bns.GetParts()[1]}) +} + +func blankSequenceToBlank(bs expreduceapi.ExpressionInterface) expreduceapi.ExpressionInterface { + if len(bs.GetParts()) < 2 { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Blank")}) + } + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Blank"), bs.GetParts()[1]}) +} diff --git a/expreduce/matchq.go b/expreduce/matcher/matchq.go similarity index 51% rename from expreduce/matchq.go rename to expreduce/matcher/matchq.go index 1631d35..f1bcee9 100644 --- a/expreduce/matchq.go +++ b/expreduce/matcher/matchq.go @@ -1,61 +1,66 @@ -package expreduce +package matcher -import "flag" +import ( + "flag" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) var freezeStateDuringPreMatch = flag.Bool( "freezeStateDuringPreMatch", false, - "Freeze the EvalState when doing a prematch pattern build. It is very " + - "rare that this has any effect. We turn this feature off for better " + - "thread safety.", + "Freeze the EvalState when doing a prematch pattern build. It is very "+ + "rare that this has any effect. We turn this feature off for better "+ + "thread safety.", ) -const MaxUint = ^uint(0) -const MaxInt = int(MaxUint >> 1) -const MaxUint64 = ^uint64(0) -const MaxInt64 = int64(MaxUint64 >> 1) +const maxUint = ^uint(0) +const maxInt = int(maxUint >> 1) +const maxUint64 = ^uint64(0) +const maxInt64 = int64(maxUint64 >> 1) -type matchIter interface { +type MatchIter interface { // returns ismatch, pd, isdone - next() (bool, *PDManager, bool) + Next() (bool, *PDManager, bool) } type dummyMatchIter struct { pm *PDManager } -func (this *dummyMatchIter) next() (bool, *PDManager, bool) { - return true, this.pm, true +func (dmi *dummyMatchIter) Next() (bool, *PDManager, bool) { + return true, dmi.pm, true } -var realSym = NewSymbol("System`Real") -var intSym = NewSymbol("System`Integer") -var strSym = NewSymbol("System`String") -var symSym = NewSymbol("System`Symbol") -var ratSym = NewSymbol("System`Rational") -var complexSym = NewSymbol("System`Complex") +var realSym = atoms.NewSymbol("System`Real") +var intSym = atoms.NewSymbol("System`Integer") +var strSym = atoms.NewSymbol("System`String") +var symSym = atoms.NewSymbol("System`Symbol") +var ratSym = atoms.NewSymbol("System`Rational") +var complexSym = atoms.NewSymbol("System`Complex") -func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { +func NewMatchIter(a expreduceapi.Ex, b expreduceapi.Ex, pm *PDManager, es expreduceapi.EvalStateInterface) (MatchIter, bool) { patternHead := "" - patExpr, patIsExpr := b.(*Expression) + patExpr, patIsExpr := b.(expreduceapi.ExpressionInterface) if patIsExpr { - sym, isSym := patExpr.Parts[0].(*Symbol) + sym, isSym := patExpr.GetParts()[0].(*atoms.Symbol) if isSym { patternHead = sym.Name } } if patternHead == "System`Except" { except := patExpr - if len(except.Parts) == 2 { - matchq, _ := IsMatchQ(a, except.Parts[1], pm, es) + if len(except.GetParts()) == 2 { + matchq, _ := IsMatchQ(a, except.GetParts()[1], pm, es) if !matchq { return &dummyMatchIter{pm}, true } return nil, false - } else if len(except.Parts) == 3 { - matchq, _ := IsMatchQ(a, except.Parts[1], pm, es) + } else if len(except.GetParts()) == 3 { + matchq, _ := IsMatchQ(a, except.GetParts()[1], pm, es) if !matchq { - matchqb, newPm := IsMatchQ(a, except.Parts[2], pm, es) + matchqb, newPm := IsMatchQ(a, except.GetParts()[2], pm, es) if matchqb { return &dummyMatchIter{newPm}, true } @@ -64,7 +69,7 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { } } else if patternHead == "System`Alternatives" { alts := patExpr - for _, alt := range alts.Parts[1:] { + for _, alt := range alts.GetParts()[1:] { // I recently changed the third argument from EmptyPD() to pm // because MatchQ[{a, b}, {a_, k | a_}] was returning True, causing // problems in some of the boolean patterns. Might need to make @@ -77,35 +82,37 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { return nil, false } else if patternHead == "System`PatternTest" { patternTest := patExpr - if len(patternTest.Parts) == 3 { - matchq, newPD := IsMatchQ(a, patternTest.Parts[1], pm, es) + if len(patternTest.GetParts()) == 3 { + matchq, newPD := IsMatchQ(a, patternTest.GetParts()[1], pm, es) if matchq { // Some Q functions are very simple and occur very often. For // some of these, skip the Eval() call and return the boolean // directly. - testSym, testIsSym := patternTest.Parts[2].(*Symbol) + testSym, testIsSym := patternTest.GetParts()[2].(*atoms.Symbol) if testIsSym { - var qFunction singleParamQType + var qFunction (func(expreduceapi.Ex) bool) if testSym.Name == "System`NumberQ" { - qFunction = numberQ + qFunction = atoms.NumberQ } if qFunction != nil { if qFunction(a) { return &dummyMatchIter{newPD}, true - } else { - return nil, false } + return nil, false } } // I used to create a NewEvalState here, but I have evidence // that the same evalstate is used: // MatchQ[1, a_?((mytestval = 999; NumberQ[#]) &)] // Timing //tmpEs := NewEvalStateNoLog(true) - res := (NewExpression([]Ex{ - patternTest.Parts[2], - a, - })).Eval(es) - resSymbol, resIsSymbol := res.(*Symbol) + res := + + es.Eval((atoms.NewExpression([]expreduceapi.Ex{ + patternTest.GetParts()[2], + a, + }))) + + resSymbol, resIsSymbol := res.(*atoms.Symbol) if resIsSymbol { if resSymbol.Name == "System`True" { return &dummyMatchIter{newPD}, true @@ -116,16 +123,16 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { } } else if patternHead == "System`Condition" { condition := patExpr - if len(condition.Parts) == 3 { - mi, cont := NewMatchIter(a, condition.Parts[1], pm, es) + if len(condition.GetParts()) == 3 { + mi, cont := NewMatchIter(a, condition.GetParts()[1], pm, es) for cont { - matchq, newPD, done := mi.next() + matchq, newPD, done := mi.Next() cont = !done if matchq { //tmpEs := NewEvalStateNoLog(true) - res := condition.Parts[2].DeepCopy() - res = ReplacePD(res, es, newPD).Eval(es) - resSymbol, resIsSymbol := res.(*Symbol) + res := condition.GetParts()[2].DeepCopy() + res = es.Eval(ReplacePD(res, es, newPD)) + resSymbol, resIsSymbol := res.(*atoms.Symbol) if resIsSymbol { if resSymbol.Name == "System`True" { return &dummyMatchIter{newPD}, true @@ -136,44 +143,44 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { } } else if patternHead == "System`Optional" { optional := patExpr - if len(optional.Parts) == 2 { - matchq, newPD := IsMatchQ(a, optional.Parts[1], pm, es) + if len(optional.GetParts()) == 2 { + matchq, newPD := IsMatchQ(a, optional.GetParts()[1], pm, es) if matchq { return &dummyMatchIter{newPD}, true } } } else if patternHead == "System`HoldPattern" { holdPattern := patExpr - if len(holdPattern.Parts) == 2 { - return NewMatchIter(a, holdPattern.Parts[1], pm, es) + if len(holdPattern.GetParts()) == 2 { + return NewMatchIter(a, holdPattern.GetParts()[1], pm, es) } } // Continue normally - _, aIsFlt := a.(*Flt) - _, aIsInteger := a.(*Integer) - _, aIsString := a.(*String) - _, aIsSymbol := a.(*Symbol) - aRational, aIsRational := a.(*Rational) - aComplex, aIsComplex := a.(*Complex) - aExpression, aIsExpression := a.(*Expression) - bExpression, bIsExpression := b.(*Expression) + _, aIsFlt := a.(*atoms.Flt) + _, aIsInteger := a.(*atoms.Integer) + _, aIsString := a.(*atoms.String) + _, aIsSymbol := a.(*atoms.Symbol) + aRational, aIsRational := a.(*atoms.Rational) + aComplex, aIsComplex := a.(*atoms.Complex) + aExpression, aIsExpression := a.(expreduceapi.ExpressionInterface) + bExpression, bIsExpression := b.(expreduceapi.ExpressionInterface) // Special case for the operator form of Verbatim forceOrdered := false - verbatimOp, opExpr, isVerbatimOp := OperatorAssertion(b, "System`Verbatim") + verbatimOp, opExpr, isVerbatimOp := atoms.OperatorAssertion(b, "System`Verbatim") if aIsExpression && isVerbatimOp { - if len(opExpr.Parts) == 2 { - if IsSameQ(aExpression.Parts[0], opExpr.Parts[1], &es.CASLogger) { - b = NewExpression(append([]Ex{opExpr.Parts[1]}, verbatimOp.Parts[1:]...)) - bExpression, bIsExpression = b.(*Expression) + if len(opExpr.GetParts()) == 2 { + if atoms.IsSameQ(aExpression.GetParts()[0], opExpr.GetParts()[1]) { + b = atoms.NewExpression(append([]expreduceapi.Ex{opExpr.GetParts()[1]}, verbatimOp.GetParts()[1:]...)) + bExpression, bIsExpression = b.(expreduceapi.ExpressionInterface) forceOrdered = true } } } // This initial value is just a randomly chosen placeholder - var headEx Ex + var headEx expreduceapi.Ex if aIsFlt { headEx = realSym } else if aIsInteger { @@ -181,7 +188,7 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { } else if aIsString { headEx = strSym } else if aIsExpression { - headEx = aExpression.Parts[0] + headEx = aExpression.GetParts()[0] } else if aIsSymbol { headEx = symSym } else if aIsRational { @@ -190,8 +197,8 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { headEx = complexSym } - if IsBlankTypeOnly(b) { - ibtc, ibtcNewPDs := IsBlankTypeCapturing(b, a, headEx, pm, &es.CASLogger) + if isBlankTypeOnly(b) { + ibtc, ibtcNewPDs := isBlankTypeCapturing(b, a, headEx, pm, es.GetLogger()) if ibtc { return &dummyMatchIter{ibtcNewPDs}, true } @@ -219,13 +226,13 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { canAssumeHead := false assumingHead := false if bIsExpression { - bExpressionSym, bExpressionSymOk := bExpression.Parts[0].(*Symbol) + bExpressionSym, bExpressionSymOk := bExpression.GetParts()[0].(*atoms.Symbol) if bExpressionSymOk { - oneIdentity := bExpressionSym.Attrs(&es.defined).OneIdentity - hasDefaultExpr := bExpressionSym.Default(&es.defined) != nil + oneIdentity := bExpressionSym.Attrs(es.GetDefinedMap()).OneIdentity + hasDefaultExpr := bExpressionSym.Default(es.GetDefinedMap()) != nil containsOptional := false - for _, part := range bExpression.Parts[1:] { - if _, isOpt := HeadAssertion(part, "System`Optional"); isOpt { + for _, part := range bExpression.GetParts()[1:] { + if _, isOpt := atoms.HeadAssertion(part, "System`Optional"); isOpt { containsOptional = true break } @@ -242,15 +249,15 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { // sequence match. assumingHead = true aIsExpression = true - aExpression = NewExpression([]Ex{bExpressionSym, a}) + aExpression = atoms.NewExpression([]expreduceapi.Ex{bExpressionSym, a}) } if aIsExpression { - aExpressionSym, aExpressionSymOk := aExpression.Parts[0].(*Symbol) + aExpressionSym, aExpressionSymOk := aExpression.GetParts()[0].(*atoms.Symbol) if canAssumeHead && aExpressionSymOk { if aExpressionSym.Name != bExpressionSym.Name { assumingHead = true aIsExpression = true - aExpression = NewExpression([]Ex{bExpressionSym, a}) + aExpression = atoms.NewExpression([]expreduceapi.Ex{bExpressionSym, a}) } } } @@ -258,7 +265,7 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { if !assumingHead { if aIsFlt || aIsInteger || aIsString || aIsSymbol || aIsRational || aIsComplex { - if IsSameQ(a, b, &es.CASLogger) { + if atoms.IsSameQ(a, b) { return &dummyMatchIter{nil}, true } return nil, false @@ -267,14 +274,14 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { } } - attrs := Attributes{} + attrs := expreduceapi.Attributes{} sequenceHead := "Sequence" startI := 0 - aExpressionSym, aExpressionSymOk := aExpression.Parts[0].(*Symbol) - bExpressionSym, bExpressionSymOk := bExpression.Parts[0].(*Symbol) + aExpressionSym, aExpressionSymOk := aExpression.GetParts()[0].(*atoms.Symbol) + bExpressionSym, bExpressionSymOk := bExpression.GetParts()[0].(*atoms.Symbol) if aExpressionSymOk && bExpressionSymOk { if aExpressionSym.Name == bExpressionSym.Name { - attrs = aExpressionSym.Attrs(&es.defined) + attrs = aExpressionSym.Attrs(es.GetDefinedMap()) sequenceHead = aExpressionSym.Name startI = 1 } @@ -282,28 +289,28 @@ func NewMatchIter(a Ex, b Ex, pm *PDManager, es *EvalState) (matchIter, bool) { isOrderless := attrs.Orderless && !forceOrdered isFlat := attrs.Flat && !forceOrdered - nomi, ok := NewSequenceMatchIter(aExpression.Parts[startI:], bExpression.Parts[startI:], isOrderless, isFlat, sequenceHead, pm, es) + nomi, ok := newSequenceMatchIter(aExpression.GetParts()[startI:], bExpression.GetParts()[startI:], isOrderless, isFlat, sequenceHead, pm, es) if !ok { return nil, false } return nomi, true } -func isMatchQRational(a *Rational, b *Expression, pm *PDManager, es *EvalState) (bool, *PDManager) { +func isMatchQRational(a *atoms.Rational, b expreduceapi.ExpressionInterface, pm *PDManager, es expreduceapi.EvalStateInterface) (bool, *PDManager) { return IsMatchQ( - NewExpression([]Ex{ - NewSymbol("System`Rational"), - NewInteger(a.Num), - NewInteger(a.Den), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rational"), + atoms.NewInteger(a.Num), + atoms.NewInteger(a.Den), }), b, pm, es) } -func isMatchQComplex(a *Complex, b *Expression, pm *PDManager, es *EvalState) (bool, *PDManager) { +func isMatchQComplex(a *atoms.Complex, b expreduceapi.ExpressionInterface, pm *PDManager, es expreduceapi.EvalStateInterface) (bool, *PDManager) { return IsMatchQ( - NewExpression([]Ex{ - NewSymbol("System`Complex"), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Complex"), a.Re, a.Im, }), @@ -321,24 +328,24 @@ type assignedMatchIter struct { assn [][]int // Inherited from sequenceMatchIter - components []Ex - lhs_components []parsedForm - pm *PDManager - sequenceHead string - es *EvalState - stack []assignedIterState + components []expreduceapi.Ex + lhsComponents []parsedForm + pm *PDManager + sequenceHead string + es expreduceapi.EvalStateInterface + stack []assignedIterState } -func NewAssignedMatchIter(assn [][]int, smi *sequenceMatchIter) assignedMatchIter { +func newAssignedMatchIter(assn [][]int, smi *sequenceMatchIter) assignedMatchIter { ami := assignedMatchIter{} ami.assn = assn ami.components = smi.components - ami.lhs_components = smi.lhs_components + ami.lhsComponents = smi.lhsComponents ami.pm = smi.pm ami.sequenceHead = smi.sequenceHead ami.es = smi.es ami.stack = []assignedIterState{ - {0, 0, CopyPD(ami.pm)}, + {0, 0, copyPD(ami.pm)}, } return ami } @@ -354,15 +361,15 @@ func (ami *assignedMatchIter) next() bool { ami.pm = p.pm return true } - lhs := ami.lhs_components[p.formI] + lhs := ami.lhsComponents[p.formI] if p.assnI >= len(ami.assn[p.formI]) { // Reached end of form. Attempt to define the sequence and continue // on success. - seq := make([]Ex, len(ami.assn[p.formI])) + seq := make([]expreduceapi.Ex, len(ami.assn[p.formI])) for i, assignedComp := range ami.assn[p.formI] { seq[i] = ami.components[assignedComp] } - patOk := DefineSequence(lhs, seq, p.pm, ami.sequenceHead, ami.es) + patOk := defineSequence(lhs, seq, p.pm, ami.sequenceHead, ami.es) if patOk { ami.stack = append(ami.stack, assignedIterState{ p.formI + 1, 0, p.pm, @@ -377,7 +384,7 @@ func (ami *assignedMatchIter) next() bool { toAddReversed := []*PDManager{} mi, cont := NewMatchIter(comp, lhs.form, p.pm, ami.es) for cont { - matchq, submatches, done := mi.next() + matchq, submatches, done := mi.Next() cont = !done if matchq { // TODO: Perhaps check if submatches are different before @@ -387,11 +394,11 @@ func (ami *assignedMatchIter) next() bool { } for i := len(toAddReversed) - 1; i >= 0; i-- { updatedPm := p.pm - if toAddReversed[i] != nil && toAddReversed[i].Len() > 0 { + if toAddReversed[i] != nil && toAddReversed[i].len() > 0 { if len(toAddReversed) > 1 { - updatedPm = CopyPD(p.pm) + updatedPm = copyPD(p.pm) } - updatedPm.Update(toAddReversed[i]) + updatedPm.update(toAddReversed[i]) } ami.stack = append(ami.stack, assignedIterState{ p.formI, p.assnI + 1, updatedPm, @@ -402,29 +409,29 @@ func (ami *assignedMatchIter) next() bool { } type sequenceMatchIter struct { - components []Ex - lhs_components []parsedForm - pm *PDManager - sequenceHead string - es *EvalState - ai assnIter - iteratingAmi bool - ami assignedMatchIter + components []expreduceapi.Ex + lhsComponents []parsedForm + pm *PDManager + sequenceHead string + es expreduceapi.EvalStateInterface + ai assnIter + iteratingAmi bool + ami assignedMatchIter } -func NewSequenceMatchIter(components []Ex, lhs_components []Ex, isOrderless bool, isFlat bool, sequenceHead string, pm *PDManager, es *EvalState) (matchIter, bool) { - headDefault := (NewSymbol(sequenceHead)).Default(&es.defined) - fp_components := make([]parsedForm, len(lhs_components)) - for i, comp := range lhs_components { - fp_components[i] = ParseForm(comp, isFlat, sequenceHead, headDefault, &es.CASLogger) +func newSequenceMatchIter(components []expreduceapi.Ex, lhsComponents []expreduceapi.Ex, isOrderless bool, isFlat bool, sequenceHead string, pm *PDManager, es expreduceapi.EvalStateInterface) (MatchIter, bool) { + headDefault := (atoms.NewSymbol(sequenceHead)).Default(es.GetDefinedMap()) + fpComponents := make([]parsedForm, len(lhsComponents)) + for i, comp := range lhsComponents { + fpComponents[i] = parseForm(comp, isFlat, sequenceHead, headDefault, es.GetLogger()) } - return NewSequenceMatchIterPreparsed(components, fp_components, isOrderless, sequenceHead, pm, es) + return newSequenceMatchIterPreparsed(components, fpComponents, isOrderless, sequenceHead, pm, es) } -func NewSequenceMatchIterPreparsed(components []Ex, lhs_components []parsedForm, isOrderless bool, sequenceHead string, pm *PDManager, es *EvalState) (matchIter, bool) { +func newSequenceMatchIterPreparsed(components []expreduceapi.Ex, lhsComponents []parsedForm, isOrderless bool, sequenceHead string, pm *PDManager, es expreduceapi.EvalStateInterface) (MatchIter, bool) { nomi := &sequenceMatchIter{} nomi.components = components - nomi.lhs_components = lhs_components + nomi.lhsComponents = lhsComponents nomi.pm = pm nomi.sequenceHead = sequenceHead nomi.es = es @@ -433,20 +440,20 @@ func NewSequenceMatchIterPreparsed(components []Ex, lhs_components []parsedForm, if *freezeStateDuringPreMatch { es.SetFrozen(true) } - formMatches := make([][]bool, len(lhs_components)) - for i, mustContain := range lhs_components { + formMatches := make([][]bool, len(lhsComponents)) + for i, mustContain := range lhsComponents { // Right now I have this strange definition of "form". It's basically where I convert blank sequences to blanks at the bottom level. What if I did this at all levels and perhaps did something with patterns? // TODO: prevent the checks here from modifying state so I can use the "rm" function. formMatches[i] = make([]bool, len(components)) - num_matches := 0 + numMatches := 0 for j, part := range components { matchq, _ := IsMatchQ(part, mustContain.form, EmptyPD(), es) if matchq { - num_matches++ + numMatches++ } formMatches[i][j] = matchq } - if num_matches < mustContain.startI { + if numMatches < mustContain.startI { if *freezeStateDuringPreMatch { es.SetFrozen(origFrozen) } @@ -457,36 +464,31 @@ func NewSequenceMatchIterPreparsed(components []Ex, lhs_components []parsedForm, es.SetFrozen(origFrozen) } - nomi.ai = NewAssnIter(len(components), lhs_components, formMatches, isOrderless) + nomi.ai = newAssnIter(len(components), lhsComponents, formMatches, isOrderless) return nomi, true } -func (this *sequenceMatchIter) next() (bool, *PDManager, bool) { +func (smi *sequenceMatchIter) Next() (bool, *PDManager, bool) { for { - if this.iteratingAmi && this.ami.next() { - return true, this.ami.pm, false + if smi.iteratingAmi && smi.ami.next() { + return true, smi.ami.pm, false } - this.iteratingAmi = false - if !this.ai.next() { + smi.iteratingAmi = false + if !smi.ai.next() { break } - this.ami = NewAssignedMatchIter(this.ai.assns, this) - this.iteratingAmi = true + smi.ami = newAssignedMatchIter(smi.ai.assns, smi) + smi.iteratingAmi = true } - return false, this.pm, true + return false, smi.pm, true } // HELPER FUNCTIONS -func ComponentsIsMatchQ(components []Ex, lhs_components []Ex, isOrderless bool, isFlat bool, sequenceHead string, pm *PDManager, es *EvalState) (bool, *PDManager) { - omi, cont := NewSequenceMatchIter(components, lhs_components, isOrderless, isFlat, sequenceHead, pm, es) - return GetMatchQ(omi, cont, pm) -} - -func GetMatchQ(mi matchIter, cont bool, pm *PDManager) (bool, *PDManager) { +func getMatchQ(mi MatchIter, cont bool, pm *PDManager) (bool, *PDManager) { for cont { - matchq, newPd, done := mi.next() + matchq, newPd, done := mi.Next() cont = !done // TODO: I could probably update my matchiters to only return if they // have a match or are done. @@ -497,8 +499,10 @@ func GetMatchQ(mi matchIter, cont bool, pm *PDManager) (bool, *PDManager) { return false, pm } -// TODO: do not export this -func IsMatchQ(a Ex, b Ex, pm *PDManager, es *EvalState) (bool, *PDManager) { +// IsMatchQ returns if an Ex `a` matches a pattern Ex `b`. If the expression +// matches the pattern and if the pattern has any named patterns, those matching +// values will be added to `pm`. +func IsMatchQ(a expreduceapi.Ex, b expreduceapi.Ex, pm *PDManager, es expreduceapi.EvalStateInterface) (bool, *PDManager) { mi, cont := NewMatchIter(a, b, pm, es) - return GetMatchQ(mi, cont, pm) + return getMatchQ(mi, cont, pm) } diff --git a/expreduce/matcher/parse_form.go b/expreduce/matcher/parse_form.go new file mode 100644 index 0000000..2a0a28f --- /dev/null +++ b/expreduce/matcher/parse_form.go @@ -0,0 +1,163 @@ +package matcher + +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type parsedForm struct { + startI int + endI int + form expreduceapi.Ex + origForm expreduceapi.Ex + isBlank bool + isImpliedBs bool + isOptional bool + defaultExpr expreduceapi.Ex + hasPat bool + patSym *atoms.Symbol +} + +func parseRepeated(e expreduceapi.ExpressionInterface) (expreduceapi.Ex, int, int, bool) { + min, max := -1, -1 + if len(e.GetParts()) < 2 { + return nil, min, max, false + } + if len(e.GetParts()) >= 3 { + list, isList := atoms.HeadAssertion(e.GetParts()[2], "System`List") + if !isList { + return nil, min, max, false + } + if len(list.GetParts()) != 2 { + return nil, min, max, false + } + i, isInt := list.GetParts()[1].(*atoms.Integer) + if !isInt { + return nil, min, max, false + } + ival := i.Val.Int64() + min = int(ival) + max = min + } + return e.GetParts()[1], min, max, true +} + +func parseForm(lhsComponent expreduceapi.Ex, isFlat bool, sequenceHead string, headDefault expreduceapi.Ex, cl expreduceapi.LoggingInterface) (res parsedForm) { + // Calculate the min and max elements this component can match. + toParse := lhsComponent + optional, isOptional := atoms.HeadAssertion(toParse, "System`Optional") + if isOptional { + toParse = optional.GetParts()[1] + } + patTest, isPatTest := atoms.HeadAssertion(toParse, "System`PatternTest") + if isPatTest { + toParse = patTest.GetParts()[1] + } + pat, isPat := atoms.HeadAssertion(toParse, "System`Pattern") + var patSym *atoms.Symbol + if isPat { + var patIsSym bool + patSym, patIsSym = pat.GetParts()[1].(*atoms.Symbol) + if patIsSym { + toParse = pat.GetParts()[2] + } else { + // Valid patterns must have symbols to define. + isPat = false + } + } + bns, isBns := atoms.HeadAssertion(toParse, "System`BlankNullSequence") + bs, isBs := atoms.HeadAssertion(toParse, "System`BlankSequence") + blank, isBlank := atoms.HeadAssertion(toParse, "System`Blank") + repeated, isRepeated := atoms.HeadAssertion(toParse, "System`Repeated") + repeatedNull, isRepeatedNull := atoms.HeadAssertion(toParse, "System`RepeatedNull") + isImpliedBs := isBlank && isFlat + // Ensure isBlank is exclusive from isImpliedBs + isBlank = isBlank && !isImpliedBs + + form := toParse + startI := 1 // also includes implied blanksequence + endI := 1 + var defaultExpr expreduceapi.Ex + + if isOptional { + defaultToUse := headDefault + if len(optional.GetParts()) >= 3 { + defaultToUse = optional.GetParts()[2] + } + if len(optional.GetParts()) >= 2 { + startI = 0 + if defaultToUse == nil { + startI = 1 + } + endI = 1 + // I think the !isPatTest part might be a hack. + if isImpliedBs && !isPatTest { + endI = maxInt + } + //form = optional.Parts[1] + defaultExpr = defaultToUse + } + } else if isBns { + form = blankNullSequenceToBlank(bns) + startI = 0 + endI = maxInt + } else if isImpliedBs { + form = blank + endI = maxInt + if len(blank.GetParts()) >= 2 { + sym, isSym := blank.GetParts()[1].(*atoms.Symbol) + if isSym { + // If we have a pattern like k__Plus + if sym.Name == sequenceHead { + form = atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Blank")}) + startI = 2 + } else { + endI = 1 + } + } + } + } else if isBlank { + form = blank + } else if isRepeated { + repPat, repMin, repMax, repOk := parseRepeated(repeated) + if repOk { + if repMin != -1 { + startI = repMin + } + if repMax != -1 { + endI = repMax + } else { + // an undefined end can match to the end of the sequence. + endI = maxInt + } + form = repPat + } + } else if isRepeatedNull { + if len(repeatedNull.GetParts()) == 2 { + startI = 0 + endI = maxInt + form = repeatedNull.GetParts()[1] + } + } else if isBs { + form = blankSequenceToBlank(bs) + endI = maxInt + } + + if isPatTest { + form = atoms.NewExpression([]expreduceapi.Ex{patTest.GetParts()[0], form, patTest.GetParts()[2]}) + } + + res.startI = startI + res.endI = endI + res.form = form + res.defaultExpr = defaultExpr + res.origForm = lhsComponent + res.isImpliedBs = isImpliedBs + res.isOptional = isOptional + res.isBlank = isBlank + if isPat { + res.hasPat = true + res.patSym = patSym + } + return res +} diff --git a/expreduce/matcher/pdmanager.go b/expreduce/matcher/pdmanager.go new file mode 100644 index 0000000..802b859 --- /dev/null +++ b/expreduce/matcher/pdmanager.go @@ -0,0 +1,136 @@ +package matcher + +import ( + "bytes" + "sort" + "strings" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type PDManager struct { + patternDefined map[string]expreduceapi.Ex +} + +func EmptyPD() *PDManager { + return &PDManager{nil} +} + +func copyPD(orig *PDManager) (dest *PDManager) { + dest = EmptyPD() + // We do not care that this iterates in a random order. + if (*orig).len() > 0 { + dest.lazyMakeMap() + for k, v := range (*orig).patternDefined { + (*dest).patternDefined[k] = v + } + } + return +} + +func (pm *PDManager) lazyMakeMap() { + if pm.patternDefined == nil { + pm.patternDefined = make(map[string]expreduceapi.Ex) + } +} + +func (pm *PDManager) Define(name string, val expreduceapi.Ex) { + pm.lazyMakeMap() + pm.patternDefined[name] = val +} + +func (pm *PDManager) update(toAdd *PDManager) { + if (*toAdd).len() > 0 { + pm.lazyMakeMap() + } + // We do not care that this iterates in a random order. + for k, v := range (*toAdd).patternDefined { + (*pm).patternDefined[k] = v + } +} + +func (pm *PDManager) len() int { + if pm.patternDefined == nil { + return 0 + } + return len(pm.patternDefined) +} + +func (pm *PDManager) string(es expreduceapi.EvalStateInterface) string { + var buffer bytes.Buffer + buffer.WriteString("{") + // We sort the keys here such that converting identical PDManagers always + // produces the same string. + keys := []string{} + for k := range pm.patternDefined { + keys = append(keys, k) + } + sort.Strings(keys) + context := atoms.NewString("Global`") + contextPath := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), + atoms.NewString("System`"), + }) + for _, k := range keys { + v := pm.patternDefined[k] + buffer.WriteString(k) + buffer.WriteString("_: ") + buffer.WriteString(v.StringForm(expreduceapi.ToStringParams{Form: "InputForm", Context: context, ContextPath: contextPath, Esi: es})) + buffer.WriteString(", ") + } + if strings.HasSuffix(buffer.String(), ", ") { + buffer.Truncate(buffer.Len() - 2) + } + buffer.WriteString("}") + return buffer.String() +} + +func (pm *PDManager) Expression() expreduceapi.Ex { + res := atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`List")}) + // We sort the keys here such that converting identical PDManagers always + // produces the same string. + keys := []string{} + for k := range pm.patternDefined { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := pm.patternDefined[k] + res.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Rule"), + atoms.NewString(k), + v, + })) + } + return res +} + +func defineSequence(lhs parsedForm, sequence []expreduceapi.Ex, pm *PDManager, sequenceHead string, es expreduceapi.EvalStateInterface) bool { + var attemptDefine expreduceapi.Ex + if lhs.hasPat { + sequenceHeadSym := atoms.NewSymbol(sequenceHead) + oneIdent := sequenceHeadSym.Attrs(es.GetDefinedMap()).OneIdentity + if len(sequence) == 1 && (lhs.isBlank || oneIdent || lhs.isOptional) { + attemptDefine = sequence[0] + } else if len(sequence) == 0 && lhs.isOptional && lhs.defaultExpr != nil { + attemptDefine = lhs.defaultExpr + } else if lhs.isImpliedBs { + attemptDefine = atoms.NewExpression(append([]expreduceapi.Ex{sequenceHeadSym}, sequence...)) + } else { + head := atoms.NewSymbol("System`Sequence") + attemptDefine = atoms.NewExpression(append([]expreduceapi.Ex{head}, sequence...)) + } + + if pm.patternDefined != nil { + defined, ispd := pm.patternDefined[lhs.patSym.Name] + if ispd && !atoms.IsSameQ(defined, attemptDefine) { + es.Debugf("patterns do not match! continuing.") + return false + } + } + pm.lazyMakeMap() + pm.patternDefined[lhs.patSym.Name] = attemptDefine + } + return true +} diff --git a/expreduce/matcher/pdreplace.go b/expreduce/matcher/pdreplace.go new file mode 100644 index 0000000..6f79907 --- /dev/null +++ b/expreduce/matcher/pdreplace.go @@ -0,0 +1,56 @@ +package matcher + +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +func replacePDInternal(e expreduceapi.Ex, pm *PDManager) (expreduceapi.Ex, bool) { + asSym, isSym := e.(*atoms.Symbol) + if isSym { + for k, def := range pm.patternDefined { + if k == asSym.Name { + // Shouldn't need the copy + return def, true + } + } + } + thisDirty := false + asExpr, isExpr := e.(expreduceapi.ExpressionInterface) + if isExpr { + for i := range asExpr.GetParts() { + possiblyNewExpr, dirty := replacePDInternal(asExpr.GetParts()[i], pm) + if dirty { + thisDirty = true + // Mark the expression as dirty and needing eval. + asExpr.ClearHashes() + } + asExpr.GetParts()[i] = possiblyNewExpr + } + } + return e, thisDirty +} + +// ReplacePD takes an expression and replaces any defined symbols in the +// PDManager with the defined values. It is a form of subsitution common in +// function evaluation and replacement. +func ReplacePD(expr expreduceapi.Ex, es expreduceapi.EvalStateInterface, pm *PDManager) expreduceapi.Ex { + if pm == nil { + return expr + } + containsAny := false + for k := range pm.patternDefined { + if atoms.ContainsSymbol(expr, k) { + containsAny = true + break + } + } + if !containsAny { + return expr + } + + // Expressions are immutable. Any time we change an expression, we must + // first copy it. + res, _ := replacePDInternal(expr.Copy(), pm) + return res +} diff --git a/expreduce/parse_form.go b/expreduce/parse_form.go deleted file mode 100644 index 62dbb57..0000000 --- a/expreduce/parse_form.go +++ /dev/null @@ -1,158 +0,0 @@ -package expreduce - -type parsedForm struct { - startI int - endI int - form Ex - origForm Ex - isBlank bool - isImpliedBs bool - isOptional bool - defaultExpr Ex - hasPat bool - patSym *Symbol -} - -func ParseRepeated(e *Expression) (Ex, int, int, bool) { - min, max := -1, -1 - if len(e.Parts) < 2 { - return nil, min, max, false - } - if len(e.Parts) >= 3 { - list, isList := HeadAssertion(e.Parts[2], "System`List") - if !isList { - return nil, min, max, false - } - if len(list.Parts) != 2 { - return nil, min, max, false - } - i, isInt := list.Parts[1].(*Integer) - if !isInt { - return nil, min, max, false - } - ival := i.Val.Int64() - min = int(ival) - max = min - } - return e.Parts[1], min, max, true -} - -func ParseForm(lhs_component Ex, isFlat bool, sequenceHead string, headDefault Ex, cl *CASLogger) (res parsedForm) { - // Calculate the min and max elements this component can match. - toParse := lhs_component - optional, isOptional := HeadAssertion(toParse, "System`Optional") - if isOptional { - toParse = optional.Parts[1] - } - patTest, isPatTest := HeadAssertion(toParse, "System`PatternTest") - if isPatTest { - toParse = patTest.Parts[1] - } - pat, isPat := HeadAssertion(toParse, "System`Pattern") - var patSym *Symbol - if isPat { - patIsSym := false - patSym, patIsSym = pat.Parts[1].(*Symbol) - if patIsSym { - toParse = pat.Parts[2] - } else { - // Valid patterns must have symbols to define. - isPat = false - } - } - bns, isBns := HeadAssertion(toParse, "System`BlankNullSequence") - bs, isBs := HeadAssertion(toParse, "System`BlankSequence") - blank, isBlank := HeadAssertion(toParse, "System`Blank") - repeated, isRepeated := HeadAssertion(toParse, "System`Repeated") - repeatedNull, isRepeatedNull := HeadAssertion(toParse, "System`RepeatedNull") - isImpliedBs := isBlank && isFlat - // Ensure isBlank is exclusive from isImpliedBs - isBlank = isBlank && !isImpliedBs - - form := toParse - startI := 1 // also includes implied blanksequence - endI := 1 - var defaultExpr Ex - - if isOptional { - defaultToUse := headDefault - if len(optional.Parts) >= 3 { - defaultToUse = optional.Parts[2] - } - if len(optional.Parts) >= 2 { - startI = 0 - if defaultToUse == nil { - startI = 1 - } - endI = 1 - // I think the !isPatTest part might be a hack. - if isImpliedBs && !isPatTest { - endI = MaxInt - } - //form = optional.Parts[1] - defaultExpr = defaultToUse - } - } else if isBns { - form = BlankNullSequenceToBlank(bns) - startI = 0 - endI = MaxInt - } else if isImpliedBs { - form = blank - endI = MaxInt - if len(blank.Parts) >= 2 { - sym, isSym := blank.Parts[1].(*Symbol) - if isSym { - // If we have a pattern like k__Plus - if sym.Name == sequenceHead { - form = NewExpression([]Ex{NewSymbol("System`Blank")}) - startI = 2 - } else { - endI = 1 - } - } - } - } else if isBlank { - form = blank - } else if isRepeated { - repPat, repMin, repMax, repOk := ParseRepeated(repeated) - if repOk { - if repMin != -1 { - startI = repMin - } - if repMax != -1 { - endI = repMax - } else { - // an undefined end can match to the end of the sequence. - endI = MaxInt - } - form = repPat - } - } else if isRepeatedNull { - if len(repeatedNull.Parts) == 2 { - startI = 0 - endI = MaxInt - form = repeatedNull.Parts[1] - } - } else if isBs { - form = BlankSequenceToBlank(bs) - endI = MaxInt - } - - if isPatTest { - form = NewExpression([]Ex{patTest.Parts[0], form, patTest.Parts[2]}) - } - - res.startI = startI - res.endI = endI - res.form = form - res.defaultExpr = defaultExpr - res.origForm = lhs_component - res.isImpliedBs = isImpliedBs - res.isOptional = isOptional - res.isBlank = isBlank - if isPat { - res.hasPat = true - res.patSym = patSym - } - return res -} diff --git a/expreduce/parser/interp.go b/expreduce/parser/interp.go new file mode 100644 index 0000000..bd3116a --- /dev/null +++ b/expreduce/parser/interp.go @@ -0,0 +1,521 @@ +package parser + +import ( + "bytes" + "fmt" + "go/token" + "log" + "math/big" + "strings" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/cznic/wl" +) + +type evalStateForParser interface { + IsDef(string) bool + MarkSeen(string) + GetStringDef(name string, defaultVal string) string + GetListDef(name string) expreduceapi.ExpressionInterface +} + +var inequalityOps = map[string]bool{ + "System`Equal": true, + "System`Unequal": true, + "System`Less": true, + "System`LessEqual": true, + "System`Greater": true, + "System`GreaterEqual": true, +} + +func convertToInequality(expr expreduceapi.ExpressionInterface) expreduceapi.ExpressionInterface { + res := atoms.E(atoms.S("Inequality")) + for i, e := range expr.GetParts()[1:] { + if i != 0 { + res.AppendEx(expr.GetParts()[0]) + } + res.AppendEx(e) + } + return res +} + +func fullyAssoc(op string, lhs expreduceapi.Ex, rhs expreduceapi.Ex) expreduceapi.Ex { + _, opIsIneq := inequalityOps[op] + if opIsIneq { + lhsEx, lhsIsEx := lhs.(expreduceapi.ExpressionInterface) + if lhsIsEx { + lhsHead := lhsEx.HeadStr() + _, lhsIsIneq := inequalityOps[lhsHead] + lhsIsIneq = lhsIsIneq || lhsHead == "System`Inequality" + if lhsIsIneq && op != lhsHead { + res := lhsEx + if lhsHead != "System`Inequality" { + res = convertToInequality(lhsEx) + } + res.AppendEx(atoms.NewSymbol(op)) + res.AppendEx(rhs) + return res + } + } + } + opExpr, isOp := atoms.HeadAssertion(lhs, op) + if isOp { + opExpr.AppendEx(rhs) + return opExpr + } + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol(op), lhs, rhs}) +} + +func removeParens(ex expreduceapi.Ex) { + expr, isExpr := ex.(expreduceapi.ExpressionInterface) + if isExpr { + for i := range expr.GetParts() { + parens, isParens := atoms.NewEmptyExpression(), true + for isParens { + parens, isParens = atoms.HeadAssertion(expr.GetParts()[i], "Internal`Parens") + if isParens { + expr.GetParts()[i] = parens.GetParts()[1] + } + } + removeParens(expr.GetParts()[i]) + } + } + return +} + +func addContextAndDefine(e expreduceapi.Ex, context string, contextPath []string, esfp evalStateForParser) { + if sym, isSym := e.(*atoms.Symbol); isSym { + if !strings.Contains(sym.Name, "`") { + for _, toTry := range contextPath { + if esfp.IsDef(toTry + sym.Name) { + sym.Name = toTry + sym.Name + return + } + } + sym.Name = context + sym.Name + } + esfp.MarkSeen(sym.Name) + } + expr, isExpr := e.(expreduceapi.ExpressionInterface) + if isExpr { + for _, part := range expr.GetParts() { + addContextAndDefine(part, context, contextPath, esfp) + } + } +} + +func parsePattern(buf string) expreduceapi.Ex { + delim := "_" + blankType := atoms.NewSymbol("System`Blank") + if strings.Contains(buf, "___") { + delim = "___" + blankType = atoms.NewSymbol("System`BlankNullSequence") + } else if strings.Contains(buf, "__") { + delim = "__" + blankType = atoms.NewSymbol("System`BlankSequence") + } + parts := strings.Split(buf, delim) + if len(parts) == 1 { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Pattern"), atoms.NewSymbol(parts[0]), atoms.NewExpression([]expreduceapi.Ex{blankType})}) + } + if len(parts) == 2 { + if parts[0] == "" { + if parts[1] == "" { + return atoms.NewExpression([]expreduceapi.Ex{blankType}) + } else if delim == "_" && parts[1] == "." { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Optional"), atoms.NewExpression([]expreduceapi.Ex{blankType})}) + } + return atoms.NewExpression([]expreduceapi.Ex{blankType, atoms.NewSymbol(parts[1])}) + } + if parts[1] == "" { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Pattern"), atoms.NewSymbol(parts[0]), atoms.NewExpression([]expreduceapi.Ex{blankType})}) + } else if delim == "_" && parts[1] == "." { + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Optional"), atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Pattern"), atoms.NewSymbol(parts[0]), atoms.NewExpression([]expreduceapi.Ex{blankType})})}) + } + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Pattern"), atoms.NewSymbol(parts[0]), atoms.NewExpression([]expreduceapi.Ex{blankType, atoms.NewSymbol(parts[1])})}) + } + return atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Error"), atoms.NewString("Pattern parse error.")}) +} + +var unicodeRedefineMap = map[string]string{ + "Ï€": "Pi", + "â…ˆ": "I", + "â…‰": "I", +} + +func parserTokenConv(tk wl.Token) expreduceapi.Ex { + switch tk.Rune { + case wl.IDENT: + redefined, isRedefined := unicodeRedefineMap[tk.Val] + if isRedefined { + return atoms.NewSymbol(redefined) + } + return atoms.NewSymbol(tk.Val) + case wl.INT: + base := 10 + tmpi := big.NewInt(0) + _, ok := tmpi.SetString(tk.Val, base) + if !ok { + log.Fatal("Failed in integer parsing.") + } + return atoms.NewInteger(tmpi) + case wl.FLOAT: + tmpf := big.NewFloat(0) + _, ok := tmpf.SetString(tk.Val) + if !ok { + log.Fatal("Failed in float parsing.") + } + return atoms.NewReal(tmpf) + case wl.STRING: + return atoms.NewString(tk.Val) + case wl.PATTERN: + return parsePattern(tk.Val) + case wl.SLOT: + tmpi := big.NewInt(1) + if tk.Val != "#" { + _, ok := tmpi.SetString(tk.Val[1:], 10) + if !ok { + log.Fatal("Failed in integer parsing.") + } + } + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Slot"), + atoms.NewInteger(tmpi), + }) + + default: + log.Fatalf("System`UnParsedToken") + } + log.Fatalf("System`UnParsedToken") + return nil +} + +func parserTagConv(tag *wl.Tag) expreduceapi.Ex { + return parserTokenConv(tag.Token) +} + +func parserExprListConv(l *wl.ExprList) (res []expreduceapi.Ex) { + for l != nil { + if l.Expression != nil { + res = append(res, parserExprConv(l.Expression)) + } else { + res = append(res, parserTokenConv(l.Token)) + } + l = l.ExprList + } + return +} + +// TODO: the following maps are tightly coupled to the parser generation in +// cznic/wl. Small modifications to wl might change all these values. Fix this +// situation. + +var terminals = map[wl.ExpressionCase]bool{ + wl.ExpressionFloat: true, // FLOAT + wl.ExpressionIdent: true, // IDENT + wl.ExpressionInteger: true, // INT + wl.ExpressionPattern: true, // PATTERN + wl.ExpressionSlot: true, // SLOT + wl.ExpressionString: true, // STRING +} + +var unaryOps = map[wl.ExpressionCase]string{ + 13: "Not", + 115: "Factorial", + 117: "Function", + 15: "Plus", + 23: "Increment", + 25: "Decrement", + 0: "PreIncrement", + 1: "PreDecrement", +} + +var binaryOps = map[wl.ExpressionCase]string{ + wl.ExpressionAssign: "Set", + 39: "SetDelayed", + 33: "ReplaceRepeated", + 31: "ReplaceAll", + 27: "Rule", + 40: "RuleDelayed", + 134: "Power", + 130: "PatternTest", + 36: "Condition", + 52: "Apply", + 38: "Map", + 24: "AddTo", + 26: "SubtractFrom", + 78: "Element", +} + +var fullyAssocOps = map[wl.ExpressionCase]string{ + 125: "CompoundExpression", + wl.ExpressionAdd: "Plus", + wl.ExpressionMul: "Times", + wl.ExpressionEq: "Equal", + wl.ExpressionNe: "Unequal", + 47: "SameQ", + 45: "UnsameQ", + 44: "StringJoin", + wl.ExpressionLt: "Less", + wl.ExpressionLe: "LessEqual", + wl.ExpressionGt: "Greater", + 48: "GreaterEqual", + wl.ExpressionLOr: "Or", + wl.ExpressionLAnd: "And", + 121: "Dot", + wl.ExpressionOr: "Alternatives", + 42: "Span", +} + +func parserExprConv(expr *wl.Expression) expreduceapi.Ex { + if _, ok := terminals[expr.Case]; ok { + return parserTokenConv(expr.Token) + } + if head, ok := binaryOps[expr.Case]; ok { + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`" + head), + parserExprConv(expr.Expression), + parserExprConv(expr.Expression2), + }) + + } + if head, ok := fullyAssocOps[expr.Case]; ok { + return fullyAssoc( + "System`"+head, + parserExprConv(expr.Expression), + parserExprConv(expr.Expression2), + ) + } + if head, ok := unaryOps[expr.Case]; ok { + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`" + head), + parserExprConv(expr.Expression), + }) + + } + + // Special handling. + switch expr.Case { + case 124: + return fullyAssoc( + "System`CompoundExpression", + parserExprConv(expr.Expression), + atoms.NewSymbol("System`Null"), + ) + case 123: + // TODO(corywalker): Fix parsing of "a + a_:5 + a". It should contain + // the expression Optional[a_, 5]. + e := parserExprConv(expr.Expression) + head := "System`Pattern" + if _, isPat := atoms.HeadAssertion(e, "System`Pattern"); isPat { + head = "System`Optional" + } + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol(head), + e, + parserExprConv(expr.Expression2), + }) + + case wl.ExpressionMessageName: + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`MessageName"), + parserTokenConv(expr.Token), + atoms.NewString(parserTagConv(expr.Tag).(*atoms.Symbol).Name), + }) + + case 132: // a[] + return atoms.NewExpression([]expreduceapi.Ex{ + parserExprConv(expr.Expression), + }) + + case 133: // a[b] + e := atoms.NewExpression([]expreduceapi.Ex{ + parserExprConv(expr.Expression), + }) + + e.AppendExArray(parserExprListConv(expr.ExprList)) + return e + case 17: // {} + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), + }) + + case 18: // {a} + e := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), + }) + + e.AppendExArray(parserExprListConv(expr.ExprList)) + return e + case 14: // (a) + // Internal`Parens are a placeholder to prevent fullyAssoc from + // translating "(x==2) == (x==2)" to "x == 2 == (x == 2)" + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("Internal`Parens"), + parserExprConv(expr.Expression), + }) + + case 54: // a[[b]] + e := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Part"), + parserExprConv(expr.Expression), + }) + + e.AppendExArray(parserExprListConv(expr.ExprList)) + return e + case 16: + e := parserExprConv(expr.Expression) + if integer, isInteger := e.(*atoms.Integer); isInteger { + return atoms.NewInteger(integer.Val.Neg(integer.Val)) + } else if flt, isFlt := e.(*atoms.Flt); isFlt { + return atoms.NewReal(flt.Val.Neg(flt.Val)) + } + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + e, + atoms.NewInteger(big.NewInt(-1)), + }) + + case 122: + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + parserExprConv(expr.Expression), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Power"), + parserExprConv(expr.Expression2), + atoms.NewInteger(big.NewInt(-1)), + }), + }) + + case 120: + return fullyAssoc( + "System`Plus", + parserExprConv(expr.Expression), + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Times"), + parserExprConv(expr.Expression2), + atoms.NewInteger(big.NewInt(-1)), + }), + ) + case 32: + return atoms.NewExpression([]expreduceapi.Ex{ + parserExprConv(expr.Expression2), + parserExprConv(expr.Expression), + }) + + case 131: + return atoms.NewExpression([]expreduceapi.Ex{ + parserExprConv(expr.Expression), + parserExprConv(expr.Expression2), + }) + + case 53: + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Apply"), + parserExprConv(expr.Expression), + parserExprConv(expr.Expression2), + atoms.E(atoms.S("List"), atoms.NewInt(1)), + }) + + case 35: + set := parserExprConv(expr.Expression2).(expreduceapi.ExpressionInterface) + head := "System`TagSet" + if _, isDelayed := atoms.HeadAssertion(set, "System`SetDelayed"); isDelayed { + head = "System`TagSetDelayed" + } + e := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol(head), + parserExprConv(expr.Expression), + set.GetParts()[1], + set.GetParts()[2], + }) + + return e + case 137: + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Derivative"), + atoms.NewInt(1), + }), + + parserExprConv(expr.Expression), + }) + + case 11: + return atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Sqrt"), + parserExprConv(expr.Expression), + }) + + case wl.ExpressionInfo: + return atoms.E( + atoms.S("Information"), + parserTagConv(expr.Tag), + ) + case wl.ExpressionInfoShort: + return atoms.E( + atoms.S("Information"), + parserTagConv(expr.Tag), + atoms.E(atoms.S("Rule"), atoms.S("LongForm"), atoms.S("False")), + ) + case 145: + if expr.Token.Val == "%" { + return atoms.E( + atoms.S("Out"), + atoms.E(atoms.S("Plus"), atoms.S("$Line"), atoms.NewInt(-1)), + ) + } else if expr.Token.Val == "%%" { + return atoms.E( + atoms.S("Out"), + atoms.E(atoms.S("Plus"), atoms.S("$Line"), atoms.NewInt(-2)), + ) + } + } + log.Fatalf("System`UnParsed: %+v %+v %+v", expr.Token, expr.Case, expr) + return nil +} + +func InterpBuf(buf *bytes.Buffer, fn string, esfp evalStateForParser) (expreduceapi.Ex, error) { + // TODO(corywalker): use the interactive mode for proper newline handling. + in, err := wl.NewInput(buf, true) + if err != nil { + panic(err) + } + expr, err := in.ParseExpression(token.NewFileSet().AddFile(fn, -1, 1e6)) + if err != nil { + return atoms.NewSymbol("System`Null"), err + } + parsed := parserExprConv(expr) + //fmt.Println(parsed) + + // Remove outer parens + parens, isParens := atoms.NewEmptyExpression(), true + for isParens { + parens, isParens = atoms.HeadAssertion(parsed, "Internal`Parens") + if isParens { + parsed = parens.GetParts()[1] + } + } + // Remove inner parens + removeParens(parsed) + + context := esfp.GetStringDef("System`$Context", "") + contextPathEx := esfp.GetListDef("System`$ContextPath") + contextPath := []string{} + for _, pathPart := range contextPathEx.GetParts()[1:] { + contextPath = append(contextPath, pathPart.(*atoms.String).Val) + } + addContextAndDefine(parsed, context, contextPath, esfp) + return parsed, nil +} + +func Interp(src string, esfp evalStateForParser) expreduceapi.Ex { + buf := bytes.NewBufferString(src) + expr, err := InterpBuf(buf, "nofile", esfp) + if err != nil { + fmt.Printf("Syntax::sntx: %v.\n\n\n", err) + return atoms.NewSymbol("System`Null") + } + return expr +} diff --git a/expreduce/parser/parens/parens.go b/expreduce/parser/parens/parens.go new file mode 100644 index 0000000..d6ed085 --- /dev/null +++ b/expreduce/parser/parens/parens.go @@ -0,0 +1,55 @@ +package parens + +import "github.com/cznic/wl" + +var headsToTokens = map[string]int{ + "System`Alternatives": 124, + "System`And": 57347, + "System`Apply": 57348, + "System`CompoundExpression": 59, + "System`Condition": 57359, + "System`Dot": 46, + "System`Equal": 57380, + "System`Factorial": 33, + "System`Function": 38, + "System`Greater": 62, + "System`GreaterEqual": 57388, + "System`Less": 60, + "System`LessEqual": 57399, + "System`Map": 57401, + "System`Not": 33, + "System`Or": 57412, + "System`PatternTest": 63, + "System`Plus": 43, + "System`Power": 94, + "System`ReplaceAll": 57428, + "System`ReplaceRepeated": 57429, + "System`Rule": 57433, + "System`RuleDelayed": 57434, + "System`SameQ": 57435, + "System`Set": 61, + "System`SetDelayed": 57436, + "System`Span": 57439, + "System`StringJoin": 57445, + "System`Times": 42, + "System`Unequal": 57462, + "System`UnsameQ": 57464, +} + +func NeedsParens(thisHead string, PreviousHead string) bool { + if PreviousHead == "" { + return false + } + prevToken, prevTokenOk := headsToTokens[PreviousHead] + thisToken, thisTokenOk := headsToTokens[thisHead] + if prevTokenOk && thisTokenOk { + prevPrec, prevPrecOk := wl.Precedence[prevToken] + thisPrec, thisPrecOk := wl.Precedence[thisToken] + if prevPrecOk && thisPrecOk { + if prevPrec < thisPrec { + return false + } + } + } + return true +} diff --git a/expreduce/pdmanager.go b/expreduce/pdmanager.go deleted file mode 100644 index c0ce3b4..0000000 --- a/expreduce/pdmanager.go +++ /dev/null @@ -1,123 +0,0 @@ -package expreduce - -import ( - "bytes" - "sort" - "strings" -) - -type PDManager struct { - patternDefined map[string]Ex -} - -func EmptyPD() *PDManager { - return &PDManager{nil} -} - -func CopyPD(orig *PDManager) (dest *PDManager) { - dest = EmptyPD() - // We do not care that this iterates in a random order. - if (*orig).Len() > 0 { - dest.LazyMakeMap() - for k, v := range (*orig).patternDefined { - (*dest).patternDefined[k] = v - } - } - return -} - -func (this *PDManager) LazyMakeMap() { - if this.patternDefined == nil { - this.patternDefined = make(map[string]Ex) - } -} - -func (this *PDManager) Update(toAdd *PDManager) { - if (*toAdd).Len() > 0 { - this.LazyMakeMap() - } - // We do not care that this iterates in a random order. - for k, v := range (*toAdd).patternDefined { - (*this).patternDefined[k] = v - } -} - -func (this *PDManager) Len() int { - if this.patternDefined == nil { - return 0 - } - return len(this.patternDefined) -} - -func (this *PDManager) String(es *EvalState) string { - var buffer bytes.Buffer - buffer.WriteString("{") - // We sort the keys here such that converting identical PDManagers always - // produces the same string. - keys := []string{} - for k := range this.patternDefined { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - v := this.patternDefined[k] - buffer.WriteString(k) - buffer.WriteString("_: ") - buffer.WriteString(v.String(es)) - buffer.WriteString(", ") - } - if strings.HasSuffix(buffer.String(), ", ") { - buffer.Truncate(buffer.Len() - 2) - } - buffer.WriteString("}") - return buffer.String() -} - -func (this *PDManager) Expression() Ex { - res := NewExpression([]Ex{NewSymbol("System`List")}) - // We sort the keys here such that converting identical PDManagers always - // produces the same string. - keys := []string{} - for k := range this.patternDefined { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - v := this.patternDefined[k] - res.appendEx(NewExpression([]Ex{ - NewSymbol("System`Rule"), - NewString(k), - v, - })) - } - return res -} - -func DefineSequence(lhs parsedForm, sequence []Ex, pm *PDManager, sequenceHead string, es *EvalState) bool { - var attemptDefine Ex = nil - if lhs.hasPat { - sequenceHeadSym := NewSymbol(sequenceHead) - oneIdent := sequenceHeadSym.Attrs(&es.defined).OneIdentity - if len(sequence) == 1 && (lhs.isBlank || oneIdent || lhs.isOptional) { - attemptDefine = sequence[0] - } else if len(sequence) == 0 && lhs.isOptional && lhs.defaultExpr != nil { - attemptDefine = lhs.defaultExpr - } else if lhs.isImpliedBs { - attemptDefine = NewExpression(append([]Ex{sequenceHeadSym}, sequence...)) - } else { - head := NewSymbol("System`Sequence") - attemptDefine = NewExpression(append([]Ex{head}, sequence...)) - } - - if pm.patternDefined != nil { - defined, ispd := pm.patternDefined[lhs.patSym.Name] - if ispd && !IsSameQ(defined, attemptDefine, &es.CASLogger) { - es.Debugf("patterns do not match! continuing.") - return false - } - } - pm.LazyMakeMap() - pm.patternDefined[lhs.patSym.Name] = attemptDefine - } - return true -} diff --git a/expreduce/permutations.go b/expreduce/permutations.go deleted file mode 100644 index 4d11686..0000000 --- a/expreduce/permutations.go +++ /dev/null @@ -1,65 +0,0 @@ -package expreduce - -// A Simple, Efficient P(n,k) Algorithm by Alistair Israel -// http://alistairisrael.wordpress.com/2009/09/22/simple-efficient-pnk-algorithm/ -// Go implementation in 2016 by Cory Walker - -func swap(ar []int, first int, second int) { - ar[first], ar[second] = ar[second], ar[first] -} - -func reverse(ar []int) { - for i, j := 0, len(ar)-1; i < j; i, j = i+1, j-1 { - swap(ar, i, j) - } -} - -func nextKPermutation(ar []int, n int, k int) int { - if k <= 0 { - return 0 - } - - var i int - var j int - edge := k - 1 - - if k < n { - j = k - // search for largest j such that a_j > a_edge (a is increasing for j>=k) - // This is the reason why k cannot be zero, since edge = k-1. - for j < n && ar[edge] >= ar[j] { - j++ - } - } - if k < n && j < n { - swap(ar, edge, j) - } else { - if k < n { - // might be an issue here - reverse(ar[k:]) - } - - // find rightmost ascent to left of edge - i = edge - 1 - for i >= 0 && ar[i] >= ar[i+1] { - i-- - } - - if i < 0 { - return 0 - } - - // find smallest j>=i+1 where a_j>a_i (a is decreasing for j>=i+1) - j = n - 1 - for j > i && ar[i] >= ar[j] { - j-- - } - - swap(ar, i, j) - - // might be an issue here - reverse(ar[i+1:]) - } - - return 1 -} diff --git a/expreduce/permutations_test.go b/expreduce/permutations_test.go deleted file mode 100644 index 340a7bf..0000000 --- a/expreduce/permutations_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package expreduce - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestPermutations(t *testing.T) { - fmt.Println("Testing permutations") - - // Test swap - ar := []int{1, 2, 3} - assert.Equal(t, []int{1, 2, 3}, ar) - swap(ar, 1, 2) - assert.Equal(t, []int{1, 3, 2}, ar) - - // Test reverse - reverse(ar) - assert.Equal(t, []int{2, 3, 1}, ar) - ar2 := []int{0, 1} - reverse(ar2) - assert.Equal(t, []int{1, 0}, ar2) - - // Test nextKPermutation - - ar3, cont := []int{0, 1, 2}, 1 - assert.Equal(t, []int{0, 1, 2}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{0, 2, 1}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{1, 0, 2}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{1, 2, 0}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{2, 0, 1}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{2, 1, 0}, ar3) - assert.Equal(t, 1, cont) - - // The algorithm should elect not to continue after this - cont = nextKPermutation(ar3, 3, 2) - assert.Equal(t, []int{2, 1, 0}, ar3) - assert.Equal(t, 0, cont) - - // Test with k = 1 - ar3, cont = []int{0, 1, 2}, 1 - assert.Equal(t, []int{0, 1, 2}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 1) - assert.Equal(t, []int{1, 0, 2}, ar3) - assert.Equal(t, 1, cont) - - cont = nextKPermutation(ar3, 3, 1) - assert.Equal(t, []int{2, 0, 1}, ar3) - assert.Equal(t, 1, cont) - - // The algorithm should elect not to continue after this - cont = nextKPermutation(ar3, 3, 1) - assert.Equal(t, []int{2, 1, 0}, ar3) - assert.Equal(t, 0, cont) -} diff --git a/expreduce/qfunctions.go b/expreduce/qfunctions.go index 68f0d54..df157d2 100644 --- a/expreduce/qfunctions.go +++ b/expreduce/qfunctions.go @@ -2,74 +2,44 @@ package expreduce import ( "math/big" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" ) -type singleParamQType (func(Ex) bool) -type singleParamQLogType (func(Ex, *CASLogger) bool) -type doubleParamQLogType (func(Ex, Ex, *CASLogger) bool) -type evalFnType (func(*Expression, *EvalState) Ex) +type singleParamQType (func(expreduceapi.Ex) bool) +type singleParamQLogType (func(expreduceapi.Ex, expreduceapi.LoggingInterface) bool) +type evalFnType (func(expreduceapi.ExpressionInterface, expreduceapi.EvalStateInterface) expreduceapi.Ex) func singleParamQEval(fn singleParamQType) evalFnType { - return (func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + return (func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - if fn(this.Parts[1]) { - return NewSymbol("System`True") + if fn(this.GetParts()[1]) { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }) } func singleParamQLogEval(fn singleParamQLogType) evalFnType { - return (func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 2 { + return (func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + if len(this.GetParts()) != 2 { return this } - if fn(this.Parts[1], &es.CASLogger) { - return NewSymbol("System`True") + if fn(this.GetParts()[1], es.GetLogger()) { + return atoms.NewSymbol("System`True") } - return NewSymbol("System`False") + return atoms.NewSymbol("System`False") }) } -func doubleParamQLogEval(fn doubleParamQLogType) evalFnType { - return (func(this *Expression, es *EvalState) Ex { - if len(this.Parts) != 3 { - return this - } - if fn(this.Parts[1], this.Parts[2], &es.CASLogger) { - return NewSymbol("System`True") - } - return NewSymbol("System`False") - }) -} - -func numberQ(e Ex) bool { - _, ok := e.(*Integer) - if ok { - return true - } - _, ok = e.(*Flt) - if ok { - return true - } - _, ok = e.(*Rational) - if ok { - return true - } - _, ok = e.(*Complex) - if ok { - return true - } - return false -} - -func vectorQ(e Ex) bool { - l, isL := HeadAssertion(e, "System`List") +func vectorQ(e expreduceapi.Ex) bool { + l, isL := atoms.HeadAssertion(e, "System`List") if isL { - for i := 1; i < len(l.Parts); i++ { - _, subIsL := HeadAssertion(l.Parts[i], "System`List") + for i := 1; i < len(l.GetParts()); i++ { + _, subIsL := atoms.HeadAssertion(l.GetParts()[i], "System`List") if subIsL { return false } @@ -79,40 +49,40 @@ func vectorQ(e Ex) bool { return false } -func matrixQ(e Ex, cl *CASLogger) bool { - l, isL := HeadAssertion(e, "System`List") +func matrixQ(e expreduceapi.Ex, cl expreduceapi.LoggingInterface) bool { + l, isL := atoms.HeadAssertion(e, "System`List") if isL { return len(dimensions(l, 0, cl)) == 2 } return false } -func symbolNameQ(e Ex, name string, cl *CASLogger) bool { - sym, isSym := e.(*Symbol) +func symbolNameQ(e expreduceapi.Ex, name string, cl expreduceapi.LoggingInterface) bool { + sym, isSym := e.(*atoms.Symbol) if isSym { return sym.Name == name } return false } -func trueQ(e Ex, cl *CASLogger) bool { +func trueQ(e expreduceapi.Ex, cl expreduceapi.LoggingInterface) bool { return symbolNameQ(e, "System`True", cl) } -func falseQ(e Ex, cl *CASLogger) bool { +func falseQ(e expreduceapi.Ex, cl expreduceapi.LoggingInterface) bool { return symbolNameQ(e, "System`False", cl) } -func booleanQ(e Ex, cl *CASLogger) bool { - sym, isSym := e.(*Symbol) +func booleanQ(e expreduceapi.Ex, cl expreduceapi.LoggingInterface) bool { + sym, isSym := e.(*atoms.Symbol) if isSym { return sym.Name == "System`False" || sym.Name == "System`True" } return false } -func primeQ(e Ex) bool { - asInt, ok := e.(*Integer) +func primeQ(e expreduceapi.Ex) bool { + asInt, ok := e.(*atoms.Integer) if !ok { return false } diff --git a/expreduce/replace.go b/expreduce/replace.go index 8471727..16be8d9 100644 --- a/expreduce/replace.go +++ b/expreduce/replace.go @@ -1,147 +1,108 @@ package expreduce +import ( + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/matcher" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + // This function assumes e and lhs have the same head and that the head is Flat. -func FlatReplace(e *Expression, lhs *Expression, rhs Ex, orderless bool, es *EvalState) Ex { - looseLhs := NewExpression([]Ex{}) - looseLhs.Parts = append(looseLhs.Parts, lhs.Parts[0]) +func flatReplace(e expreduceapi.ExpressionInterface, lhs expreduceapi.ExpressionInterface, rhs expreduceapi.Ex, orderless bool, es expreduceapi.EvalStateInterface) expreduceapi.Ex { + looseLHS := atoms.NewExpression([]expreduceapi.Ex{}) + looseLHS.AppendEx(lhs.GetParts()[0]) if !orderless { - looseLhs.Parts = append(looseLhs.Parts, NewExpression([]Ex{ - NewSymbol("System`Pattern"), - NewSymbol("System`Expreduce`start"), - NewExpression([]Ex{NewSymbol("System`BlankNullSequence")}), + looseLHS.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Pattern"), + atoms.NewSymbol("System`Expreduce`start"), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`BlankNullSequence")}), })) } - looseLhs.Parts = append(looseLhs.Parts, lhs.Parts[1:]...) - looseLhs.Parts = append(looseLhs.Parts, NewExpression([]Ex{ - NewSymbol("System`Pattern"), - NewSymbol("System`Expreduce`end"), - NewExpression([]Ex{NewSymbol("System`BlankNullSequence")}), + looseLHS.AppendExArray(lhs.GetParts()[1:]) + looseLHS.AppendEx(atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`Pattern"), + atoms.NewSymbol("System`Expreduce`end"), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`BlankNullSequence")}), })) - pm := EmptyPD() - matchq, newPd := IsMatchQ(e, looseLhs, pm, es) + pm := matcher.EmptyPD() + matchq, newPd := matcher.IsMatchQ(e, looseLHS, pm, es) if matchq { - var tmpEx Ex + var tmpEx expreduceapi.Ex if orderless { - tmpEx = ReplacePD(NewExpression([]Ex{ - e.Parts[0], + tmpEx = matcher.ReplacePD(atoms.NewExpression([]expreduceapi.Ex{ + e.GetParts()[0], rhs, - NewSymbol("System`Expreduce`end"), - }), es, newPd) + atoms.NewSymbol("System`Expreduce`end"), + }), + + es, newPd) } else { - tmpEx = ReplacePD(NewExpression([]Ex{ - e.Parts[0], - NewSymbol("System`Expreduce`start"), + tmpEx = matcher.ReplacePD(atoms.NewExpression([]expreduceapi.Ex{ + e.GetParts()[0], + atoms.NewSymbol("System`Expreduce`start"), rhs, - NewSymbol("System`Expreduce`end"), - }), es, newPd) + atoms.NewSymbol("System`Expreduce`end"), + }), + + es, newPd) } return tmpEx } return e } -func ReplacePDInternal(e Ex, pm *PDManager) (Ex, bool) { - asSym, isSym := e.(*Symbol) - if isSym { - for k, def := range pm.patternDefined { - if k == asSym.Name { - // Shouldn't need the copy - return def, true - } - } - } - thisDirty := false - asExpr, isExpr := e.(*Expression) - if isExpr { - for i := range asExpr.Parts { - possiblyNewExpr, dirty := ReplacePDInternal(asExpr.Parts[i], pm) - if dirty { - thisDirty = true - // Mark the expression as dirty and needing eval. - asExpr.evaledHash = 0 - asExpr.cachedHash = 0 - } - asExpr.Parts[i] = possiblyNewExpr - } - } - return e, thisDirty -} - -func ReplacePD(this Ex, es *EvalState, pm *PDManager) Ex { - if pm == nil { - return this - } - containsAny := false - for k := range pm.patternDefined { - if ContainsSymbol(this, k) { - containsAny = true - break - } - } - if !containsAny { - return this - } - - // Expressions are immutable. Any time we change an expression, we must - // first copy it. - res, _ := ReplacePDInternal(this.Copy(), pm) - return res -} - // The goal of this function is to replace all matching expressions with the // RHS upon successful matches. We will NOT substitute any named patterns in // the RHS. We will merely make sure that the named patterns are added to pm. // Final named pattern substitution will occur at the last possible time. -func ReplaceAll(this Ex, r *Expression, es *EvalState, pm *PDManager, - stopAtHead string) Ex { - asExpression, isExpression := this.(*Expression) +func replaceAll(this expreduceapi.Ex, r expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface, pm *matcher.PDManager, + stopAtHead string) expreduceapi.Ex { + asExpression, isExpression := this.(expreduceapi.ExpressionInterface) if isExpression { - _, isRestrictedHead := HeadAssertion(this, stopAtHead) + _, isRestrictedHead := atoms.HeadAssertion(this, stopAtHead) if isRestrictedHead { return this - } else { - // Continue recursion - es.Debugf("ReplaceAll(%v, %v, es, %v)", this, r, pm) - return asExpression.ReplaceAll(r, stopAtHead, es) } + // Continue recursion + es.Debugf("ReplaceAll(%v, %v, es, %v)", this, r, pm) + return exprReplaceAll(asExpression, r, stopAtHead, es) } - if res, matches := IsMatchQ(this, r.Parts[1], pm, es); res { - return ReplacePD(r.Parts[2], es, matches) + if res, matches := matcher.IsMatchQ(this, r.GetParts()[1], pm, es); res { + return matcher.ReplacePD(r.GetParts()[2], es, matches) } return this } -func tryCondWithMatches(rhs Ex, matches *PDManager, es *EvalState) (Ex, bool) { - asCond, isCond := HeadAssertion(rhs, "System`Condition") +func tryCondWithMatches(rhs expreduceapi.Ex, matches *matcher.PDManager, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { + asCond, isCond := atoms.HeadAssertion(rhs, "System`Condition") if !isCond { - if asWith, isWith := HeadAssertion(rhs, "System`With"); isWith { - if len(asWith.Parts) == 3 { - if _, hasCond := HeadAssertion(asWith.Parts[2], "System`Condition"); hasCond { + if asWith, isWith := atoms.HeadAssertion(rhs, "System`With"); isWith { + if len(asWith.GetParts()) == 3 { + if _, hasCond := atoms.HeadAssertion(asWith.GetParts()[2], "System`Condition"); hasCond { appliedWith, ok := applyWithFn(asWith, es) if ok { - asCond, isCond = HeadAssertion(appliedWith, "System`Condition") + asCond, isCond = atoms.HeadAssertion(appliedWith, "System`Condition") } } } } - if asMod, isMod := HeadAssertion(rhs, "System`Module"); isMod { - if len(asMod.Parts) == 3 { - if _, hasCond := HeadAssertion(asMod.Parts[2], "System`Condition"); hasCond { + if asMod, isMod := atoms.HeadAssertion(rhs, "System`Module"); isMod { + if len(asMod.GetParts()) == 3 { + if _, hasCond := atoms.HeadAssertion(asMod.GetParts()[2], "System`Condition"); hasCond { appliedMod, ok := applyModuleFn(asMod, es) if ok { - asCond, isCond = HeadAssertion(appliedMod, "System`Condition") + asCond, isCond = atoms.HeadAssertion(appliedMod, "System`Condition") } } } } } if isCond { - condRes := asCond.Parts[2].Eval(es) - condResSymbol, condResIsSymbol := condRes.(*Symbol) + condRes := es.Eval(asCond.GetParts()[2]) + condResSymbol, condResIsSymbol := condRes.(*atoms.Symbol) if condResIsSymbol { if condResSymbol.Name == "System`True" { - return tryCondWithMatches(asCond.Parts[1], matches, es) + return tryCondWithMatches(asCond.GetParts()[1], matches, es) } } return nil, false @@ -149,14 +110,14 @@ func tryCondWithMatches(rhs Ex, matches *PDManager, es *EvalState) (Ex, bool) { return rhs, true } -func Replace(this Ex, r *Expression, es *EvalState) (Ex, bool) { - mi, cont := NewMatchIter(this, r.Parts[1], EmptyPD(), es) +func replace(this expreduceapi.Ex, r expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) (expreduceapi.Ex, bool) { + mi, cont := matcher.NewMatchIter(this, r.GetParts()[1], matcher.EmptyPD(), es) for cont { - res, matches, done := mi.next() + res, matches, done := mi.Next() cont = !done if res { - replacedRhs := ReplacePD(r.Parts[2], es, matches) - toReturn, ok := tryCondWithMatches(replacedRhs, matches, es) + replacedRHS := matcher.ReplacePD(r.GetParts()[2], es, matches) + toReturn, ok := tryCondWithMatches(replacedRHS, matches, es) if ok { return toReturn, true } diff --git a/expreduce/resources.go b/expreduce/resources.go index df3a416..4fbb349 100644 --- a/expreduce/resources.go +++ b/expreduce/resources.go @@ -126,7 +126,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _resourcesArithmeticM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x5a\x5f\x73\xdb\x46\x92\x7f\xd7\xa7\x98\xd3\x43\x0a\x00\x09\x92\x00\x49\xcb\xb1\xce\x97\xf2\xf9\xe2\x8a\xea\x36\x59\x27\x76\xed\x0b\x8b\x94\x06\xc0\x50\x42\x2d\x01\x70\x01\xd0\x16\x9d\xf8\xbb\xef\xaf\x67\xf0\x67\x40\x0d\x28\xca\x51\xd6\x2e\x81\x40\x4f\x77\x4f\x4f\x4f\x4f\xff\x03\xde\x6f\x76\xc5\xab\x57\xbb\x82\xdf\x0a\xf6\x9a\x9d\xdf\x58\xc2\x63\x03\x26\x7c\x5c\x46\xa3\x91\x7d\xc3\xc2\x2c\xd9\xee\x4a\x51\xb0\xf2\x4e\xb0\x62\x97\xb0\x6c\xcd\xf8\x66\xc3\xc4\xfd\x36\x17\x45\x11\x67\x69\xc1\xe2\x54\x8e\xae\x77\x69\x58\x02\x30\x3a\xbf\x3c\xb3\x9c\xdf\xcf\xff\x21\xf2\x80\x97\x71\xb2\xa0\x49\x96\x8b\x40\xdc\x5e\x5f\x5f\x0f\xd9\xdf\xb7\x84\xc4\x37\x8b\xd0\xbb\xfe\xe1\x97\x5d\x12\x88\xfc\xd7\xa5\xc3\x3b\x23\xfe\xc1\x88\x48\x23\xd0\x2e\xcf\x87\xec\x1c\x6c\x06\x56\xe8\x0d\x42\xdf\x76\xf8\x00\x03\xe7\x5f\x87\x8e\x7d\xc6\x2c\xe7\x23\x64\xf8\x9c\xe5\x9b\x88\xc5\x05\x4b\xb3\x92\xe5\x82\x47\x7b\xb6\xce\x72\x88\x07\x50\xc2\xa3\x14\x22\x8f\x80\x7d\x44\xbc\x06\xfc\x31\x4e\x04\xe0\x46\x71\x87\x1c\xd2\x1c\xc3\xf5\x1f\xe0\x3e\xbe\x84\x37\x65\x99\xc7\x01\x29\x5b\x89\x84\x0d\xf9\xfd\xdd\x86\x97\x43\xf6\xb7\xb8\x28\x79\xb0\x11\x43\x06\xa6\x22\x8f\xc3\x77\x95\xaa\xa1\xb3\x54\x5c\x45\x22\x2d\xe3\x72\x8f\x87\x3c\x12\xf9\x06\x6b\x1c\xb2\xf7\x79\x56\x8a\xb0\x14\xd1\xd7\xcb\xb3\x8f\xa2\x28\x8b\x1b\xe2\x49\x2c\xcf\x18\xfe\xfd\xf8\x21\x4e\xb6\x1b\xf1\xe3\x3d\xa7\x9f\x62\x21\x81\x6a\x80\x27\x82\x08\x16\xfe\x90\x91\x2d\x78\xcb\x61\x3b\xf8\x36\x4b\x12\x4c\xb6\x38\xbf\x5a\xb3\xdf\x04\xdf\x14\x8c\xe7\x82\x91\x25\x00\x3a\x64\x19\xcc\x20\x67\x57\x69\x29\x6e\x45\xae\xc6\x22\x91\x40\x90\x88\x95\x99\x22\x78\x75\xae\xf3\x6b\x26\x9b\x8c\x86\xcc\x9a\x8f\x7c\xe6\xb2\x91\x6f\xe3\x3a\x37\x4e\x2b\xd7\xc0\x77\x65\x96\x40\xed\x21\xec\x70\x4f\x06\x1a\xc4\xd8\x57\xb6\x89\xff\x29\x58\x29\xf2\xa4\x6f\x0e\x3e\x78\xe1\x04\x2b\x2c\x8b\x63\x59\xb8\xc1\x75\x4e\x00\x23\xb2\x65\xcd\x99\xc3\xc2\x15\xb7\x81\x66\x4d\x71\x1f\xd9\x36\x64\xe4\x83\xc0\x76\xe5\x75\x10\xba\xe1\xc0\x77\x80\x82\x6b\x34\x98\xe3\x2f\x72\xe9\x3a\x25\x98\x91\xa9\x3b\xc5\xdc\x01\x0b\x59\xc4\x70\x5c\x86\x6c\xe6\x70\x27\x70\x42\x27\x72\x84\xb3\xc6\x3c\xee\x85\x0e\x58\x4a\x0e\x30\x9d\x1f\xe5\x06\xb6\x7b\x04\x53\x07\xa0\xd5\x03\x1d\x46\x9e\xd2\x59\xa4\x83\xd0\xcc\x0a\x6b\x4a\x6f\xe5\xbc\xe7\x96\x5c\xb2\x4d\xc6\xe7\x39\xf5\x43\x47\x44\x1d\xd9\x1b\xd5\x38\x8a\x62\xf4\x38\x89\xdf\x25\xf1\x4f\x20\x69\x45\xaa\x6e\xc7\xde\xc9\x22\x35\x14\xa3\x23\x22\x75\x25\x3a\x41\x20\xc7\x0a\x80\x12\x2a\x82\xe6\xa9\x9f\xc0\x25\x8e\xae\x5a\x83\x7b\x82\x5e\x3b\xf8\x8f\x62\x5b\xae\x37\xb2\x3b\x6b\x70\x4f\xd9\x09\x7d\x92\x5a\x4d\xee\x11\xcd\x3e\x9c\xa6\xa5\x92\xda\x3d\x34\xbb\xf2\x8e\x97\xec\x33\x4e\x76\x26\x9d\x6c\x24\x36\xa2\x14\x32\x26\x50\x10\xe0\x11\xbc\x51\x54\x74\x0c\xf1\xb4\x43\xde\xa2\x0d\xd9\x04\x12\x4c\x0c\x73\x8b\x64\x5b\xee\x99\xf4\x02\x5a\x00\x32\x4f\x36\x94\x78\x8b\xa5\x81\xcd\x36\xcf\xb6\x70\x54\x3c\x0c\x77\xc9\x0e\x1e\x16\x4c\x28\xae\xfd\xc6\x95\xfb\x2e\x7a\x8f\xd1\xec\x62\xfc\x02\xa2\x15\xfb\x44\x6a\xaa\x26\x58\xcc\x87\xcc\x5f\x62\xa0\x01\x5c\x0c\xd9\x94\x00\x53\x85\x7d\xc4\xb0\xfb\x39\xba\xdf\xc8\xd2\xf5\xbe\x7f\x1a\x4f\xf7\x04\x9e\x47\x56\x7e\xc0\xd3\x35\x30\x3d\xdc\x00\xe5\xb4\xc1\x9e\x25\x59\x9a\x25\x31\x45\x12\x6c\x40\x24\x6e\x73\x21\x98\x67\xdc\x50\x3e\xb8\x70\x02\xe5\xbc\x7d\x27\x50\xce\xdb\xc0\x9a\x83\x25\xe2\xce\xad\x48\x45\xce\x37\xec\x13\x02\xd1\xa1\x63\x7c\x84\x63\x0f\x62\x1d\x39\x7c\xe7\xb1\xd8\xc1\x11\x02\x2a\x74\xf7\x01\xfa\xa1\xbc\xbb\x82\xd4\x20\xe3\x16\xfb\x1c\x97\x77\xd9\x8e\xd6\x10\x66\x62\xbd\x8e\xc3\x18\x51\xaf\x47\xf4\xde\x58\xf6\x40\x21\x51\x14\x97\xf1\x27\xc1\xe2\x2a\x4f\x30\x33\x04\xab\xc1\xa4\x67\x39\x41\x15\xf8\x06\xa6\x33\xd9\xf2\x4f\x49\xd9\xa2\xef\x34\x72\xd7\x1c\x14\x31\x24\x7d\x56\xef\xa8\x16\x73\x7b\x19\x28\xf1\x8e\xe2\x3c\x9d\xcd\xe1\x4a\x03\x5e\x20\xd8\x16\x94\x39\xc5\xd8\x1c\x69\xf0\x66\xe7\x13\x3d\xcc\x14\xa2\xff\x5c\x9a\xf1\xf2\x62\x34\x97\x8e\xc2\x61\xf7\xe0\x65\xdd\xe3\xe1\xe5\x64\x44\x20\xba\xdc\xd3\x5c\xbe\xbc\x93\x37\x73\xb3\x3e\x2a\x2e\xd6\xc5\x88\xf8\xd8\x47\x19\x61\xc4\xa1\x3b\xba\xc8\x95\x4c\xe8\x7e\xaa\x28\x1f\x9b\x68\x3e\x71\xa4\xf5\xfd\xe5\xff\xbb\x5b\xfa\x33\xb9\x09\x2a\x6f\x36\xb4\x95\x94\xa2\xe2\x0c\xb6\x9e\xc9\xb8\xaf\x2e\xe9\x34\xc1\xa9\xf6\x26\xb8\x41\xfa\xed\x7e\x4f\xbf\x00\xa4\xd2\xe1\x61\xd0\xb8\x44\xe4\x75\x18\x0b\xa4\x3b\xa0\xbb\x10\x2e\x92\x52\x3d\x05\x70\x42\xa8\x47\xe6\x82\x3d\x59\xa3\x53\x39\x12\x52\x3c\xa1\x0d\x25\x1b\x17\x34\x0d\x88\xa2\xa9\x53\xb9\xa7\x1e\x11\xee\x49\x6e\xcf\xd9\xd3\x7e\x38\xa8\x16\x5e\x4a\xc8\xf7\x00\x40\x74\xe7\x5e\xfe\xfa\xf2\x7a\x2f\xe5\x01\xa4\x57\x9e\x36\x4b\x7d\x34\x8b\x3d\x85\x85\x7a\x98\xb5\x2c\xb4\x51\xe7\xe2\x64\x16\x38\x26\xf8\x7b\x02\x13\x9f\xe5\xa4\x32\x86\xda\x85\x6e\x69\x0b\x0b\x5c\x4b\x79\x7a\xd4\xb5\x30\x12\x4e\xc9\xe4\xa1\x2e\xb6\xa7\x3c\x66\x06\x8d\xed\x25\x23\x04\x5f\x69\xee\x7b\x9b\x38\x5a\x4a\xa9\x9e\x2d\x39\x1d\x50\xf4\x69\x77\x06\x11\xa0\x7e\x88\x53\x48\x81\x2c\xe2\x88\x07\x70\x04\xd0\x29\x24\x93\x6a\x88\x1e\x07\xc4\x5f\xc2\xcc\xfb\xce\x48\x84\x2f\x52\x82\x3d\xfb\x82\x6d\x97\x00\x1f\x20\x97\x59\x72\x4c\x89\xb7\x77\xbe\x54\x15\xc7\x19\x6a\xc6\xb3\x0f\xbb\x44\x6f\x0c\xe0\x71\x41\x29\xd7\x90\xa5\xcb\x1b\x54\xd6\xe5\x2e\x4f\x3b\x4d\x81\x9b\x94\x9a\x05\xdb\x58\xc8\x48\x7e\x43\xb8\x37\xa3\xb3\x33\x8d\xf0\x77\x24\x03\x20\xff\xda\x43\x2f\x29\x98\xf8\xc4\x37\x3b\x79\x1c\x29\x18\xb2\x1b\xd0\xdc\x40\x00\x8f\x0a\x48\x4c\x61\xe2\xf8\xcd\x4c\x6f\x70\xad\xd8\x9e\x5f\xd2\x82\x17\xf1\xf5\x87\x7d\x12\x64\x1b\xb0\x6e\x6f\x11\x18\xd2\xeb\xaa\xa8\xfd\xba\x64\xaf\x20\xcd\xd8\x77\x52\x47\x6e\x4c\x6a\x1f\xa1\xf4\xbe\x99\xf2\x1b\xc9\xa4\xa8\xea\xe1\x1b\x24\x3d\x42\xa8\xf5\x26\xc0\x43\xb6\x26\x7e\xca\x36\xd1\x9b\x0d\x68\x51\xd7\x47\x4d\xbb\xc1\xd4\x79\x00\xc5\x53\x1a\x0f\x33\xe4\x94\x52\x50\x92\x70\xc8\xf0\xe4\x4d\xbe\x2e\xcd\xa1\xa3\x8b\xea\x9d\x8e\x3a\x39\x82\x3a\x9b\x4f\x26\x1e\xfe\x26\x87\xcc\xa7\x80\x3d\x8d\x68\x72\x9c\xa8\xa3\xe5\x43\xc2\xf4\xc9\x44\x5e\x3f\xd1\xb4\x92\x4b\xe6\x8b\xc0\xe6\x72\x0a\xff\x2b\x6e\x03\x25\x66\x0f\x61\x30\x40\xee\x32\x10\x15\xb5\xa2\x24\x12\x84\x30\x6c\xb6\xf8\xda\x47\xc6\x6e\xa9\x7a\x96\xd7\x48\x5e\x85\xbc\x06\xec\x4e\xc2\xef\x24\xfc\x4e\xc2\xef\x2a\xe6\xe4\xc6\x1f\xb0\xc7\x23\x81\x6f\x87\xec\x8e\xe6\xd2\x3c\x94\x6c\xba\x1d\x36\x2f\x1d\x6a\x5e\x3a\xa6\xe6\x25\x8a\xbe\x68\x17\x96\x27\x37\x30\xd9\x47\x6a\x1a\xc6\xaa\xb1\xb4\xd9\x4b\x8c\x24\x53\xc5\x0b\x71\x75\x63\x9c\xd0\xb4\xa0\xcc\x37\xdf\x6d\x44\xcd\xa4\xd8\x17\xa5\x48\x46\xec\xe7\x2c\x8a\xd7\x7b\xe9\x70\xce\x42\x9e\x0b\xe4\x42\xf6\xd9\x61\xc3\xb0\x6e\x3a\xf2\xeb\x55\xd3\x3b\x4c\xa8\x5b\xa8\x03\x52\xad\x7d\x48\x47\x13\x44\x0e\x5f\x59\xc9\x20\xb5\x1d\x80\xd9\xf8\x92\x59\xff\x55\x75\x1b\x17\x7c\xc9\xfe\xf8\x83\x35\x8f\x49\xf7\x31\x5d\xda\xb4\xb4\x43\x31\x78\xed\x6d\xe0\x4c\xe3\x48\x4a\x14\xd4\xa0\x55\x7a\xdd\x99\x1d\x08\x8e\x6b\x05\x2b\x2b\x1d\x78\x76\x2b\x00\x67\xaf\x5f\x53\xdb\xe1\x12\xab\x6c\xd8\xad\xc2\xeb\xba\x2c\x74\x02\x13\x10\x3b\x50\x82\x31\xf1\xb5\x10\xad\xed\x55\x28\x41\x26\x19\x9f\x43\x55\x97\x86\x2d\x68\xea\x56\x8f\x58\x55\x32\x82\x4b\x9c\xa2\x80\xac\x66\xec\x51\x85\x44\x21\xfe\xa9\xeb\x29\xfe\xca\x26\x17\x28\xb4\x1a\x1a\x97\x0e\xe5\x2e\x69\x35\x5c\xad\x59\x72\x68\x26\x07\xc6\x10\x54\x4b\x98\xae\x52\x80\x62\xf4\x96\xd2\x53\x71\x7f\x95\xae\x91\x93\x52\x87\x57\x27\x3e\x18\xbc\x6c\xf5\xfe\xc3\x2f\xe2\x96\x53\x4d\xb6\x0a\x5a\x5d\x87\x8d\x48\x91\x79\x03\xb0\x88\x55\x20\x21\xda\x8e\x86\xec\xbb\xef\x70\x68\xe9\x36\x82\xed\xf4\xef\x4a\xcd\x3c\x69\x98\x77\x35\xd7\x42\x8f\xec\x4f\xb5\xec\x90\xbd\x62\x56\xa3\x9b\x56\x75\x51\xb3\x3f\xec\x0f\xa6\x9c\x4e\xa5\x04\x0d\xe9\x28\xdd\x12\x0e\x13\x84\xef\xb3\xcf\x22\xd7\xcd\x5e\xb7\x82\xbc\xc5\xee\x28\xfc\x8c\x55\xd2\xc9\x72\x65\x65\x79\xe3\x5c\x26\x77\x0a\x69\x29\x95\x86\x53\x4f\xc5\x1f\x4e\xe1\x6b\xa8\x6c\x42\xca\xe3\xec\x7f\x80\x74\xf6\x21\x4e\x17\xf7\xd7\x4b\xe7\x6d\x56\xd0\xef\x8a\xd4\xad\xab\xff\x23\xc7\xf8\xb2\x32\xff\x0a\xc9\xa9\x88\x1e\x20\xbf\xcd\xca\x16\x59\x8b\xcd\x6a\x57\x9e\xf9\xc5\x81\x64\x7a\x42\x00\x6f\xba\xf4\x1f\x3a\x15\xb2\xf4\x8e\x05\xe3\xdb\x2d\x9c\x68\xa7\x77\xdf\xd3\xa7\x9f\x8e\xfd\x21\xd5\xc2\x54\x56\xae\xc8\x99\x4f\x6c\x9b\x2a\x4b\x1c\x25\x73\x7f\x62\x65\xf9\x83\xd0\xa6\x3d\x41\x59\xb4\x0a\xcd\x48\x63\x4b\x16\x03\x84\x36\x0e\xc6\xe1\x38\x6a\xdb\xeb\xef\x76\x39\xbd\xb8\x38\xb6\xa4\xda\x3e\xe8\x28\x07\xf5\xbb\x8d\x62\xb7\xdd\x6e\xb3\x9c\xf2\x4a\x0b\xe1\x04\x75\x64\x5c\xb2\xbc\xc6\x8c\x44\xb8\xe1\xea\x49\x76\x45\x23\xf9\x26\x8a\x60\x50\xb9\xdd\xb3\x76\xd7\x1f\x4f\xbb\xd6\xe8\xfa\x4b\xa7\xed\xad\xf9\xd4\x5b\x73\x5c\xdf\xf8\x76\xe4\x63\x37\xca\xa5\x59\x79\x47\xbd\x25\x84\xb0\x48\xc0\x47\xa8\xb7\x30\x81\x60\x59\x2a\x7a\xa6\xc7\x7c\xca\xc6\x97\x8f\xbd\x7c\x38\xde\x05\x4e\x76\x9b\x32\x96\x85\x75\x5f\x2f\x98\x52\x35\xc7\xbc\x9f\x18\x9a\x3b\xde\x78\x2e\x87\xcd\x1d\x60\x65\x92\x8f\xb5\x80\xb5\xd5\x3c\x64\xb4\xce\xb9\x3c\x09\x07\xfd\x1c\x23\x23\x1f\xb9\xe3\x7c\x32\x36\x77\xfb\xe6\x32\x95\x3c\x3a\x8a\x84\x0d\x18\xe6\xf1\xf1\x4c\x21\xcc\x7b\x18\x78\x35\x82\xd7\x83\x60\xb0\xec\x87\xab\xfd\xad\xb5\x4a\x3a\xdd\x47\x5e\x15\x79\x13\xea\xef\xce\xb0\x9e\x95\xdf\xdb\x0f\x6e\x90\x66\x66\x3b\xc2\x08\xcc\x98\xae\xe6\xb2\xbb\x1e\x7e\x71\x7c\x02\xac\xdd\x99\x4d\x1e\x91\xc2\x1b\x5b\x10\xd5\xae\x10\x9f\xad\xd5\xef\x3b\x75\xaf\x1b\xbf\x8e\x76\x22\xf5\xf3\xe8\x0f\x71\x1a\x5f\x3c\xdf\x51\xd6\x25\xa8\x31\x3b\xed\xf6\x5e\x2e\x6c\x3c\x66\x3f\xa1\x10\x33\xe9\xa0\x3d\x8d\xfd\x7d\x60\x6d\xe2\x39\xcd\x88\xd3\xd7\xab\x77\xae\xde\x23\xf2\xa3\xaf\xeb\x78\xfd\xee\x90\x9f\x22\x92\xa1\x75\xac\x6f\x34\xb1\x7a\x89\x13\xf0\xb2\xdf\x16\xd4\x3b\x3b\x6f\xdc\x2f\x95\xa7\xac\x85\x9f\x24\x91\xb2\x1b\xb8\x1a\x18\xcb\x17\x91\x67\x46\xbf\x70\x3c\x52\x69\x33\x74\x23\xa2\x6a\xf4\xab\x24\xc4\xdc\x8c\x3f\x29\xa2\x01\xc9\xad\x90\xc6\x7d\x48\x09\xbd\x23\x48\x1c\x73\x57\x12\xc6\x94\x8c\xfb\x87\xc0\x36\xe9\x79\xc3\xa1\xdc\xaa\xca\xa2\xfc\x61\x6b\x8d\x74\x3a\x96\x43\x8e\xb0\x81\xec\x88\xbe\x6e\x70\xfc\x95\xbc\xeb\xaa\xe3\x6d\x96\x56\xef\x65\x48\xbd\xe2\x1e\x9e\x98\x02\x2b\x25\x28\x4d\x11\x56\x50\xb0\xca\xc5\xe1\x11\x6d\x24\xc8\x77\xc8\x6a\x7e\xe6\x65\x78\xf7\xeb\xe2\xc3\xbf\x72\x38\x15\xe7\x7d\xbc\x74\x46\x90\xfc\x9a\xbe\x34\xe8\xf8\x7c\xad\xe1\x4e\x59\x2e\x44\x9a\xda\xea\x55\x3c\x24\x75\xfd\x0a\x42\xc2\xba\xf2\x46\x76\x0e\x7b\xdc\xb1\xe7\xcb\xd5\x79\xbe\xc2\xf7\x2b\x42\xfa\x35\x52\x5c\x8d\xad\x19\x93\x12\x4e\x29\xfb\xb4\x26\x83\x2b\x22\xae\x41\x1a\x0d\x6a\x4e\xe2\xeb\x54\x23\xc8\x20\xe5\xe3\x54\xa9\x90\x1e\xc9\xb2\xb4\x67\x38\x29\x0c\xdb\x0f\x81\x15\xa8\x0f\x4e\x20\xe8\x41\x4e\x30\xa3\x67\xb7\x9e\x40\x97\x95\x99\x83\x6a\x77\x39\xba\xc0\x66\x37\x68\x75\x14\x20\x35\xe0\x5e\x8d\x67\x36\x48\x8f\xd3\x79\x07\x74\xca\xe8\x5c\xb9\x03\x35\x65\x0f\xe9\xdc\x4c\x3a\x7f\x94\xd4\x9a\x0e\x48\xb6\x5a\xb2\x9a\xd2\x1b\xd0\xac\xec\xea\x11\xe2\xab\x66\x4e\x0a\xda\x8a\x74\x7a\x02\xa1\xd4\x91\x6f\x10\xd8\xff\x13\xc4\xfe\xd8\x3d\x41\xe4\xe9\xc0\x9a\xb3\x2b\xdb\xb8\xe6\xf9\x09\xb3\xeb\x73\x93\x27\x52\x16\xee\x8d\x5f\x38\x57\x76\x6d\x7c\x54\xe2\xb9\x7e\x7d\x3a\x28\xa7\xfc\xff\x34\xfb\x9c\xbe\xe3\xf1\x66\x97\x9b\x7b\x80\xae\xaf\x8e\xa4\x3a\x9e\xcd\x41\xeb\x09\xb4\xc0\x1d\x70\x0d\x97\x37\x73\xc9\x46\xd1\x7b\x95\x13\xeb\xad\xa2\x0a\xd4\xd3\xd2\xd6\x92\xe8\xbe\xb6\x76\x97\x41\x4f\x6b\x5b\xe7\x73\x72\x7b\xdb\xc4\xf9\x4f\x31\xef\xb6\xb9\xf5\xaf\xcc\x14\x87\x27\x76\x73\x2b\xaa\xa7\x74\x74\x3d\x7f\x22\x39\xc9\x75\x55\x3d\x44\xca\xf2\x7b\x7a\x87\xeb\x85\x47\x8d\x90\xf5\xc2\x57\x3f\x53\xf5\x33\x53\x3f\xf3\x65\xcb\x6b\xbd\xa0\x58\xf3\x08\xbb\xf9\xc5\x0b\x6d\x76\x0a\x88\x44\x30\xeb\xeb\xae\xce\x66\xba\xb0\x6d\xbb\xd4\x6b\xdb\xa5\x9e\x6a\x97\x6a\x26\xf6\x26\xe8\x74\x22\xf1\x28\xf7\x0f\x5b\x86\x4a\x37\xa4\xc4\xb3\xea\x42\xf2\xa0\xc8\x36\xd0\x3e\xa3\xbd\x12\x9a\x4d\xd1\xd6\x80\x8a\xb7\x1f\x0e\x52\xa1\x7f\x85\x15\xfe\xf7\x64\xe8\x72\x04\x55\x85\x50\xb7\x7b\xd4\x70\xd3\xfb\xa1\xa1\x83\x86\x90\x01\xc3\xe5\xaa\xef\x22\x67\x5a\x76\x8c\x01\x20\x69\x08\x47\x5a\x06\x9a\x59\x74\xac\xa4\x31\x0d\xf0\x78\x8a\x59\xcc\x47\xd8\x0b\x29\x16\xee\x7a\xf6\x4e\x21\xcc\x97\xc6\x82\xf7\x4d\x47\x99\xf2\x84\xee\xd2\x62\x2b\x42\xa4\x5a\x38\x05\x71\xba\xdd\x95\x94\x6c\xa1\x2a\x45\xd9\xbb\x11\xeb\x12\xe3\xcd\x29\xe9\xa9\x81\x95\x6e\x86\x95\x8e\x8c\xf3\xfe\xef\xae\x64\x45\x96\x88\x52\x96\xa1\x07\x1f\x04\x60\xc7\x91\xd6\xa0\xde\xc8\x8f\x4c\x20\x1b\x3b\xcb\x6a\x16\xb7\x7a\xea\xad\xb9\x3b\x1f\x29\x10\xc5\xc4\xac\x2d\x1a\xba\x5f\xd5\xc2\xbb\x74\x7b\x04\xaf\xfa\xce\xab\xc5\xae\x01\xba\x61\xff\x5f\xfc\x09\xf5\x82\x6e\xdb\x0a\x42\xc7\x38\x58\x6a\x2d\xf6\x1b\x14\x9f\xd2\x8a\xeb\xf1\xeb\x61\xa0\x8c\x0d\x03\x1d\x4b\x53\x08\x27\x1b\x5b\x63\x5d\x8a\xee\x89\x9f\xb0\x56\xd2\x78\x50\xdc\xbc\xb3\xb0\xab\x34\xcc\x05\x6d\xa7\xbe\xb6\x06\x88\x9d\xbf\xa1\xae\x4d\x51\xb9\x66\x8e\xa7\x34\xea\xf8\xdf\x2c\x8f\x6f\x63\x2a\xa9\xa5\xf1\xd1\xca\x35\x6a\xb5\x72\xea\xa1\xca\x2f\x74\xbc\x4b\xf9\x2d\x90\xd7\x7d\x93\xd6\xe0\x37\x1e\xf8\x5d\x9c\x17\xe5\x09\x07\xad\xa1\x7c\x8a\x36\x50\x8d\x96\x59\xf5\x5a\xe2\x35\x33\x57\xe6\x1a\xce\x60\x60\x2e\xed\x5b\x8c\x8e\x9d\x08\x83\x3a\x1b\xa0\x54\x67\xb1\x0b\x4a\x6a\xba\x90\x4e\xd7\x79\x96\x9c\xa8\x55\x8d\x49\x47\xab\xae\xd2\xea\xe0\x50\xab\x0d\xfe\x93\xb5\xda\x50\xfe\x85\x5a\x75\x5d\x73\x47\xc4\xac\xd5\xf7\xb9\x30\xda\xa9\x0e\x3f\xc1\x54\x53\xf1\xb9\xd5\x67\x97\xf6\xd0\x50\xed\x83\x0c\x41\x7c\xbb\x91\xea\xc4\xcf\xad\x51\x58\xe1\x60\xd0\x68\xec\x09\x76\x0a\xa1\x8c\xa6\xaa\xc3\x4f\xb7\xd6\x43\xc5\x1e\xb1\xd5\x07\x8a\xfd\x76\x3b\xd5\x89\x9f\x5b\xb1\x30\x44\xd7\x3d\xaa\xd8\x1e\x53\x7d\x13\x45\x1f\xb3\x4e\x0e\x44\x80\x3a\x4c\x48\xfb\xbc\x09\x6e\x4e\xb2\xd0\x8a\x52\xbe\x85\xec\x9a\x67\xd0\xd5\xa2\x44\xec\x55\x5f\x9b\x96\x10\xda\x73\x2b\x6a\xae\xe1\x0c\x5e\xb3\x9e\xee\xaf\x59\x57\x1f\x2a\xdb\x7a\x07\xbb\xea\x7e\x64\xd3\xc2\x6b\xcd\xb5\x76\x48\xea\x3b\xcd\x12\xbb\x7c\x1e\xe8\xd1\x3d\xd4\xa3\x8e\xff\xb8\x3a\x75\xec\xe7\xd6\xaa\xa7\xe1\xb8\x7d\x5a\xf5\x8c\x5a\xfd\x77\x00\x00\x00\xff\xff\x98\xb7\xdf\xbc\xcb\x34\x00\x00") +var _resourcesArithmeticM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x5a\x6f\x73\xdb\x36\x93\x7f\xef\x4f\x81\xf3\x8b\x0e\x49\x89\x92\x48\x49\x71\x1a\x5f\xda\xc9\xe5\x9a\xa9\xe7\xae\xbd\xb4\xc9\xdc\x1b\x8d\x64\x83\x24\x64\x73\x1e\x91\xd4\x43\x52\x89\x95\x36\xdf\xfd\xf9\x2d\xc0\x3f\xa0\x0c\xca\x72\xea\x3e\xc9\x98\x22\x17\xbb\x8b\xc5\x0f\x0b\x60\x77\xc9\xf7\x9b\x5d\xf1\xea\xd5\xae\xe0\xb7\x82\xbd\x66\xe7\x37\x96\xf0\xd8\x80\x09\x1f\x97\xd1\x68\x64\xdf\xb0\x30\x4b\xb6\xbb\x52\x14\xac\xbc\x13\xac\xd8\x25\x2c\x5b\x33\xbe\xd9\x30\x71\xbf\xcd\x45\x51\xc4\x59\x5a\xb0\x38\x95\xad\xeb\x5d\x1a\x96\x20\x8c\xce\x2f\xcf\x2c\xe7\x8f\xf3\xff\x17\x79\xc0\xcb\x38\x59\x50\x27\xcb\x45\x20\x6e\xaf\xaf\xaf\x87\xec\xff\xb6\xc4\xc4\x37\x8b\xd0\xbb\xfe\xf1\xd7\x5d\x12\x88\xfc\xb7\xa5\xc3\x3b\x2d\xfe\x41\x8b\x48\x23\xc8\x2e\xcf\x87\xec\x1c\x6a\x06\x56\xe8\x0d\x42\xdf\x76\xf8\x00\x0d\xe7\x5f\x87\x8e\x7d\xc6\x2c\xe7\x23\x6c\xf8\x9c\xe5\x9b\x88\xc5\x05\x4b\xb3\x92\xe5\x82\x47\x7b\xb6\xce\x72\x98\x07\x52\xc2\xa3\x14\x26\x8f\xc0\x7d\xc4\xbc\x86\xfc\x31\x4e\x04\xe8\x46\x73\x87\x1c\xd6\x1c\xe3\xf5\x1f\xf0\x3e\x3e\x84\x37\x65\x99\xc7\x01\x81\xad\x4c\xc2\x84\xfc\xf1\x6e\xc3\xcb\x21\xfb\xdf\xb8\x28\x79\xb0\x11\x43\x06\xa5\x22\x8f\xc3\x77\x15\xd4\xc0\x2c\x15\x57\x91\x48\xcb\xb8\xdc\xe3\x21\x8f\x44\xbe\xc1\x18\x87\xec\x7d\x9e\x95\x22\x2c\x45\xf4\xf5\xf2\xec\xa3\x28\xca\xe2\x86\x74\x92\xca\x33\x86\x7f\x3f\x7d\x88\x93\xed\x46\xfc\x74\xcf\xe9\xa7\x58\x48\xa2\x6a\xe0\x89\x20\x81\x85\x3f\x64\xe4\x0b\xde\x72\xd8\x36\xbe\xcd\x92\x04\x9d\x2d\xce\xaf\xd6\xec\x77\xc1\x37\x05\xe3\xb9\x60\xe4\x09\xa0\x0e\x59\x06\x37\xc8\xd9\x55\x5a\x8a\x5b\x91\xab\xb6\x48\x24\x30\x24\x62\x65\xa6\x04\x5e\x9d\xeb\xfa\x9a\xce\x26\xa3\x21\xb3\xe6\x23\x9f\xb9\x6c\xe4\xdb\xb8\xce\x8d\xdd\xca\x31\xf0\x5d\x99\x25\x80\x3d\x84\x1f\xee\xc9\x41\x83\x18\xf3\xca\x36\xf1\x3f\x04\x2b\x45\x9e\xf4\xf5\xc1\x07\x2f\x9c\x60\x85\x61\x71\x0c\x0b\x37\xb8\xce\x89\x60\x64\xb6\xac\x39\x73\x58\xb8\xe2\x36\xd8\xac\x29\xee\x23\xdb\x86\x8d\x7c\x10\xd8\xae\xbc\x0e\x42\x37\x1c\xf8\x0e\x58\x70\x8d\x06\x73\xfc\x45\x2e\x5d\xa7\x44\x33\x2a\x75\xa7\xe8\x3b\x60\x21\x8b\x18\x96\xcb\x90\xcd\x1c\xee\x04\x4e\xe8\x44\x8e\x70\xd6\xe8\xc7\xbd\xd0\x09\x4b\xa9\x01\xae\xf3\x93\x9c\xc0\x76\x8e\xe0\xea\x20\xb4\x38\xd0\x62\xe4\x29\xad\x45\x5a\x08\x4d\xaf\xf0\xa6\xf4\x56\xf6\x7b\x6e\xc9\x21\xdb\xe4\x7c\x9e\x53\x3f\x74\x4c\xd4\x99\xbd\x51\xcd\xa3\x24\x46\x8f\x8b\xf8\x5d\x11\xff\x04\x91\xd6\xa4\xea\x76\xec\x9d\x6c\x52\x23\x31\x3a\x62\x52\xd7\xa2\x13\x0c\x72\xac\x00\x2c\xa1\x12\x68\x9e\xfa\x05\x5c\xd2\xe8\xaa\x31\xb8\x27\xe0\xda\xe1\x7f\x94\xdb\x72\xbd\x91\xdd\x19\x83\x7b\xca\x4c\xe8\x9d\xd4\x30\xb9\x47\x90\x7d\xd8\x4d\x2b\x25\xd1\x3d\x74\xbb\xf2\x8e\x97\xec\x33\x56\x76\x26\x37\xd9\x48\x6c\x44\x29\xe4\x99\x40\x87\x00\x8f\xb0\x1b\x45\x45\xc7\x11\x4f\x5b\xe4\x2d\xdb\x90\x4d\x60\xc1\xc4\xd0\xb7\x48\xb6\xe5\x9e\xc9\x5d\x40\x3b\x80\xcc\x9d\x0d\x25\xdf\x62\x69\x50\xb3\xcd\xb3\x2d\x36\x2a\x1e\x86\xbb\x64\x87\x1d\x16\x4a\xe8\x5c\xfb\x9d\xab\xed\xbb\xe8\x5d\x46\xb3\x8b\xf1\x0b\x98\x56\xec\x13\x89\x54\x2d\xb0\x98\x0f\x99\xbf\x44\x43\x43\xb8\x18\xb2\x29\x11\xa6\x8a\xfb\x88\x63\xf7\x6b\x74\xbf\x51\xa5\xeb\x7d\xff\x34\x9d\xee\x09\x3a\x8f\x8c\xfc\x40\xa7\x6b\x50\x7a\x38\x01\x6a\xd3\x86\x7a\x96\x64\x69\x96\xc4\x74\x92\x60\x02\x22\x71\x9b\x0b\xc1\x3c\xe3\x84\xf2\xc1\x85\x13\xa8\xcd\xdb\x77\x02\xb5\x79\x1b\x54\x73\xa8\xc4\xb9\x73\x2b\x52\x91\xf3\x0d\xfb\x84\x83\xe8\x70\x63\x7c\x44\x63\x0f\x63\x7d\x72\xf8\xce\x63\x67\x07\xc7\x11\x50\xb1\xbb\x0f\xd8\x0f\xed\xdd\x15\x04\x83\x3c\xb7\xd8\xe7\xb8\xbc\xcb\x76\x34\x86\x30\x13\xeb\x75\x1c\xc6\x38\xf5\x7a\x4c\xef\x3d\xcb\x1e\x00\x12\x45\x71\x19\x7f\x12\x2c\xae\xe2\x04\xb3\x42\xa8\x1a\x4c\x7a\x86\x13\x54\x07\xdf\xc0\xb4\x26\x5b\xfd\x29\x81\x2d\xfa\x56\x23\x77\xcd\x87\x22\x9a\xe4\x9e\xd5\xdb\xaa\x9d\xb9\xbd\x0a\x94\x79\x47\x79\x9e\xae\xe6\x70\xa4\x01\x2f\x70\xd8\x16\x14\x39\xc5\x98\x1c\xe9\xf0\xe6\xcd\x27\x7a\x18\x29\x44\xff\xbe\x30\xe3\xe5\xc5\x68\x2e\x37\x0a\x87\xdd\x43\x97\x75\x8f\x87\x97\x93\x11\x91\xe8\x72\x4f\x7d\xf9\xf2\x4e\xde\xcc\xcd\x78\x54\x5a\xac\x8b\x11\xe9\xb1\x8f\x2a\x42\x8b\x43\x77\x74\x91\x23\x99\xd0\xfd\x54\x49\x3e\xd6\xd1\x7c\xe2\x48\xef\xfb\xdb\xff\x77\xa7\xf4\x17\xda\x26\x28\xbd\xd9\xd0\x54\x52\x88\x8a\x35\xd8\xee\x4c\xc6\x79\x75\x09\xd3\x04\xab\xda\x9b\xe0\x06\xe1\xb7\xfb\x3d\xfd\x82\x90\xca\x0d\x0f\x8d\xc6\x21\x22\xae\x43\x5b\x20\xb7\x03\xba\x0b\xb1\x45\x52\xa8\xa7\x08\x4e\x08\x78\x64\x2c\xd8\x13\x35\x3a\xd5\x46\x42\xc0\x13\xdb\x50\xaa\x71\x21\xd3\x90\xe8\x34\x75\xaa\xed\xa9\xc7\x84\x7b\xb2\xdb\x73\xf6\x34\x1f\x0e\xb2\x85\x97\x92\xf2\x3d\x08\x30\xdd\xb9\x97\xbf\xbe\xbc\xde\x4b\x7b\x40\xe9\xb5\xa7\x8d\x52\x1f\x8d\x62\x4f\x51\xa1\x1e\x66\xad\x0a\xad\xd5\xb9\x38\x59\x05\x96\x09\xfe\x9e\xa0\xc4\x67\x39\x41\xc6\x90\xbb\xd0\x2d\x4d\x61\x81\x6b\x29\x57\x8f\xba\x16\x46\xc1\x29\xb9\x3c\xe0\x62\x7b\x8a\x63\x66\x40\x6c\x2f\x15\xe1\xf0\x95\xee\xbe\xb7\x49\xa3\xa5\x40\xf5\x6c\xa9\xe9\x40\xa2\x0f\xdd\x19\x4c\x00\xfc\x30\xa7\x90\x06\x59\xa4\x11\x0f\xd0\x08\xa2\x53\x48\x25\x55\x13\x3d\x0e\x48\xbf\xa4\x99\xe7\x9d\x91\x09\x5f\xa4\x05\x7b\xf6\x05\xd3\x2e\x09\x3e\x48\x2e\xb3\x64\x9b\x32\x6f\xef\x7c\xa9\x32\x8e\x33\xe4\x8c\x67\x1f\x76\x89\x5e\x18\xc0\xe3\x82\x42\xae\x21\x4b\x97\x37\xc8\xac\xcb\x5d\x9e\x76\x8a\x02\x37\x29\x15\x0b\xb6\xb1\x90\x27\xf9\x0d\xf1\xde\x8c\xce\xce\x34\xc1\x3f\x10\x0c\x40\xfc\x6b\x8f\xbc\x94\x60\xe2\x13\xdf\xec\xe4\x72\xa4\xc3\x90\xdd\x40\xe6\x06\x06\x78\x94\x40\xa2\x0b\x93\xc6\x6f\x56\x7a\x83\x6b\xa5\xf6\xfc\x92\x06\xbc\x88\xaf\x3f\xec\x93\x20\xdb\x40\x75\x7b\x8b\x83\x21\xbd\xae\x92\xda\xaf\x4b\xf6\x0a\xd6\x8c\x7d\x27\x75\xe4\xc4\xa4\xf6\x11\x49\xef\x9b\x25\xbf\x51\x4c\x9a\xaa\x1e\xbe\xc1\xd2\x23\x82\x5a\x6d\x02\x3a\x64\x69\xe2\xe7\x6c\x13\xbd\xd9\x40\x16\x79\x7d\xd4\x94\x1b\x4c\x95\x07\x48\x3c\xa5\xf0\x30\x43\x4c\x29\x0d\x25\x0b\x87\x0c\x4f\xde\xe4\xeb\xd2\x7c\x74\x74\x59\xbd\xd3\x59\x27\x47\x58\x67\xf3\xc9\xc4\xc3\xdf\xe4\x50\xf9\x14\xb4\xa7\x09\x4d\x8e\x0b\x75\x50\x3e\x14\x4c\x9f\x2c\xe4\xf5\x0b\x4d\x2b\xbb\x64\xbc\x08\x6e\x2e\xbb\xf0\xbf\xe2\x36\x50\x66\xf6\x08\x06\x03\xc4\x2e\x03\x51\x49\x2b\x49\x12\xc1\x11\x86\xc9\x16\x5f\xfb\xc4\xd8\x2d\x65\xcf\xf2\x1a\xc9\xab\x90\xd7\x80\xdd\x49\xfa\x9d\xa4\xdf\x49\xfa\x5d\xa5\x9c\xb6\xf1\x07\xea\xf1\x48\xe4\xdb\x21\xbb\xa3\xbe\xb4\x1d\x4a\x16\xdd\x0e\x8b\x97\x0e\x15\x2f\x1d\x53\xf1\x12\x49\x5f\xb4\x0b\xcb\x93\x0b\x98\xec\x23\x15\x0d\x63\x55\x58\xda\xec\x25\x47\x92\xa9\xe4\x85\xb4\xba\x31\x56\x68\x5a\x50\xe4\x9b\xef\x36\xa2\x56\x52\xec\x8b\x52\x24\x23\xf6\x4b\x16\xc5\xeb\xbd\xdc\x70\xce\x42\x9e\x0b\xc4\x42\xf6\xd9\x61\xc1\xb0\x2e\x3a\xf2\xeb\x55\x53\x3b\x4c\xa8\x5a\xa8\x13\x52\xad\x7c\x48\x4b\x13\x42\x0e\x5f\x59\xc9\x20\xb5\x1d\x90\xd9\xf8\x92\x59\xff\x51\x55\x1b\x17\x7c\xc9\xfe\xfc\x93\x35\x8f\x49\xf7\x31\x5d\xda\x34\xb4\x43\x33\x78\xbd\xdb\x60\x33\x8d\x23\x69\x51\x50\x93\x56\xe9\x75\xa7\x77\x30\x38\xae\x15\xac\xac\x74\xe0\xd9\xad\x01\x9c\xbd\x7e\x4d\x65\x87\x4b\x8c\xb2\x51\xb7\x0a\xaf\xeb\xb4\xd0\x09\x4c\x44\xcc\x40\x09\xc5\xa4\xd7\xc2\x69\x6d\xaf\x42\x49\x32\xd9\xf8\x1c\x50\x5d\x1a\xa6\xa0\xc9\x5b\x3d\x52\x55\xd9\x08\x2d\x71\x8a\x04\xb2\xea\xb1\x07\x0a\xc9\x42\xfa\x53\xd7\x53\xfa\x95\x4f\x2e\x90\x68\x35\x32\x2e\x2d\xca\x5d\xd2\x22\x5c\x8d\x59\x6a\x68\x3a\x07\xc7\x10\x52\x4b\xb8\xae\x02\x40\x29\x7a\x4b\xe1\xa9\xb8\xbf\x4a\xd7\x88\x49\xa9\xc2\xab\x0b\x1f\x34\x5e\xb6\xb8\xff\xf8\xab\xb8\xe5\x94\x93\xad\x82\x16\xeb\xb0\x31\x29\x32\x4f\x00\x06\xb1\x0a\x24\x45\x9b\xd1\x90\x7d\xf7\x1d\x16\x2d\xdd\x46\xf0\x9d\xfe\x59\xa9\x95\x27\x8d\xf2\x2e\x72\x2d\xf5\xc8\xfc\x54\xc3\x0e\xd9\x2b\x66\x35\xd8\xb4\xd0\x45\xcd\xfc\xb0\x3f\xd5\x9e\x53\x61\xa0\xf1\x1c\x15\x5b\xda\xb4\x57\xbd\xcf\x3e\x8b\x5c\x77\x7a\xdd\x07\xf2\x96\xb9\x03\xf7\x19\xab\x6c\x93\xc9\xca\xca\xf2\xc6\xb9\x0c\xed\x14\xd3\x52\x42\x86\x35\x4f\xa9\x1f\xd6\xe0\x6b\x00\x36\x21\xe8\x38\xfb\x01\x4c\x67\x1f\xe2\x74\x71\x7f\xbd\x74\xde\x66\x05\xfd\xae\x08\x6c\x1d\xfc\x8f\x1c\xed\xcb\xca\xf9\x2b\x26\xa7\x12\x7a\xc0\xfc\x36\x2b\x5b\x66\xed\x64\x56\x73\xf2\xcc\xaf\x0d\xa4\xd2\x13\x8e\xef\xa6\x46\xff\xa1\x93\x1f\xcb\xbd\xb1\x60\x7c\xbb\xc5\x16\xda\xa9\xdc\xf7\x54\xe9\xa7\x63\x7f\x48\x99\x30\x25\x95\x2b\xda\xca\x27\xb6\x4d\x79\x25\x16\x92\xb9\x3a\xb1\xb2\xfc\x41\x68\xd3\x9c\x20\x29\x5a\x85\x66\xa6\xb1\x25\x53\x01\x62\x1b\x07\xe3\x70\x1c\xb5\xc5\xf5\x77\xbb\x9c\x5e\x5b\x1c\x1b\x52\xed\x1f\xb4\x90\x83\xfa\xcd\x46\xb1\xdb\x6e\xb7\x59\x4e\x51\xa5\x85\xc3\x04\x59\x64\x5c\xb2\xbc\xe6\x8c\x44\xb8\xe1\xea\x49\xd6\x44\x23\xf9\x1e\x8a\x68\x80\xdc\xee\x19\xbb\xeb\x8f\xa7\x5d\x6f\x74\xfd\xa5\xd3\x56\xd6\x7c\xaa\xac\x39\xae\x6f\x7c\x37\xf2\xb1\x7b\xc6\xa5\x59\x79\x47\x95\x25\x1c\x60\x91\xc0\x0e\xa1\xde\xc1\x04\x82\x65\xa9\xe8\xe9\x1e\xfd\x29\x1f\x5f\x3e\xf6\xea\xe1\x78\x0d\x38\xd9\x6d\xca\x58\xa6\xd5\x7d\x95\x60\x0a\xd4\x1c\xf3\x7c\xa2\x69\xee\x78\xe3\xb9\x6c\x36\xd7\x7f\x95\x4b\x3e\x56\x00\xd6\x46\xf3\x50\xd1\x3a\xe7\x72\x25\x1c\x54\x73\x8c\x8a\x7c\x44\x8e\xf3\xc9\xd8\x5c\xeb\x9b\xcb\x40\xf2\x68\x2b\xc2\x35\x70\x98\xdb\xc7\x33\xc5\x30\xef\x51\xe0\xd5\x0c\x5e\x0f\x83\xc1\xb3\x1f\x8e\xf6\xf7\xd6\x2b\x69\x75\x1f\x79\x51\xe4\x4d\xa8\xba\x3b\xc3\x78\x56\x7e\x6f\x35\xb8\x61\x9a\x99\xfd\x08\x2d\x70\x63\xba\x9a\x93\xee\xba\xf9\xc5\xf1\x0e\x30\x76\x67\x36\x79\xc4\x0a\x6f\x6c\xc1\x54\xbb\x62\x7c\xb6\x42\xbf\xef\xd4\x95\x6e\xfc\x3a\xda\x8a\xd4\xd7\xa3\x3f\xc4\x6a\x7c\xf1\x7c\x4b\x59\xb7\xa0\xe6\xec\x14\xdb\x7b\xb5\xb0\xf1\x98\xfd\x8c\x34\xcc\x84\x41\xbb\x1a\xfb\xab\xc0\x5a\xc7\x73\xea\x11\xab\xaf\x17\x77\xae\xde\x22\xf2\xa3\x2f\xeb\x78\xfd\xe6\x90\x9f\x62\x92\xa1\x70\xac\x4f\x34\xa9\x7a\x89\x15\xf0\xb2\xdf\x17\xd4\x1b\x3b\x6f\xdc\x6f\x95\xa7\xbc\x85\x9f\x64\x91\xf2\x1b\x6c\x35\x70\x96\x2f\x22\xcf\x8c\xfb\xc2\xf1\x93\x4a\xeb\xa1\x7b\x22\xaa\x32\xbf\x0a\x42\xcc\xa5\xf8\x93\x4e\x34\x30\xb9\x15\xd3\xb8\x8f\x29\xa1\x37\x04\x89\x63\xae\x49\xc2\x99\x92\x71\x7f\x13\xd4\x26\x3d\xef\x37\xd4\xb6\xaa\xa2\x28\x7f\xd8\x7a\x23\xad\x8e\xe5\x90\xe3\xd8\x40\x74\x44\xdf\x36\x38\xfe\x4a\xde\x75\xe1\x78\x9b\xa5\xd5\x5b\x19\x82\x57\xdc\x63\x27\xa6\x83\x95\x02\x94\x26\x05\x2b\xe8\xb0\xca\xc5\xe1\x12\x6d\x2c\xc8\x77\x88\x6a\x7e\xe1\x65\x78\xf7\xdb\xe2\xc3\x3f\x73\x6c\x2a\xce\xfb\x78\xe9\x8c\x60\xf9\x35\x7d\x67\xd0\xd9\xf3\xb5\x72\x3b\xc5\xb8\x30\x69\x6a\xab\x17\xf1\xb0\xd4\xf5\x2b\x0a\x19\xeb\xca\x1b\x59\x37\xec\xd9\x8e\x3d\x5f\x8e\xce\xf3\x15\xbf\x5f\x09\xd2\xaf\x51\xe2\x6a\x6c\xcd\x98\xb4\x70\xba\xa4\x1a\xfa\x64\x70\x45\xc2\x35\x49\x93\x41\xc6\x49\x7a\x9d\xaa\x05\x11\xa4\x7c\x9c\x2a\x08\xe9\x91\x3c\x4b\x7b\xc6\x26\x85\x66\xfb\x21\xb1\x22\xf5\xd1\x89\x04\x1c\x64\x07\x33\x7a\x76\xeb\x0e\x74\x5b\x99\xf9\x50\xed\x0e\x47\x37\xd8\xbc\x0d\x5a\x1d\x00\x24\x02\xee\xd5\x78\x66\x43\xf4\xb8\x9c\x77\x20\xa7\x9c\xce\x95\x33\x50\x4b\xf6\x88\xce\xcd\xa2\xf3\x47\x45\xad\xe9\x80\x6c\xab\x2d\xab\x25\xbd\x01\xf5\xca\xae\x1e\x11\xbe\x6a\xfa\xa4\x43\x5b\x89\x4e\x4f\x10\x94\x18\xf9\x06\x83\xfd\xbf\x20\xec\x8f\xdd\x13\x4c\x9e\x0e\xac\x39\xbb\xb2\x8d\x63\x9e\x9f\xd0\xbb\xde\x37\xed\x44\xca\xc3\xbd\xf1\x0b\xe7\xca\xae\x9d\x8f\x12\x3c\xd7\xaf\x57\x07\xc5\x94\xff\x93\x66\x9f\xd3\x77\x3c\xde\xec\x72\x73\x05\xd0\xf5\xd5\x92\x54\xcb\xb3\x59\x68\x3d\x07\x2d\x78\x07\x5c\xe3\xe5\x4d\x5f\xb2\x4c\xf4\x5e\xc5\xc4\x7a\xa1\xa8\x22\xf5\x14\xb4\xb5\x20\xba\xaf\xa8\xdd\x55\xd0\x53\xd8\xd6\xf5\x9c\x5c\xdc\x36\x69\xfe\x4b\xca\xbb\x45\x6e\xfd\x1b\x33\xa5\xe1\x89\xb5\xdc\x4a\xea\x29\xf5\x5c\xcf\x9f\x48\x4d\x72\x5c\x55\x05\x91\xa2\xfc\x9e\xca\xe1\x7a\xe1\x51\x19\x64\xbd\xf0\xd5\xcf\x54\xfd\xcc\xd4\xcf\x7c\xd9\xea\x5a\x2f\xe8\xac\x79\x44\xdd\xfc\xe2\x85\xd6\x3b\x1d\x88\x24\x30\xeb\xab\xad\xce\x66\xba\xb1\x6d\xb1\xd4\x6b\x8b\xa5\x9e\x2a\x96\x6a\x2e\xf6\x26\xe8\xd4\x21\xf1\x28\xe7\x0f\x53\x86\x4c\x37\xa4\xc0\xb3\xaa\x41\xf2\xa0\xc8\x36\x40\x9f\xd1\x5c\x09\xcd\xa7\x68\x6a\x20\xc5\xdb\xcf\x06\x29\xd1\xbf\xc2\x08\xff\x73\x32\x74\x39\x0e\x55\xc5\x50\x17\x7b\x54\x73\x53\xf9\xa1\xa6\x83\x72\x90\x81\xc3\xe5\xaa\xea\x22\x7b\x5a\x76\x9c\x01\x24\xe9\x08\x47\x4a\x06\x9a\x5b\x74\xbc\xa4\x71\x0d\xe8\x78\x8a\x5b\x20\xab\x92\x46\xcd\x7b\xe6\x4d\x35\x77\x5b\x9b\x64\xf7\x4d\x07\x48\xb9\x3a\x77\x69\xb1\x15\x21\xc2\x2c\xac\x80\x38\xdd\xee\x4a\x0a\xb4\x90\x91\x22\xe5\xdd\x88\x75\x89\xf6\x66\x85\xf4\xe4\xbf\x0a\x97\x61\x85\x8f\xb1\xdf\xff\xda\x95\xac\xc8\x12\x51\xca\x14\xf4\xe0\x53\x00\xcc\x36\x42\x1a\xe4\x1a\xf9\x91\x0e\x64\x51\x67\x59\xf5\xe2\x56\x4f\xbd\xf9\xf6\x61\xc8\xa3\x10\x1b\x61\x69\xfc\xc0\xcc\x29\xe5\x44\x31\x4d\xcc\xa8\x52\xd3\xfd\xaa\x1e\xa4\x4b\xb7\x47\xf8\xaa\x2f\xc1\x5a\xee\x9a\xa0\x3b\xff\x7f\xc7\x9f\x90\x53\xe8\xfe\xaf\x28\xb4\xd4\x83\xa5\x56\x84\xbf\x41\x82\x2a\x3d\xbd\x6e\xbf\x1e\x06\xca\x21\xd1\xd0\xf1\x46\xc5\x70\xb2\x43\x36\x1e\xa8\xe4\x9e\xf8\x91\x6b\x65\x8d\x07\xe0\xe6\x9d\x81\x5d\xa5\x61\x2e\x68\xda\xf5\xb1\x35\x44\x78\xc8\x0d\x55\x76\x8a\x6a\xfb\xe6\x78\x4a\xa3\xce\x1e\x9d\xe5\xf1\x6d\x4c\x69\xb7\x74\x52\x1a\xb9\x26\xad\x46\x4e\x55\x56\xf9\x0d\x8f\x77\x29\xbf\x16\xf2\xba\xef\xda\x1a\xfe\x66\x97\x7e\x17\xe7\x45\x79\xc2\x62\x6c\x24\x9f\x82\x06\x32\xd6\x32\xab\x5e\x5c\xbc\x66\xe6\xec\x5d\xe3\x19\x0c\xcc\xe9\x7f\xcb\xd1\xf1\x13\x61\x80\xb3\x21\x4a\x38\x8b\x5d\x50\x52\x61\x86\x30\x5d\xe7\x59\x72\x22\xaa\x9a\x92\x0e\xaa\xae\x42\x75\x70\x88\x6a\xc3\xff\x64\x54\x1b\xc9\xbf\x11\x55\xd7\x35\x57\x4d\xcc\xa8\xbe\xcf\x85\xd1\x4f\x75\xfa\x09\xae\x9a\x8a\xcf\x2d\x9e\x5d\xd9\x43\x47\xb5\x0f\xa2\x08\xf1\xed\x4e\xaa\x0b\x3f\x37\xa2\xf0\xc2\xc1\xa0\x41\xec\x09\x7e\x0a\xa3\x8c\xae\xaa\xd3\x4f\xf7\xd6\x43\x60\x8f\xf8\xea\x03\x60\xbf\xdd\x4f\x75\xe1\xe7\x06\x16\x8e\xe8\xba\x47\x81\xed\x71\xd5\x37\x51\xf4\x31\xeb\xc4\x49\x44\xa8\x8f\x09\xe9\x9f\x37\xc1\xcd\x49\x1e\x5a\x49\xca\xf7\x94\x5d\xf7\x0c\xba\x28\x4a\xc6\x5e\xf8\xda\xd0\x85\xd8\x9e\x1b\xa8\xb9\xc6\x33\x78\xcd\x7a\x2a\xc4\x66\xac\x3e\x54\xbe\xf5\x0e\x7e\xd5\xfd\x0c\xa7\xa5\xd7\xc8\xb5\x7e\x48\xf0\x9d\xe6\x89\x5d\x3d\x0f\x70\x74\x0f\x71\xd4\xf9\x1f\x87\x53\xe7\x7e\x6e\x54\x3d\x8d\xc7\xed\x43\xd5\x33\xa2\xfa\xaf\x00\x00\x00\xff\xff\x4c\x95\x8f\x78\xed\x34\x00\x00") func resourcesArithmeticMBytes() ([]byte, error) { return bindataRead( @@ -141,12 +141,12 @@ func resourcesArithmeticM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/arithmetic.m", size: 13515, mode: os.FileMode(420), modTime: time.Unix(1524352562, 0)} + info := bindataFileInfo{name: "resources/arithmetic.m", size: 13549, mode: os.FileMode(420), modTime: time.Unix(1541059048, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _resourcesAtomsM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xac\x58\x5f\x73\x9b\x38\x10\x7f\xcf\xa7\xd8\xc9\x53\x12\x43\x0c\xfe\x93\xc4\xc9\xe4\x6e\x6e\x6e\xda\x69\x1e\x6e\xda\xb4\xbd\xb9\x07\x86\x3a\x32\xc8\xb1\xe6\x00\xf9\x84\x70\xec\xf6\xfa\xdd\x6f\x25\x40\x06\x1b\xb0\xd3\x9e\x1f\x02\x5d\x69\x7f\xbb\xab\xfd\x69\xd9\xed\x47\x22\x19\x4f\x48\x74\x7b\x9b\xa5\xe4\x99\xc2\x3d\x9c\x3e\x95\xb2\x27\x60\x29\xc8\x05\x85\x05\x25\x21\xcc\xb9\xd0\xff\x20\x92\xc7\x2c\x00\x51\x6c\x02\xb9\x59\xd2\xcb\xd3\xbb\x93\xdf\xa4\x14\x6c\x96\x49\x9a\x7a\x25\x80\x8f\x70\xdf\x3e\x08\x2e\x69\x20\x69\xf8\xfd\xee\xe4\x33\x4d\x65\x6a\xf0\xd5\xea\x09\xe0\xef\xcd\x27\x16\x2f\x23\xfa\x66\x4d\xd4\x23\xf5\xb4\x50\x2f\xfc\xce\xe3\x98\x26\xd2\x3b\x2d\x75\x52\x20\x82\x42\x20\x28\x41\x44\x98\x0b\x1e\xc3\xd3\x67\x16\xd3\xf4\x09\x5e\x16\x34\x01\xb2\x75\x0c\x1d\x8e\x55\x04\x34\x09\x78\x96\x48\x2a\x68\x78\x7b\xea\x5b\x5b\xf0\x4f\x24\xa6\xca\x23\xe3\xaf\x05\x1a\xca\x1b\x5b\x70\xf5\xc5\x76\x7d\xe8\xf7\xe1\x1d\xc6\x5e\x55\x32\x1e\xfd\xb5\x60\xc1\x42\xe3\xff\x93\xb1\x15\x89\x50\x08\x92\xab\xe3\x60\xc9\xb3\x3a\x29\x34\x9e\x40\xc8\x04\x06\x1f\x6d\x0e\x5a\x1e\xf7\xaf\x3a\xcd\xbd\x17\x30\xa3\x0a\x99\xae\x30\xcc\x98\xe3\x29\xd0\xf5\x32\x62\x01\x93\x07\xb1\xcb\x37\x1d\x58\x77\x54\xdb\x73\x4e\x55\x4e\xd8\x7c\x03\x3c\x41\x9b\x24\xca\xf4\x4a\x8b\xad\x71\x7f\x58\x31\xe3\x3a\xca\x4e\xc7\xa9\xc5\xec\x79\x21\xf1\x78\x82\x28\x0b\xa9\x41\x57\xc7\xc6\x81\x24\xf0\x80\xd9\x7a\xa6\xa2\xc5\x56\xb1\x5a\xb1\x67\xbb\x0e\x5a\x74\x9d\x63\x43\xe3\x73\x48\x78\x62\x17\x40\x9a\xc1\x39\xaf\x12\x2e\x81\x44\x11\x7f\xd9\xa3\x0a\x72\x3b\x79\xd6\xe6\x0d\x8e\x87\x36\x13\xff\xd4\x82\x5d\x89\xaf\xf5\x7c\x0b\xde\xbc\xcd\x04\x12\x41\x74\x11\xfb\xcf\x24\xa4\x73\x96\x20\x99\x45\x8d\xe2\x0b\x92\x84\x11\x4a\x49\x10\x70\x11\xa2\xf1\x3d\x0e\x55\x5c\x7a\x40\x10\x24\x78\xcc\x12\xbc\x16\xbb\x1e\x39\x7e\xab\x1e\x7a\x81\x7e\xad\x1f\x12\xf4\x80\xc9\x4d\x4d\xd3\xdd\xd3\xdc\x3b\x49\x48\xb2\x78\x46\x45\x8a\xce\xae\x28\xa4\x3c\xc6\x3f\x4b\x1a\x30\x5c\xd1\xee\xab\x8c\xaa\xb2\xb1\x24\x12\xbd\x43\xd6\x12\x19\x2c\x50\xd8\x92\xd8\x81\x22\x11\xd6\x0f\x89\x85\xc1\xb8\x31\xb0\x60\xe8\x37\x6e\xff\x2c\x32\x6a\xc1\x1f\x0a\xf3\xd1\x53\x6a\x16\x20\xc2\xd1\x7b\x8d\x05\x32\x35\x8c\x9a\x95\xaf\x7e\x33\xcc\x37\xe5\xcd\x77\x6d\x07\xfa\x97\x07\x20\xc0\xfe\x05\xbe\x11\x94\x7c\x6f\x8f\xb6\x00\x32\xfa\x7d\xa3\x5e\xd1\x36\x74\xd2\xe5\xd3\x6b\xc0\x72\x9d\xfe\xf5\xce\xfd\xbb\xf6\x0f\xf2\x77\xad\xef\x4c\x2d\xe9\x85\xa8\x4d\xd5\x75\xea\x14\x29\xae\x5d\x73\x3a\x6d\xe5\xc6\xfe\x1d\x3d\x12\x3b\xdf\x6f\xb7\xa3\xd7\x4b\x8e\xbd\x5f\x73\x5a\x8a\x93\xde\x69\x5f\xb5\xfa\xe1\xec\xde\x9f\x71\xfb\x79\x1c\x2e\x05\x3f\x70\xf1\xec\xfd\x9b\xf7\x1a\x55\xbb\x43\xb7\xbd\x4e\xd8\xce\xcf\x68\xb6\x25\x69\x96\x7d\xfd\xea\xcd\x88\x40\xf2\xce\x39\x57\x6f\x48\x81\xfe\xc0\x57\x9c\xcf\x05\x29\x9d\x16\x22\xe4\x7b\xb1\x3d\xa5\xcd\x79\x3c\x12\xad\x5a\xc1\x06\xfe\x8f\x02\xef\xa2\xfc\x6f\x1e\x77\x03\xbf\xde\xf9\x5a\x69\x43\xbf\xf6\x30\x0e\x6b\xd5\x15\xf2\xe8\x1a\xb5\xde\xe2\xd7\x09\xd5\xde\xf1\x28\xf4\x76\x3d\xbd\xbf\xbf\xcf\x17\xb4\x76\x5e\xb3\x4e\xb0\xe7\x3b\x29\x08\x5b\xed\x30\x0b\xd1\xeb\x1a\xcc\x33\x02\xb7\x70\x56\xd6\xc7\x7f\xa7\x1f\x29\x89\xf0\x6f\xb1\xed\xfc\x1c\x2e\xa0\xc0\xf5\xb0\x3d\x8c\xf0\x30\x59\x3c\xf5\x51\x2a\xd0\xf5\xe9\x74\x0a\xb7\xf7\x66\x03\xd1\x62\xd5\x1b\xa9\x37\x16\x97\xdb\x8e\xb0\xd2\x6b\xb4\xd2\x6b\xb6\xd2\x2b\xac\x28\x0b\xbd\xc2\x42\xb9\xba\x9e\x5a\x1b\xad\x59\x0a\xb2\xa9\xb5\x6a\x83\x5a\xf7\x32\x6b\xd3\x5b\xb5\xa2\x5c\xec\xa2\x34\x86\xbd\xbe\xc8\xec\xcd\xc5\xca\x5a\x5f\xac\x7a\x9b\x8b\x6c\x1b\x75\xa5\x79\x2f\xf6\xb6\xf4\xee\xc5\xea\x11\xad\xbb\x21\x4d\x69\xdc\x76\xaf\x90\x29\x37\xc8\xaf\xb3\x11\x86\x71\xf3\x70\x7e\x36\xc0\xe7\xf0\xe1\xbc\xca\x96\xbc\xe8\x54\xc9\x92\x4b\x3a\xb9\x92\xea\x2d\x4d\xa3\x48\xae\xdc\x12\x4c\xbe\xf8\x9a\x58\x4e\xdf\x51\x6c\x0f\x55\xfd\xcb\x5f\x3a\xee\x56\xb1\x03\xef\x45\xe7\xe6\xe2\x4a\xed\xed\x86\x17\x2e\xa2\xb0\x59\x27\xf7\xdb\xd2\xad\x6e\xe9\x52\xed\xca\x29\xd2\xd6\x26\x3a\x7a\x60\x9a\x9b\x47\x3c\x6f\xc0\x97\x9c\xa9\x39\xa6\x61\xa6\xa3\xed\xf3\x1c\x3d\x6a\x96\xdb\x0e\x26\xfa\x4a\x68\xe7\xdd\xcb\xf1\xb0\x79\x50\x78\x9f\xe0\x98\x87\xb3\x00\x3a\x1a\x50\xd0\x26\x98\x1a\xe2\x96\x38\xc7\x49\x7d\x1b\xd5\x60\xb2\x1d\x16\x60\xb6\x01\xb2\x5c\xd2\x44\xf5\xca\x78\xab\x43\xec\x43\x63\x54\xd2\x01\xb5\x4d\x48\x55\x47\x9a\xdd\xd0\x86\xcb\x36\x57\xf5\xe5\x33\x12\xfc\x8d\x6d\xb9\xb2\x26\x66\x4c\x0a\x22\x36\xf6\x12\x67\x3c\x96\x2a\x97\xea\xe7\x98\xb6\x77\xec\xae\x73\xa9\x58\x84\x8f\x2f\x63\xc7\x71\xa0\x0f\xea\x75\x34\x99\x4c\x8e\x1a\x1f\x5a\xaa\x3f\x9e\xa6\x05\xba\x64\xd5\xe8\x50\xce\x53\x15\x46\x14\xa2\x4e\x52\xb0\xca\x7c\xb4\xc3\x06\xd3\xe3\x36\x12\xa2\x4c\xc9\x2b\x38\x61\xfa\xe7\x3c\x1b\x6d\xac\x28\x91\x8f\xcf\x48\x48\x24\x51\xf5\x21\x0b\x64\x86\xb5\xae\x85\x09\x37\xee\x78\xe2\x8e\x07\x37\xc3\xc1\xe8\xfa\x66\x72\x7d\x3d\x1c\x0d\x47\xe3\x2b\xd7\x1d\x5c\x4d\xc6\x13\x7c\x8e\x6f\x26\xa3\xc1\xf5\xc0\x29\x7f\x16\xbc\x25\x81\xe4\x02\x47\x1d\x6f\xe4\xf8\x3f\x91\x32\x9d\x31\x33\x75\xec\x27\xed\xb1\x21\x6b\x8f\x1e\xf5\x9f\xb0\x72\x63\x44\x49\x0a\x0a\x0f\xd8\x1c\x9e\xa8\xce\xe6\xf6\x4a\x28\x27\xb1\xb8\x00\x57\x1e\xbd\xb0\x54\x27\x71\x0b\x81\x1f\x09\xfc\x34\xe8\xf3\xa6\xf9\xe7\xbb\x58\x6b\xca\xf4\x63\x77\xaa\x1f\x5f\x93\xeb\xa2\xe4\x19\x4f\x48\x57\x8b\x62\x76\xb9\x9d\x2d\x89\xd9\x36\xb8\xac\x9f\x62\x8c\x5f\x48\xc3\x56\x15\xb0\x73\x97\x0b\xf3\x82\xa6\x7e\x55\xa1\xf9\x9f\x2b\x23\x34\xb3\x19\x7e\x2c\x0d\xd4\xaf\x1f\x78\xca\x24\x5b\xd1\x2f\x9b\x26\x9d\xf2\x93\x37\xb5\x54\x73\xa0\x17\x58\xac\xeb\xf2\xae\x37\xeb\xbb\x5c\x58\xf3\xc6\x08\xab\xc8\xb9\x70\xdb\x7b\x4c\xad\x02\x59\xd0\xbb\x93\xff\x02\x00\x00\xff\xff\x09\x28\x52\xb9\xc7\x13\x00\x00") +var _resourcesAtomsM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xac\x58\x5f\x73\x9b\x38\x10\x7f\xcf\xa7\xd8\xc9\x53\x12\x43\x0c\xfe\x93\xc4\xc9\xe4\x6e\x6e\x6e\xda\x69\x1e\x6e\xda\xb4\xbd\xb9\x07\x0f\x75\x64\x90\x63\xcd\x01\xf2\x09\xe1\xd8\xcd\xe5\xbb\xdf\x4a\x80\x0c\x36\x60\xbb\x3d\x3f\x04\xba\xd2\xfe\x76\x57\xfb\xd3\xb2\xdb\xcf\x44\x32\x1e\x93\xf0\xf6\x36\x4d\xc8\x33\x85\x7b\x38\x7d\x2a\x64\x4f\xc0\x12\x90\x73\x0a\x73\x4a\x02\x98\x71\xa1\xff\x41\x24\x8f\x98\x0f\x22\xdf\x04\x72\xbd\xa0\x97\xa7\x77\x27\xbf\x49\x29\xd8\x34\x95\x34\x19\x17\x00\x1e\xc2\xbd\x7e\x12\x5c\x52\x5f\xd2\xe0\xed\xee\xe4\x2b\x4d\x64\x62\xf0\xd5\xea\x09\xe0\xef\xdd\x17\x16\x2d\x42\xfa\x6e\x45\xd4\x23\x19\x6b\xa1\x5e\xf8\x9d\x47\x11\x8d\xe5\xf8\xb4\xd0\x49\x80\x08\x0a\xbe\xa0\x04\x11\x61\x26\x78\x04\x4f\x5f\x59\x44\x93\x27\x78\x99\xd3\x18\xc8\xc6\x31\x74\x38\x52\x11\xd0\xd8\xe7\x69\x2c\xa9\xa0\xc1\xed\xa9\x67\x6d\xc0\xbf\x90\x88\x2a\x8f\x8c\xbf\x16\x68\xa8\xf1\xd0\x82\xab\x6f\xb6\xeb\x41\xb7\x0b\x1f\x30\xf6\xb2\x92\xf1\xe8\xaf\x39\xf3\xe7\x1a\xff\x9f\x94\x2d\x49\x88\x42\x90\x5c\x1d\x07\x8b\x9f\xd5\x49\xa1\xf1\x18\x02\x26\x30\xf8\x70\xbd\xd7\xf2\xb0\x7b\xd5\x6a\xee\xa3\x80\x29\x55\xc8\x74\x89\x61\x46\x1c\x4f\x81\xae\x16\x21\xf3\x99\xdc\x8b\x5d\xbc\xe9\xc0\xda\xa3\xda\x9c\x73\xa2\x72\xc2\x66\x6b\xe0\x31\xda\x24\x61\xaa\x57\x1a\x6c\x0d\xbb\xfd\x92\x19\xd7\x51\x76\x5a\x4e\x2d\x62\xcf\x73\x89\xc7\xe3\x87\x69\x40\x0d\xba\x3a\x36\x0e\x24\x86\x07\xcc\xd6\x33\x15\x0d\xb6\xf2\xd5\x92\x3d\xdb\x75\xd0\xa2\xeb\x1c\x1a\x1a\x9f\x41\xcc\x63\x3b\x07\xd2\x0c\xce\x78\x15\x73\x09\x24\x0c\xf9\xcb\x0e\x55\x90\xdb\xf1\xb3\x36\x6f\x70\xc6\x68\x33\xf6\x4e\x2d\xd8\x96\x78\x5a\xcf\xb3\xe0\xdd\xfb\x54\x20\x11\x44\x1b\xb1\xff\x8c\x03\x3a\x63\x31\x92\x59\x54\x28\x3e\x27\x71\x10\xa2\x94\xf8\x3e\x17\x01\x1a\xdf\xe1\x50\xc9\xa5\x07\x04\x41\x82\x47\x2c\xc6\x6b\xb1\xed\x91\xe3\x35\xea\xa1\x17\xe8\xd7\xea\x21\x46\x0f\x98\x5c\x57\x34\xdd\x1d\xcd\x9d\x93\x84\x38\x8d\xa6\x54\x24\xe8\xec\x92\x42\xc2\x23\xfc\xb3\xa0\x3e\xc3\x15\xed\xbe\xca\xa8\x2a\x1b\x0b\x22\xd1\x3b\x64\x2d\x91\xfe\x1c\x85\x0d\x89\xed\x29\x12\x61\xfd\x90\x58\x18\x8c\x1b\x3d\x0b\xfa\x5e\xed\xf6\xaf\x22\xa5\x16\xfc\xa1\x30\x1f\xc7\x4a\xcd\x02\x44\x38\x78\xaf\xb1\x40\x26\x86\x51\xd3\xe2\xd5\xab\x87\x79\x55\xde\xbc\x69\x3b\xd0\xbd\xdc\x03\x01\xf6\x2f\xf0\x4a\x50\xf2\xd6\x1c\x6d\x0e\x64\xf4\xbb\x46\xbd\xa4\x6d\xe8\xa4\xcb\xe7\xb8\x06\xcb\x75\xba\xd7\x5b\xf7\xef\xda\xdb\xcb\xdf\x95\xbe\x33\x95\xa4\xe7\xa2\x26\x55\xd7\xa9\x52\x24\xbf\x76\xf5\xe9\xb4\x95\x1b\xbb\x77\xf4\x40\xec\x6c\xbf\xdd\x8c\x5e\x2d\x39\xf6\x6e\xcd\x69\x28\x4e\x7a\xa7\x7d\xd5\xe8\x87\xb3\x7d\x7f\x86\xcd\xe7\xb1\xbf\x14\xfc\xc0\xc5\xb3\x77\x6f\xde\x31\xaa\x76\x8b\x6e\x73\x9d\xb0\x9d\x9f\xd1\x6c\x4a\xd2\x34\xfd\xfe\x7d\x3c\x25\x02\xc9\x3b\xe3\x5c\xbd\x21\x05\xba\x3d\x4f\x71\x3e\x13\x24\x74\x92\x8b\x90\xef\xf9\xf6\x84\xd6\xe7\xf1\x40\xb4\x72\x05\xeb\x79\x3f\x0a\xbc\x8d\xf2\xbf\x79\xdc\x0e\x7c\xbc\xf3\x95\xd2\x86\x7e\xed\x60\xec\xd7\xaa\x2a\x64\xd1\xd5\x6a\xbd\xc7\xaf\x13\xaa\x7d\xe0\x61\x30\xde\xf6\xf4\xfe\xfe\x3e\x5b\xd0\xda\x59\xcd\x3a\xc1\x9e\xef\x24\x27\x6c\xb9\xc3\xcc\x45\xc7\x35\x98\x67\x04\x6e\xe1\xac\xa8\x8f\xff\x4e\x3e\x53\x12\xe2\xdf\x7c\xdb\xf9\x39\x5c\x40\x8e\x3b\xc6\xf6\x30\xc4\xc3\x64\xd1\xc4\x43\xa9\x40\xd7\x27\x93\x09\xdc\xde\x9b\x0d\x44\x8b\x55\x6f\xa4\xde\x58\x54\x6c\x3b\xc0\x4a\xa7\xd6\x4a\xa7\xde\x4a\x27\xb7\xa2\x2c\x74\x72\x0b\xc5\xea\x6a\x62\xad\xb5\x66\x21\x48\x27\xd6\xb2\x09\x6a\xd5\x49\xad\x75\x67\xd9\x88\x72\xb1\x8d\x52\x1b\xf6\xea\x22\xb5\xd7\x17\x4b\x6b\x75\xb1\xec\xac\x2f\xd2\x4d\xd4\xa5\xe6\x3d\xdf\xdb\xd0\xbb\xe7\xab\x07\xb4\xee\x86\x34\x85\x71\xdb\xbd\x42\xa6\xdc\x20\xbf\xce\x06\x18\xc6\xcd\xc3\xf9\x59\x0f\x9f\xfd\x87\xf3\x32\x5b\xb2\xa2\x53\x26\x4b\x26\x69\xe5\x4a\xa2\xb7\xd4\x8d\x22\x99\x72\x43\x30\xd9\xe2\x31\xb1\x9c\x7e\xa0\xd8\x1e\xaa\xfa\x97\xbd\xb4\xdc\xad\x7c\x07\xde\x8b\xd6\xcd\xf9\x95\xda\xd9\x0d\x2f\x5c\x84\x41\xbd\x4e\xe6\xb7\xa5\x5b\xdd\xc2\xa5\xca\x95\x53\xa4\xad\x4c\x74\x74\xcf\x34\x37\x0b\x79\xd6\x80\x2f\x38\x53\x73\x4c\xcd\x4c\x47\x9b\xe7\x39\x7a\xd0\x2c\xb7\x19\x4c\xf4\x95\xd0\xce\xbb\x97\xc3\x7e\xfd\xa0\xf0\x31\xc6\x31\x0f\x67\x01\x74\xd4\xa7\xa0\x4d\x30\x35\xc4\x2d\x70\x8e\x93\xfa\x36\xaa\xc1\x64\x33\x2c\xc0\x74\x0d\x64\xb1\xa0\xb1\xea\x95\xf1\x56\x07\xd8\x87\x46\xa8\xa4\x03\x6a\x9a\x90\xca\x8e\xd4\xbb\xa1\x0d\x17\x6d\xae\xea\xcb\xa7\xc4\xff\x1b\xdb\x72\x65\x4d\x4c\x99\x14\x44\xac\xed\x05\xce\x78\x2c\x51\x2e\x55\xcf\x31\x69\xee\xd8\x5d\xe7\x52\xb1\x08\x1f\xdf\x86\x8e\xe3\x40\x17\xd4\xeb\x60\x34\x1a\x1d\x34\x3e\x34\x54\x7f\x3c\x4d\x0b\x74\xc9\xaa\xd0\xa1\x98\xa7\x4a\x8c\xc8\x45\xad\xa4\x60\xa5\xf9\x68\x8b\x0d\xa6\xc7\xad\x25\x44\x91\x92\x23\x38\x61\xfa\xe7\x2c\x1b\x4d\xac\x28\x90\x0f\xcf\x48\x40\x24\x51\xf5\x21\xf5\x65\x8a\xb5\xae\x81\x09\x37\xee\x70\xe4\x0e\x7b\x37\xfd\xde\xe0\xfa\x66\x74\x7d\xdd\x1f\xf4\x07\xc3\x2b\xd7\xed\x5d\x8d\x86\x23\x7c\x0e\x6f\x46\x83\xde\x75\xcf\x29\x7e\x16\xbc\x27\xbe\xe4\x02\x47\x9d\xf1\xc0\xf1\x7e\x22\x65\x3a\x63\x66\xea\xd8\x4d\xda\x63\x4d\xd6\x1e\xc7\xd4\x7b\xc2\xca\x8d\x11\xc5\x09\x28\x3c\x60\x33\x78\xa2\x3a\x9b\x9b\x2b\xa1\x9c\xc4\xe2\x02\x5c\x79\xf4\xc2\x12\x9d\xc4\x0d\x04\x7e\x24\xf0\xd3\xa0\xcf\x9b\x66\x9f\xef\x7c\xad\x2e\xd3\x8f\xed\xa9\x7e\x3c\x26\xd7\x79\xc9\x33\x9e\x90\xb6\x16\xc5\xec\x72\x5b\x5b\x12\xb3\xad\x77\x59\x3d\xc5\x08\xbf\x90\x86\xad\x2a\x60\xe7\x2e\x13\x66\x05\x4d\xfd\xca\x42\xf3\x3f\x57\x46\x68\x66\x33\xfc\x58\x1a\xa8\x5f\x3f\xf1\x84\x49\xb6\xa4\xdf\xd6\x75\x3a\xc5\x27\x6f\x62\xa9\xe6\x40\x2f\xb0\x48\xd7\xe5\x6d\x6f\x56\x77\x99\xb0\xe2\x8d\x11\x96\x91\x33\xe1\xa6\xf7\x98\x58\x39\xb2\xa0\x1a\x59\xfb\xaf\x05\xaf\x4a\x19\xc9\xa8\x24\x1e\x1e\xc2\x7f\x01\x00\x00\xff\xff\x91\xba\x8e\x52\xe4\x13\x00\x00") func resourcesAtomsMBytes() ([]byte, error) { return bindataRead( @@ -161,7 +161,7 @@ func resourcesAtomsM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/atoms.m", size: 5063, mode: os.FileMode(420), modTime: time.Unix(1524352562, 0)} + info := bindataFileInfo{name: "resources/atoms.m", size: 5092, mode: os.FileMode(420), modTime: time.Unix(1541057403, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -446,7 +446,7 @@ func resourcesPatternM() (*asset, error) { return a, nil } -var _resourcesPlotM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x6c\x54\x61\x6f\xe2\x38\x10\xfd\xce\xaf\x18\xf5\xa4\x53\x2b\x65\x29\x74\xaf\xbb\x12\xa8\x27\xb1\xdb\x83\xeb\x09\x16\x04\x7c\xb3\x72\x8b\x49\x1c\xb0\xd6\x38\x51\xe2\x20\xb8\x28\xff\xfd\x66\x9c\x84\x24\xc0\x87\x52\xec\x99\x37\xef\xcd\x9b\x31\x23\x63\x62\xb9\x4d\x8d\x48\xd8\x5f\xa7\x28\x16\x7e\xea\x89\x85\x0a\xcd\x22\x94\xda\x24\x2e\xbc\x41\xf6\x77\xa8\xfc\x91\x52\xf9\xb0\x73\x27\x83\x05\xfa\xa7\x03\x31\xd7\x3b\xf1\x73\x2a\x13\xe3\xc2\xe0\x0d\x3a\x00\xb3\xd0\x4f\x95\x60\x99\x2e\xd2\x1c\x48\x8c\x88\x56\xf2\x3f\x81\xc9\x22\x52\xdc\x13\xfe\x58\x3b\x90\xea\x40\x2a\x23\xb0\x6a\x91\x97\x3b\x88\x85\x12\x84\xe4\xaf\xbd\xde\x90\x6e\x2a\x34\x5e\x3d\x5a\x32\xc6\x3e\xbb\x2e\x7c\x82\xf2\xf0\xe2\xba\x4f\xcf\x15\xec\xf9\x19\x7e\x58\x54\xcd\x84\xb8\x40\xc3\x73\xb7\xca\xef\x13\xf8\x4f\x38\xf2\x78\x1e\x7c\x20\x3f\x37\x32\xd4\x16\x73\xad\x08\x6c\x3b\x00\x6b\xbe\xa5\x7e\xda\x88\x66\x33\x96\x36\x77\xe0\x26\xc5\xc2\xa1\xa1\xd4\x81\xba\x85\xda\x98\xdc\xb5\xfc\x2b\xa1\x84\x67\xd8\xb5\x0c\x07\x1e\x3f\x0e\xec\x37\x8b\xc7\xa9\xbc\x41\xef\x09\x7e\x77\x09\x80\xb0\x0e\xcd\x63\x30\x48\x13\xbe\x23\x87\x1e\x36\x74\xc6\xc9\x14\x62\x1c\x38\x48\xfc\x7a\xe0\xa7\xdc\xdd\x40\x84\xa1\x04\x36\x81\xde\x40\x78\x14\x31\x98\xbd\x28\xe4\x40\x12\x09\x4f\x06\x52\xf8\xdd\x87\x61\xa7\xb1\x17\x54\xac\xb9\x08\x0e\x2c\xe2\xd0\xa0\x48\xe1\x3b\xb0\x14\xdc\xbf\x1c\xf3\x4e\x49\x7c\xbb\x12\xd5\x3e\x44\x97\xcd\x71\x20\x48\x95\x5a\x52\x9a\x03\xbe\x4c\xd0\xc7\xf3\x3c\x22\xcb\x8a\x2d\xa8\x33\x91\xfb\xfe\xe6\x95\x2c\xd6\xb8\x4b\x31\x52\x3a\x93\x7a\xc6\x4f\xec\x1f\x4c\x64\x75\x1d\xc6\xac\xfa\x7e\x63\x02\x2f\x30\x1c\x02\x8e\x81\xae\xec\x9c\x4a\xe4\x0d\x88\x6c\xcf\x89\xa7\xad\x94\xc8\xde\x8b\x9b\x71\xaa\x3d\xba\xa3\xbd\xfa\xf0\x85\x36\xd2\x9c\xcb\xa2\x23\xb2\xd6\x2c\x69\x1f\x28\x3a\x41\x1f\x85\xb6\xc7\x7f\x1f\x3f\xf5\x9f\x1c\x18\x9d\x44\x42\x91\x6c\x1d\xa7\xe8\x06\x7d\xe6\x15\x16\x43\x53\xbe\x15\xca\xc6\x7f\x84\x1a\xe3\xf4\x99\x17\xa8\x79\x2c\x77\xd2\x72\x66\x3d\x07\x7a\x15\xea\x5a\xd3\xe0\x46\xd3\x38\xe6\x07\x61\x71\xd9\x98\xab\x04\xab\xda\x7f\xb4\xc0\xad\x73\xde\xcc\xaf\x85\xb4\x95\x34\x4f\x2d\xc0\x5a\x7a\xbf\x8a\xce\xb2\x51\x6a\xc2\x03\xf6\xec\xa1\xf0\xea\x2b\x41\xef\xde\x57\x45\x26\xb1\xf4\xa7\x52\x97\xee\xb4\x38\xdb\xf1\x95\x39\x2b\xdb\xce\xbb\x8c\xd1\x6b\x79\x14\x6c\x12\xf3\xf3\x54\x1c\x85\x62\xbd\xee\x2b\x7a\xd3\xfd\xa3\x9e\xb2\x30\xfb\xd0\xb7\x35\x1f\xde\x45\xc0\x53\x65\xbe\x85\xa9\xf6\x79\x7c\xb6\x85\x1e\x28\xd4\x10\x56\x3e\xe1\x2a\x77\x26\x92\x7d\x23\x6f\x9b\x84\x0a\x5f\x8a\xdd\x17\x7a\xc9\xec\x8b\x5b\x43\x56\x1e\x57\x52\xef\xaa\x49\x24\x16\x52\xb6\x40\xcb\x5c\xec\x2c\xde\x35\x5e\x83\xc5\x5e\x82\xdf\x95\x8c\x22\x2c\x41\x49\xc5\x7e\xb4\xe3\x0b\xee\xfb\x65\x38\xcb\x88\x4e\xf8\xd8\x71\xef\x05\x45\x34\x4f\xe4\x75\x7d\x7e\xad\x25\x42\xf3\x96\x9c\xaf\x87\x76\x7f\x36\xf4\x0c\xd0\xdc\x68\x2f\xbd\x84\x65\x59\x46\x95\xe9\xaf\xb6\x7e\x1e\x71\x0f\x57\x8d\xf5\xbb\x0d\x9a\xe5\xe4\xdb\xf7\x50\x85\x31\x12\x7d\xfe\x4a\xf3\xb0\x43\xf9\xda\xc7\x94\xca\xc2\x35\x96\xfc\x85\xd3\x4c\x10\xf9\xc5\xad\xb1\x34\xe2\xc6\x9b\x44\x95\xf9\xf5\x6f\x86\x8b\xbf\x02\xff\x07\x00\x00\xff\xff\x45\xe4\xc1\x2c\xcd\x06\x00\x00") +var _resourcesPlotM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x55\x6f\x6f\xe2\x46\x13\x7f\xcf\xa7\x18\xe5\x91\x1e\x25\x92\x8f\x00\x77\xc9\x5d\x83\x52\x1d\x77\x29\x1c\x15\x5c\xa2\x90\x77\x2b\x37\xd9\xd8\x6b\x58\x75\x59\x5b\xf6\x3a\x0d\x45\xfe\xee\x9d\x19\xdb\xd8\x10\x1a\xa9\x6f\x16\xef\xce\xfc\xe6\xef\x6f\x86\xef\xb1\x89\xd3\x1b\xe9\xa4\xf8\xe5\xb3\x07\xfa\xd1\x87\xab\x6b\x58\xfc\xa5\x5d\xb0\x12\xda\xeb\x00\xf4\x3d\xb8\x9f\x7c\x63\x35\xd1\xeb\x7e\x44\xa5\x5e\xf7\x82\x8e\xcf\x7d\x9f\xe4\x83\x3d\xf9\x97\x2f\x24\xba\xa4\xa3\xff\x89\xe5\x0f\x69\xae\xf6\x54\x2e\x4a\x34\x1d\x03\xbf\xe3\x0f\x3b\x9d\xdf\x5e\x93\x54\x85\x79\xa0\xc6\xda\x38\x95\x4e\xd7\x72\xa9\xad\x4c\x37\x77\xb1\xb6\x2e\x13\xb9\x8d\xf8\x5d\x85\xe5\x03\xc7\x88\x96\x17\xca\xa8\xc0\xbd\x11\x7b\x70\x3a\x5d\x8b\xff\x09\x31\xf0\x7d\x1f\xae\xaf\xa1\x77\x06\xff\x27\x37\x23\xe7\x52\xfd\x9c\x3b\x95\x89\x9d\xc7\x3b\x13\xbb\x12\x86\xaa\xb0\xfd\x11\x9b\x70\x64\x4c\x31\x6c\x62\x9a\xa8\x4a\x41\x44\xf6\xd1\x83\x54\xda\xa5\x7a\x9c\xe9\xcc\x55\x51\xcc\xe3\x30\x37\x4a\x6c\x6d\xed\x3d\x73\x2a\x59\xe8\xbf\x31\xe9\x54\x25\x46\x06\x2a\x1c\x5b\x0f\x0e\xa3\x2c\xa8\x36\x50\x81\xd0\xf5\x45\xaf\x37\xa4\x97\x1a\x8d\x4f\xa7\xec\x4b\x88\x8f\x98\xc6\x07\xa8\x2e\x98\xd4\xd9\x79\x0d\x3b\x3f\x87\x9f\x8c\x6a\x3c\x21\x2e\xb2\x70\xde\xad\xf5\xfb\x04\xfe\x15\x5e\x64\x7a\x1b\x4d\xd1\xbf\x74\x3a\xb6\x8c\x39\x8c\x08\x28\x1b\xec\x97\x7c\xa6\x74\xf6\x01\xed\x5c\xd8\x6b\xe1\xc1\xa1\x0a\xa3\xa1\x15\xa7\x07\x4d\x02\x4d\x59\x0a\x9f\xbd\xff\xc7\x9e\xfb\x84\xf9\xb7\x26\x62\x8b\x66\xda\xaa\x77\x3a\x48\xe2\xc3\xfe\x71\xc0\x01\x91\xb2\x24\xfd\xf6\x46\xa7\xc8\x27\xfd\xa2\xc4\x6d\x22\x03\xed\x36\xa2\xdf\xc5\xc0\x59\xc5\x83\xd1\x73\x16\x1b\xf4\xfb\xb0\xd2\xc1\x9f\x56\x65\x19\x4a\x2f\x7d\xa6\x38\xb0\xf9\xa3\x8c\xa9\x1c\xfa\x7e\xf1\x7e\xec\xef\xd1\x8f\xe5\xc7\xd8\xb7\xe3\x5e\x64\x2b\x3e\xe1\x07\xda\x99\x46\xe2\x87\x92\x21\x42\x88\xff\xd7\xc0\xd9\x02\x05\x83\x9a\x55\xfd\xcb\x36\x1f\xa9\x51\x26\x84\xde\xf5\xce\x83\x83\xfd\x40\x92\xad\xae\x7a\x3d\x53\x76\xe9\x56\x84\xf1\x8b\x5d\x83\x68\xa2\xae\xae\xf2\x4c\x2e\x89\xc3\x27\x4f\x74\xe7\x42\x10\x5f\x3c\x58\x6b\xfc\x5c\xcb\xd7\xc2\x7f\x82\x04\x45\x19\x3c\x45\xf6\x09\xe2\x17\x95\x82\x5b\xa9\xd2\x2d\x64\x89\x0a\x74\xa4\x55\xd8\x3d\x19\xb6\xcb\x46\xc6\xda\x95\xf2\xe0\x2e\x8d\x1d\x76\x4d\x85\xb8\x63\x30\xe7\xdd\xb5\xe8\x54\x8e\xdf\x9b\x59\x43\x95\xf5\x38\x8e\x7a\x7a\xa3\xdc\x98\xfb\x32\xf5\x50\x67\xc8\xf9\xcd\x6d\x42\xf4\xae\x0a\xcc\x08\x0c\xe0\x58\x7f\xea\x5e\x73\x7d\x1b\x9b\xa8\xfd\x3b\x7e\xc0\xd7\xaf\x30\x97\x89\x38\x2d\x37\x13\x4f\x26\x2e\x26\xaf\x34\x59\x82\x76\xce\x29\xc5\xb9\xb6\x73\xf9\x2a\x08\x2b\x1a\x6b\x42\x70\xda\xfd\xd6\x78\x0d\x60\x38\x04\x9c\xb1\x8a\x8c\x98\x5e\x89\x7c\x03\xa2\x85\x58\xb0\xa3\xfd\xd4\x80\xc9\xcf\x2f\xe3\xdc\x06\xf4\x46\x3b\x63\x1a\x2a\xeb\x70\x0c\x2a\xab\x23\x6a\x8a\xbb\xa7\x61\x27\xe9\x04\x3b\xa0\x2c\x5f\xff\x38\xfd\xd0\x3f\xc3\x09\x79\xc5\xd2\xa0\x64\x5b\xae\x7c\x3a\x8b\x1a\x8b\xa2\x99\x7c\x56\x86\xe5\x3f\x63\x8b\x72\x3a\x8b\x12\x75\x9b\x6a\x9c\x7e\x96\xf5\xf0\x7f\xa1\x46\x1d\xc6\x74\xf5\x26\xa6\x71\x2a\xd7\x8a\x71\xdb\xb1\x34\x19\x5a\xe5\x1f\xda\x4e\x7b\xf7\xa2\xad\xdf\x04\xb2\x1f\x49\xfb\xb6\x07\x78\xc0\x89\x2f\x33\xdb\x8e\x72\x17\xaf\x31\xe7\x00\x03\xaf\x3f\x09\x7a\xf4\xbd\x36\x32\x49\x75\xc8\x24\x79\x93\xfd\x81\x7c\xe1\x36\x86\xd3\x69\x56\xd1\x24\x95\x9b\x99\x7a\x51\x46\x54\x7f\xbb\x9f\x9a\x36\x2b\xb7\x8a\x43\xb6\x79\x72\xa3\x22\x99\x1b\xf7\x2d\xce\x6d\x88\x5b\x94\x0d\x9d\x90\xa8\x09\xac\xda\xcf\x50\xeb\xce\x55\xb6\x6a\xe9\x55\xeb\x8d\x09\x43\x7b\x5a\x5c\xfa\x0d\x64\x11\x48\xa4\xe9\xb2\xee\x44\xc6\x90\xaa\x6c\x34\x67\x25\x69\xf1\xad\x19\x9f\x12\xbb\x13\x7e\x37\x3a\x49\xd0\x04\x29\x31\x3f\x0e\xe4\x77\x32\x0c\x2b\xf1\x76\x4b\xee\x54\x88\x19\xf7\x06\x48\xf3\xf6\x8d\x6a\xdd\xdc\x2f\x9a\x10\x01\xda\xcf\x58\x7a\x68\xba\x76\xbc\x39\x3c\x08\x58\xde\x04\x17\x7a\x26\xaa\x55\xb0\x3f\x18\x3e\x8e\xe5\x3f\x01\x00\x00\xff\xff\x2f\x42\x43\xaa\x21\x09\x00\x00") func resourcesPlotMBytes() ([]byte, error) { return bindataRead( @@ -461,12 +461,12 @@ func resourcesPlotM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/plot.m", size: 1741, mode: os.FileMode(420), modTime: time.Unix(1524352562, 0)} + info := bindataFileInfo{name: "resources/plot.m", size: 2337, mode: os.FileMode(420), modTime: time.Unix(1540963483, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _resourcesPowerM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x7d\x7b\x77\xdb\xb8\xf1\xe8\xff\xf9\x14\x68\x7a\xce\x96\xa2\x48\x49\x24\x25\xc7\x4e\xea\xed\xa6\xbb\xc9\xfd\xf9\xdc\x7d\xa4\x9b\xec\xf6\x9e\xe3\x2b\xda\x14\x05\xdb\xaa\x25\x52\x21\xa5\x58\xae\xeb\xef\x7e\x67\x06\x00\x09\x3e\x40\x49\x69\x7b\x73\x4e\x64\x12\x98\x19\x0c\x06\x83\xc1\x60\xf0\xe0\x87\xf4\x81\x67\xaf\x5f\x6f\xf3\xe8\x96\xb3\x73\xf6\xf2\x7a\x16\xe5\x3c\xe4\xbb\xf5\x35\xbb\x59\x24\xf3\x9c\x51\xc2\x35\xcb\xa2\x45\xce\xe7\x6c\x93\xb2\xcd\x1d\x67\x6b\xc4\x62\xe9\x0d\xbb\x46\xc8\xc1\xcb\x37\x2f\x2c\xfb\xe3\x62\xb5\x5e\x2e\x6e\x1e\x59\xc2\xf3\x0d\x80\x42\x4e\x9a\xf0\x64\x93\xdb\xbd\x17\x54\xca\xa5\xf8\x8d\xae\x9c\xd9\xd5\x45\xb2\xe1\xb7\x3c\x9b\x3a\x71\xf1\xc8\x5e\x9f\xb3\x28\xb4\x66\x76\xdc\x7b\xd3\x44\xf8\x95\x47\xcb\xc3\xa1\x3f\x3e\xae\x66\xe9\x11\xf0\xbf\x46\x9b\x45\x9a\x88\x12\xda\x40\x2f\x12\x10\xc6\x62\xf3\xe8\xb0\x11\x65\x5f\x24\x73\xbe\xe1\xd9\x6a\x91\x44\x1b\xae\x80\xdc\x83\xa0\xae\x54\xae\xd7\x42\x7c\x70\x18\xf5\x0e\xb0\xab\x22\xbb\x85\xbe\xeb\x51\xce\xa8\xcc\xd1\x28\x38\xec\xaa\x93\x6c\x25\xdd\x0c\xe9\x39\x2c\xba\xaa\x32\x30\xbb\xfa\xcb\xcf\xdb\xd5\x8c\x67\x7f\x43\x2a\x82\x19\x82\xf8\xfb\xdd\x22\xbe\xbb\x7c\xc1\xe0\xdf\x8c\xfd\x19\xd8\x73\xe8\xf9\xfb\x14\x34\x89\xef\x0a\xbe\x25\xc0\xf9\xf9\x79\x01\x52\xe5\xbc\xa0\x20\x73\x47\x3a\x4a\x17\xc6\xb7\x65\xae\x5e\xd6\xa7\x6c\x2b\x41\x7e\x4b\x40\x8d\x79\x0c\xfa\x2c\x21\x38\x55\xe9\xaf\xd0\x27\x5e\x4c\xcb\xfa\xd5\xea\xd5\x2a\x18\x5d\x0a\xee\x21\x62\x18\x1d\x5e\xf1\x73\x05\x6c\x10\xdd\x9f\xdb\xeb\x79\x84\x80\x46\x5f\x29\x19\xd9\xff\x1c\xa6\xba\xd8\x65\x02\xd2\x9a\x5f\x4d\xa9\xe6\xb3\xd0\xb2\x12\xf7\xa7\x74\x7e\x99\x38\xf3\x69\x6f\x38\xef\x31\x1b\x13\x55\x0a\x26\x0c\xdf\xb0\x5f\xb2\xcb\x04\x58\x99\x83\xe0\xe8\x6f\x45\xf2\x6e\x97\xe8\x2d\x9b\x00\xd9\x9c\x13\x0c\x70\x80\xe6\xc8\xb2\x7f\x58\xe4\x9b\x6c\x31\xdb\x6e\x38\x8b\x92\x47\x76\x0f\xa6\x0e\xcd\x99\xb0\x6b\x37\x69\xc6\x92\xed\x8a\x67\x8b\x98\x7d\x89\x96\x5b\x9e\xb3\x45\xc2\x3e\x2d\x56\x3c\x7f\x8d\xd8\xd6\xcd\x22\xcb\x37\xaf\x2d\x55\x39\xf6\x2f\x46\xf6\x89\xfe\xca\x6a\xf6\xfe\x62\x59\x7f\xfc\xc3\xb9\xeb\xf5\xbe\xe9\x61\xa5\x16\x49\xc2\xb3\xab\xab\x5e\x08\x45\x5c\x21\xa3\x44\x03\xdf\x20\x93\x48\x5f\x12\xc8\x14\x93\x90\xef\x5f\xc0\xce\x66\x0f\x60\x74\x1d\x96\x26\xcb\x47\x36\x2f\x39\x5e\xc8\x62\x89\x5b\xaa\x0f\x11\xbb\x2a\x8b\x91\xe5\x28\xfe\x0e\x28\x4e\xf1\xcd\x72\x61\xc6\x17\x71\x54\x4a\xeb\xd3\x1d\xcf\x39\xdb\x44\xf7\x9c\x6d\xd7\x6c\x03\xe8\x03\xf6\x21\xcd\xf3\xc5\x0c\x18\x8b\xd3\xe4\x0b\xcf\x36\x38\x34\xfc\xb6\x16\xe2\x1a\x14\x26\xbf\x68\x75\x32\xb3\xd3\xc2\x04\x15\xe9\x33\x27\x2a\x5a\xb3\x01\xcc\x55\x0d\xfe\x02\xa5\x41\xeb\x7d\xe1\x55\xe4\x28\xe4\xce\x2c\xe4\x05\x01\xe8\x24\x50\xc0\xd0\x27\x28\xf7\x42\x4f\x56\xa9\x17\x2d\x85\x15\xd4\xa1\xd4\xb2\xa4\x12\x47\x0e\x14\x32\xc1\x96\xef\x33\x59\x56\x75\x38\xd9\x81\x46\x3e\x6a\xe3\x89\xaa\xb0\xcc\x85\xf7\xc7\x29\xca\xfb\xef\x9c\xad\xa2\x47\xf6\x10\x25\x24\xb9\x39\x5f\x67\x1c\x44\x0e\x52\xbe\x5b\x90\xba\xdd\x44\x5f\x52\x1a\x62\x71\xbc\xbd\xe5\xd0\x56\xd0\x38\xa5\x1a\xa3\x88\x65\x67\xbf\x1c\x39\xde\x34\xe4\x7a\x6b\x7f\x7c\x58\x6c\xc0\xa4\x60\x37\x02\xfd\x19\x4f\xb1\xcb\x8e\x1c\xd1\x97\x41\x18\x17\xf8\xd7\x77\xa4\x51\x09\xb0\x0f\x01\x53\x8a\x5c\xc6\xaf\x9c\xc5\xea\x6a\x1a\x26\x3a\x49\xa0\xb5\x5d\xf2\xcb\x27\x60\x67\x13\x81\xa7\xf0\x36\x8b\x3f\x45\x09\x00\x03\xec\xf4\xd9\x61\x1f\x3f\x67\x1b\x78\x0b\xfd\xfe\x62\x15\xfa\x80\x6c\x2b\x7a\xdf\xa7\xf9\x65\x62\x13\xde\xd4\xf9\xb8\x48\x8a\x97\x69\x7b\xa1\xd4\x95\xfe\x7b\x25\x8a\x96\xa8\x19\xca\xfe\x95\x3e\x3a\x5e\x85\xb5\xec\x56\xcb\xf2\xe9\x97\x1f\x7e\xb1\xe2\x34\x7b\x7c\x88\x96\xf7\x3c\xeb\xbd\x66\xbf\xf2\x55\xfa\x45\x36\x61\x94\x63\xcb\x65\x9c\xe5\x77\xe9\x76\x39\x67\x33\xb0\x34\x6c\x95\x66\x65\x63\x42\xaf\xc9\x65\x4b\xbe\xa3\xee\xaa\x2a\xfe\xf3\xe5\x3b\xd9\x2f\xdf\x85\xd6\x8f\xe9\x2d\xa8\xe8\xb4\x9f\x81\x57\x85\x1d\x9b\xbc\x13\x50\xc2\x77\x21\xa6\x20\x88\x84\xa0\x8c\x37\x2f\xde\x6e\xa4\x99\xc8\x85\x46\x4e\x41\x72\x4f\x3f\x82\xf1\x88\x66\x4b\xd0\x85\x9f\x85\x5d\x7b\xbf\x4d\x62\x54\x23\x87\xfd\x92\xf0\x8b\x39\xb8\x69\xe4\x20\x7c\xc8\xd2\x0d\xd9\xf4\xe7\x37\x2f\x3e\x01\xf9\xfc\x5a\x98\x4f\x20\x41\x46\xff\x1d\x39\x79\xfc\xdd\x2e\xc2\x3f\xb9\x18\xb3\x28\x03\x04\xb6\x02\x2a\x97\x2f\xdf\x29\xb7\x0f\x75\x57\x5a\x2a\x90\x06\xd4\x3b\x06\x99\x6e\x85\x67\x18\xc5\x9b\xe5\xe3\xeb\x97\x53\xa7\x24\xf0\x31\x5a\x71\x2c\x12\x7a\xeb\xd0\xf3\x27\x0e\xb3\xdc\x49\x2f\x74\x03\x1d\xa6\x28\xe4\xfd\x32\x85\x1e\x96\xdc\x82\x09\x84\x22\x4a\x57\x93\xca\xb9\x8b\x92\xf9\x12\x8a\x81\x3e\x70\xc7\x6e\xaa\x90\xd8\xcb\x16\x28\xf5\x5a\xe1\x20\xb3\xe4\x96\x8a\x7f\xe9\x0d\xce\xce\x26\xa3\x13\xde\x0f\x46\xde\xe8\xa5\xc3\x5e\x0e\x26\xa1\xeb\x8d\xe0\xdf\xe0\x65\x2b\x33\x6f\xb7\x9b\x74\x05\x85\xc4\xd1\x12\xcc\x61\xb4\x5e\xc3\x6f\x9e\xae\x38\x03\xcf\x19\x46\x90\xaa\x41\x65\x19\xe8\x74\x6e\xa8\xfa\x2a\x1c\x0f\xa0\xe2\xa0\xcd\x83\x1e\x68\x34\x41\x80\x09\x79\xf7\x7e\x9b\xa1\x2e\xed\x11\x7b\xc6\xe7\xdb\x58\x55\x3f\x87\xaa\xa6\xd0\xe2\xc4\x98\x2e\xa0\x18\x34\x76\x0e\x95\x6d\xc8\x5f\x13\x41\x45\xd5\x51\x04\xa3\x70\xd4\xce\x71\xdd\xdf\x60\xa3\xd0\x82\x31\xaf\x64\x9d\xb4\xa8\x64\x18\x7a\x0d\x24\xd0\x6c\x02\x1b\x85\x23\xd7\x39\xb6\x47\xae\xa6\x16\x34\x50\x89\xa1\x0d\x3a\x46\xb3\x44\x8f\xf5\x19\x98\x51\x6b\xd7\xf7\x7a\xa1\x67\xaa\xc1\x48\x70\xed\x19\xab\x08\x8d\x89\x10\x83\x3a\x48\xa1\x85\xa0\x81\xee\xa4\x56\x40\x99\x39\xa0\xec\x81\x09\xa0\xca\xe4\x60\x1f\x97\x83\x03\xd8\x1c\x98\xf9\xa4\x9e\x52\x2b\xa5\x8d\x55\x84\x38\xa2\x25\xfe\xc9\xb3\xb4\xa5\x21\xf4\xae\x82\xcc\x89\x4a\x8e\xfe\x0d\x65\xea\x04\x1e\x98\x54\x8f\x06\xfb\x49\x38\x32\xf6\x63\x62\x0e\x45\x63\x2e\x4e\xc1\x0c\x0e\x80\x12\xd5\x34\x37\x55\x5b\x3d\x8f\x81\x1e\x34\xc0\xeb\x35\x35\xea\x51\xa5\x1a\x7b\x88\x74\xd2\x38\x3b\x13\x62\x30\x80\xf8\x13\x04\x9a\x84\x41\x7b\x11\xd2\x70\x4f\x6a\x56\x5b\x63\xa1\xb0\xeb\x26\x80\xba\xe9\x6f\x67\xc4\x1f\x9c\xbd\x9a\x04\xa7\xbc\xef\x4d\x4e\xcf\x90\xa5\xe0\x2c\x3c\x3b\x3b\x33\x4b\x3b\x18\x04\x27\xa3\x33\x9f\xbb\xde\xe4\x6c\x24\x11\xdc\x4e\x8c\x43\x47\x81\xc3\x70\x3a\x64\x8a\x70\x5e\x87\xa1\x92\x00\xfe\x3e\x80\x3d\xea\xeb\x01\x27\x7b\x21\xf6\x16\x72\x26\xfe\x75\xc0\x0d\x24\xbb\x5d\x52\xaa\xd2\xda\x0b\x39\x08\x03\x73\xe5\xc6\x04\x63\x79\x03\xdb\xb7\x3d\x1c\x35\xcd\xda\x8f\x03\x93\x79\xc4\x90\x7d\xc8\x6b\x90\x68\x85\xd9\x6b\x52\x9a\x30\x0d\x56\xdc\x03\x78\xd9\xd7\x24\x04\x74\x60\xab\x00\x2c\x08\xe8\x40\x59\xba\x5d\xc2\x1c\xe1\x98\xa2\xc1\xd1\x90\x5f\xd1\x70\x05\xaa\x26\x42\x8e\x9c\x00\xf9\xc2\xcd\x1e\x0e\xd9\xff\xf0\x68\xde\x4a\xbd\x88\x18\x14\xf1\xa4\x23\x31\xa0\x0c\xbf\x1b\xa1\xce\x95\x7b\x00\x5b\x6d\x35\xa9\x14\xa3\x8d\xac\xca\x07\x6e\x99\x4c\x37\x09\x83\xd3\xe7\x30\x70\xf9\x6c\x9c\xc4\x18\xbc\x42\xe1\x14\xf6\x0c\x00\x32\x6f\x50\x40\xb5\xbb\x02\xca\xaf\xd4\x5c\xcc\x76\xc0\x9a\x1b\xda\xda\xb0\x26\xc7\xaf\x15\xf8\xc9\x83\xe9\xda\xaf\x7c\xbd\x8c\x62\xfe\x76\xb9\xc4\xa9\x74\x14\xae\xaf\x06\xcc\xfd\x96\x3d\xad\x9f\xa7\xed\x58\x30\x61\xf5\x81\xa8\x2a\xa2\xd7\xca\xeb\x08\x3b\x93\xdf\xdb\x0b\x57\x0b\x75\x52\xbf\x39\x16\xe7\x2b\x50\xe6\x87\xa0\x28\x11\x42\x6d\xbb\x41\x1b\x42\x17\x55\xff\x8a\x9a\x1f\x5f\xf1\xe3\xeb\xad\x63\x68\x9d\x83\x91\xdf\x99\x6c\xee\xdc\x2c\x4d\x37\x2c\x5a\xde\xa6\x19\xcc\xd4\x56\x03\xd6\xda\x3d\xa0\x9f\x79\x27\xa1\xe5\x0d\xc7\xed\x25\xa3\x3a\x4b\x80\x41\x3b\x04\xc5\x2c\xa9\x97\x5e\x7a\x23\x0f\x21\xfd\xde\xf4\xfc\x0f\xe7\xc5\x1a\x44\x37\x0e\xf8\x44\x07\xa1\x8c\xa8\x0f\x10\x64\x5b\xf6\x29\xb6\x6f\xbb\xdb\xa3\x30\x03\xa3\x8a\x8f\xba\x04\xe0\xb0\xd3\x0e\x6c\xb2\x56\x0e\x7b\x25\x40\x86\x43\xa3\x81\x93\x80\x67\x7b\x01\xa1\x8a\x42\xe4\xae\x91\xa7\x76\xeb\x60\x62\xd1\x00\x6d\x10\x24\x90\x01\x51\xbe\xea\x22\x58\xd6\xd9\x3d\xb8\xd2\xfb\x20\xfd\x57\x04\x16\x98\xd9\x92\x10\xae\x04\x69\xa8\xbc\x1c\x0c\x1e\x71\xba\x95\x45\x73\x8c\x17\xe4\xed\x3a\x3f\x46\x53\x80\xfc\x60\xdf\xf3\x4f\x7b\x1d\xcd\x3b\x96\x36\x40\x42\xbb\x7b\xc0\xbd\x09\x4a\xc5\x87\x6c\x36\x79\xa5\xb0\xce\xc6\xfe\x49\xf0\x6a\xf2\x9f\x47\x0b\x58\x50\x70\x16\x84\xe3\x2e\xc6\x2a\xa0\x00\x38\x3e\x8a\x15\xa0\x4e\x18\xf6\x04\x5b\x08\xfe\x4a\x10\xdb\x93\xea\x7c\x04\xad\x89\xad\x88\xd5\x89\xec\x63\x3c\xe8\x60\xfb\x40\xb0\x48\xe4\xe1\xf8\x68\x06\x72\x85\x0d\x2f\x9a\xbc\x4b\x5c\x22\xdb\xd7\x40\xdd\x0e\xba\x17\xa0\xba\x08\x37\xee\x75\xf5\xc0\xf6\xb1\xd4\x1b\x8e\x0c\x52\x1e\x10\xcc\x00\xe7\xa6\x13\x74\x98\x2e\x56\x12\x0e\x03\x44\xff\x3b\x49\x1f\x92\xf7\xd1\x62\xb9\xcd\x2a\x91\xad\xb2\x06\x41\xff\x42\xc4\x7a\xfd\xb3\x69\x8f\xbd\x83\xa2\x2c\xcb\x67\x17\xec\xff\x5e\x7e\x58\x4c\x7b\xd8\xb8\x40\xdf\x0a\x58\x9f\x5d\xd8\x05\x5c\x18\x74\x69\xdb\xd3\x93\x3b\x71\xbc\xa1\xd4\xdd\x67\xe7\xc9\x1d\xc3\xab\x2f\x04\x85\xaf\x01\xbc\x06\x65\xae\x2f\x72\xd5\xab\xe7\x80\x43\xf3\x34\x72\x6a\x86\x0b\xd2\x3c\xc7\x2d\x25\x0e\xef\x3e\xbc\x97\x09\x8a\x06\xe6\x04\xd5\x9c\xa0\xcc\x19\x23\x0d\x1a\x48\x4a\x3a\x93\x2a\xf4\x44\x41\x83\x5f\xf5\x09\x03\xbb\x97\x4f\x09\x0a\x39\xe9\x49\x43\x06\xe9\x98\x82\xd1\xa1\xc9\x33\x79\xa9\x7f\xdb\x2e\xf8\x46\xc9\xfd\xc5\xf3\x9b\x17\x2f\x7e\x4c\x6f\xf5\x85\x7f\x0c\x23\xf3\xa9\x5a\xf6\xc7\x00\x10\x34\xef\x16\x03\xd5\xcb\xf4\x36\xa2\x21\x5a\xac\xf8\xd3\x7a\x3f\x42\x17\xeb\x03\x7f\xf9\x99\xdf\x46\xc5\xf2\xcc\x85\xfd\x61\x01\x8d\x81\x10\x6e\x32\x15\xa0\x35\x49\xc9\xa5\x3a\xf1\x22\x20\x3a\xb2\xdc\xfd\xd8\xf5\x45\x40\x3d\x6f\x24\x97\x83\x2a\x89\x45\xac\x1f\x5f\xde\xa9\xf5\x6a\x7a\x01\xcf\x54\xad\xd4\x52\xfa\x5a\xa4\x17\x0b\x46\x1e\x2e\x4e\x09\x9a\x14\x7a\x9f\x56\x82\xee\x90\x54\x0d\xb9\xd7\x23\xee\xcd\x18\x3b\xa0\x1c\x10\x61\x2f\xfb\x93\xc3\x04\xd3\xed\x9d\xd8\x97\xd9\x21\x0e\x0c\xed\x30\x98\x0f\x7e\x3d\x13\x7f\xa7\x9a\x4e\x60\xff\xd1\x95\x82\xfa\x53\x55\x2b\xf2\xcf\x5b\x8c\xb2\x93\xf3\x56\xea\x83\x58\x0e\x79\xcd\xa2\x4a\x30\x5c\x0d\x79\x6c\xcd\xb3\x1b\xa8\xb4\x44\xc6\x89\x90\x26\x32\x2c\x64\xdf\x32\x85\x2e\x35\x62\x2a\x32\x29\x1f\xe5\xba\xd8\x2a\xf2\xa9\xda\x9a\x12\xa0\xc8\x2f\xe8\xd8\xb3\xab\x0f\xcb\x6d\x4e\x40\x94\xf3\x76\x96\x03\xd8\x54\xc0\x5b\xd1\x50\xbc\xf7\xec\xd9\x14\xd7\xa4\x23\xf6\x07\xd2\x1f\x49\x04\xd7\x6e\xaa\xab\x94\x51\x38\x98\xc8\xec\xdd\x55\x7d\x9d\xdf\xb2\x7f\x4e\xb3\x15\xc9\xe8\x81\xb3\x07\x5a\x21\xa2\xc5\x3d\x5c\x3d\xc2\xc5\xd6\xf9\x22\xe3\xb8\x48\xe2\x30\x90\x11\xcb\x16\xb7\x77\xe0\x33\xa7\x0f\xec\xe5\xee\xea\x25\x5b\xe4\x44\x24\x86\x29\xe5\x62\xce\x33\x3e\x17\x0b\x4b\xf9\x9a\xc7\x38\xd9\x04\x12\x51\xc2\x46\x2c\xcd\x98\x57\x78\xd5\xbb\xf3\xf3\x73\xf4\x24\x9d\xe2\xcd\x73\xd4\xe2\xbe\xf0\x76\xd9\x4e\xb8\xaf\xb8\x7c\x2f\x14\x13\x99\x3f\x46\x33\xa9\xb2\xe0\xe3\x32\xf9\xd0\x3e\x7a\xc8\x6c\x98\x70\xb7\xe7\x33\x9b\x55\x09\xb9\x06\x4a\x9e\xcc\x37\x10\x1a\xc9\xec\xd1\xd4\xb8\x1c\x51\x63\x1d\xe6\xf3\xa2\x40\xdf\xdd\x85\x8f\x53\x31\xbf\xb2\xe0\xb1\xef\x83\x6b\x48\x6a\xaa\x1b\xd0\x0b\xbd\xa7\x5c\x5c\x43\xb3\x50\x07\x59\xac\xa2\x5b\x18\x1a\xb3\x47\xdc\x44\x00\x7a\xc7\x32\x5c\xdc\xcd\x71\x8d\x0d\x3c\xbf\x6b\x55\x79\xea\x36\x17\xa8\x17\xe5\x3a\x2e\xf3\xaa\xc6\xe4\x42\x74\x8b\x34\xbe\xe7\x73\xad\x0f\xe0\x64\x3a\x9a\x37\x0d\xc9\xc5\x31\x8d\x85\x71\xa8\x0b\x43\x44\x81\xb2\xc6\xba\x61\x58\x8b\xe5\x7e\x5e\x2c\xef\x95\xd6\xdf\x61\xab\xca\x36\xab\x17\xec\xfd\x32\xda\x6c\x78\x72\xf9\x01\x9c\x84\xed\x46\xc4\x3e\xd8\xf0\x3b\x18\xa5\x3f\x44\xf3\x5f\x51\x97\x2f\xff\x08\x58\x30\x9a\x7f\x83\xc9\x82\x01\x49\xe2\x43\x94\x6d\xc4\x46\x8d\xcb\x84\x60\x84\x50\x6e\x79\xf2\x7b\x94\x41\x07\x9c\xcf\x39\x58\xa2\x2b\x34\x15\x4e\xb9\xae\x45\xef\x54\x3a\x6d\x6e\xf8\xee\x3b\x4b\x02\xb2\xb0\x04\xea\x11\x19\xa8\x41\x94\xcc\xf7\x13\x7a\xc1\xd0\x1c\x7c\xf7\x9d\x18\x5f\xad\x9f\xb6\x4b\x68\xbf\x74\xb5\x80\x01\xf1\xbb\xef\x4a\x84\xcb\x4b\x41\xf0\xb7\x64\xf1\x79\xcb\xaf\x17\x53\xb0\x10\x58\xa1\x1a\xc3\x4e\x17\x06\x68\xda\x53\x35\x0d\xbb\x26\xc9\xe5\x47\x9e\xdc\x6e\xee\x2e\x0b\xe4\xe9\x33\x08\x83\x13\xec\xaf\xb8\x92\x88\x9c\x62\x93\xe7\x64\xbc\xca\x25\xfb\xc2\x16\xb1\xd7\xdf\x0a\x01\x97\x55\xc7\x2a\x62\x1d\x80\xa9\x96\x66\x75\x54\x99\xf9\x54\xf4\xab\xf8\xca\x16\xd4\x91\x94\x65\xc5\xf6\x1f\xa1\xdd\x7a\xd8\x70\x39\xaa\x86\x20\xaa\x77\x05\x59\x0c\x2e\x29\xc1\xc8\x81\xaa\xb0\x5a\x6f\x68\x59\x49\x30\x4e\xbb\x06\x33\xd2\x7f\xd5\x18\x72\xf9\x1a\x1c\x95\x01\xd3\x6a\xa7\x01\x38\x4c\x5a\x51\xeb\x43\xb6\x90\x2b\x9e\x48\x6b\x9e\x82\x10\x12\x18\x8b\xf2\xed\x7a\x9d\x82\xbd\xca\x39\xd8\xc5\x39\x8b\xb2\xdb\x2d\x2e\x8d\x0e\x5e\x4e\xdf\x28\x22\xd3\x5e\xa5\x77\x89\x64\xea\x62\xcd\xbe\x24\xc9\x1f\xd1\xa1\xa2\x10\x7d\xd0\x00\x0c\xbf\x8f\xbb\x98\xc4\x33\x9b\xc1\x5b\x1f\x7e\xf5\xbc\x18\x9e\x4f\x30\x8f\x9e\x02\x82\xb1\xe5\x73\xc4\x62\xc2\x08\x30\x97\x9e\xe2\x10\x26\xbc\xb2\x0a\x56\x84\xc4\x30\x11\xd7\x50\xda\xa7\x10\x44\x48\x90\x8e\xd8\x9c\x9e\xe7\xf4\xcc\xe9\x19\x3d\x76\xa2\x82\xdb\x92\x2c\x84\xc2\x5c\xde\x43\x27\x51\x4a\xa4\x9d\xec\x5c\xd4\x44\xfe\x8d\xe5\x5f\x9f\x0a\xe1\xf4\x34\x2b\x9e\x62\xf9\x04\x85\x4a\x2c\x2e\xb1\xe0\xaf\x62\x80\xaa\x61\x5b\xa2\x78\xc8\xde\xc3\x00\xf8\xbe\xc8\x34\x15\x19\xce\x50\x60\xe1\x9c\xc4\x03\xe9\xf3\x9e\x26\xa2\x90\x28\x87\x73\x0c\x5e\xb6\x93\x1a\x92\x58\xe8\x37\x1e\xce\xdb\xa4\x3b\x9c\x1b\xc6\x1c\x42\x82\x12\xa3\x1e\x3d\x41\x83\x9a\x88\x11\x35\x5c\x4f\xd8\x4b\x54\xca\xd1\x61\xbe\x2d\x91\x34\x59\xec\x1f\xbb\x7e\xde\x2e\x97\x38\x05\x3a\x19\x91\x16\xd9\x4a\x03\x43\x1f\xa5\x65\x05\xc7\x24\x47\xe1\x84\xd4\x75\x42\x22\xc4\x5f\x6b\x82\x30\x04\x31\xee\xe9\xef\xb1\xf6\x3e\x23\x3a\xd5\x77\x3d\x3f\xae\xe5\xc7\x1a\x3d\x6f\xa4\x31\x11\xd4\x93\xe2\x6a\x52\xa0\xd5\x40\x4b\x8a\xf5\xa4\x59\x13\x71\x56\x81\xf2\x47\xaa\x4a\x1a\x5c\x91\x18\x6b\x8c\x50\xe2\xac\xa8\x00\x4c\xb9\xde\x98\x83\x52\x96\xe5\xa9\xa9\x6a\x00\x63\x1b\x38\x53\xa0\x27\x6a\xca\x07\x93\xeb\x22\x4b\x4f\xef\xc1\x5b\xc0\xe4\xd4\x13\xbc\x8c\x4a\x0f\x10\x63\xaf\x48\x7a\xbb\x5c\x36\x8d\x2c\x46\xd3\xf7\xd9\x59\xc8\x61\xe0\x69\xb2\x25\xff\xc2\x97\x79\x69\x75\x29\x12\x2f\x6c\xea\x4f\xd1\x5a\x5a\x43\x07\xd5\x10\xa6\xb6\xc5\x1c\xea\x79\xda\x62\x33\x01\xb5\xd3\x6c\x42\xfe\x31\x96\x93\x66\x70\x5e\x7f\x17\xaa\x49\x09\x2d\xb6\x5b\x3b\x5c\x50\x50\x12\xc1\x22\x75\xa1\x7c\x48\x97\x8f\x62\x38\xfe\x5b\x29\x16\x90\x8b\x96\x8e\x7b\xdf\xbe\x44\x28\x9b\x8c\xc3\x4c\x16\x7c\x10\x74\x74\xd9\x82\x26\x2d\xe8\xad\x45\x30\xfe\x29\x68\xdc\x73\x77\x0d\xd0\x34\x2c\xd1\xde\x48\x9d\xd2\x9a\x06\x40\x20\x47\xf2\x02\x36\x80\x1d\x24\x56\x8c\xa5\x6b\x68\x7e\x1d\x01\xfc\x9b\x2f\xe8\xdf\x4c\x5b\x89\x0d\xec\x2f\x57\xe1\x2f\x6b\x39\xa1\x84\x56\x2a\x37\xc4\x97\x45\x5c\xdc\x5c\xbe\xcf\x38\x07\x78\xa4\xc5\xbe\xf9\x86\xa9\x31\x1d\x31\x00\x52\xb8\xed\xef\xa3\x65\xce\xdb\x8b\x51\xc4\x6a\xa4\xea\x98\x06\xa4\x26\x41\xd5\x16\x48\x84\xb6\xfc\x73\xbe\xa2\xad\x44\x6c\x9b\xcc\xd3\x98\xc6\x5b\x98\x8c\xc8\x8d\x6d\x62\x03\x56\x92\x62\x1b\x2c\xd0\x89\x2a\x26\x28\xe4\x11\xbe\xa6\x4d\xa2\x7a\xc9\x72\xa3\xa4\x96\xe4\xb0\xdf\x25\x6e\x7e\xb9\x9e\x4e\x6b\xbb\xdb\x0a\x40\x83\x2e\x6a\x10\xa5\x36\x1a\xad\xa8\x90\x89\x5e\xbc\x0f\x0a\xe9\x06\xbb\x3e\x0c\x58\xbb\x76\xc3\xdd\x8e\x63\x04\x27\x81\x37\xe1\x71\x35\xf5\x28\x0c\xf7\x48\x8e\x46\x47\xd2\x7f\x3c\x82\x3c\x08\xe8\x18\x66\x8e\x81\x7d\xec\x10\x65\x1b\x23\x66\xb6\x0d\x82\xa7\xc6\xed\xe3\x6e\xd1\xdd\xf4\x18\xdc\xe3\x31\x54\x69\x5f\x89\xb9\xb3\xf7\x20\x1a\x94\x57\xe0\x3d\x1e\x85\x37\x98\x28\xc9\xa0\x5e\xc2\xcf\x51\x25\x8a\xee\xf2\xf2\x8e\x2f\x97\xe9\xcb\xaf\xc0\x7c\x3c\x14\x67\x77\x04\xec\xe3\x11\xb0\xbe\x6d\xa6\xdc\xd6\x3c\xf6\x2e\xc4\x1d\xc6\x47\xc9\x58\x20\xd8\x47\x9a\x8a\x12\xeb\x38\x83\x51\xe0\x1d\xd3\xad\x7d\xfb\x18\xa1\x3d\x76\x08\xcd\x00\xfd\xcf\xc3\xa1\xb1\x02\xa8\xfb\x06\x94\x96\x2a\x3f\x86\x47\x35\x22\x89\xe6\x70\xcd\x43\xe8\x83\xd9\x87\xc6\x12\x0d\x7d\x4c\x4f\x42\x9c\x0e\x0c\x83\x1e\xd2\xc6\x97\x63\xd4\xfc\x60\xe8\x63\x60\xc9\x52\xd9\xd8\x1f\xd4\xd3\xe1\x82\xf5\x1d\x7f\x70\x44\xab\x45\x4e\x74\x04\x74\xe2\x1c\x3e\x96\x14\x86\xf3\x60\x14\xd2\x0a\x43\x24\xb2\x09\x6d\xb9\xfe\xe9\xc8\x86\x19\x92\x0d\xb3\x68\x6c\x3a\x98\x6c\xb8\x81\x37\x81\xa4\x13\x99\x34\x86\xa4\x33\x78\x87\x39\xe1\x49\x60\x8b\xc9\xf6\xd9\x88\x12\x4a\x9c\x60\xa2\x11\x19\x97\xf3\x87\xc3\xf9\xfe\x6f\x71\x52\x72\x70\xd0\x2a\x5f\xab\x86\x16\xa3\xc2\x31\x6a\x4d\x48\x46\x94\x36\xcd\x18\x3e\x56\xd6\x40\x54\x2c\xac\x36\xdb\xa2\x34\x72\xa0\x2b\x53\x0a\x8c\xf8\xce\xf9\x2d\x78\xd7\xb4\x1a\xb2\xbe\x16\x6e\x2f\x54\x13\x4f\xc7\xa9\xbd\xd4\x85\x0b\x5c\x4c\x31\x0a\x8a\x38\x47\xbb\x1a\x16\x13\x8c\x28\x03\x0f\xfc\x8e\x47\x73\xe1\x0e\x57\xc0\x28\x5b\xe4\x4e\xeb\x14\x9a\xa8\xe0\xf4\x63\x0e\x9d\xf1\x1b\x89\x8c\x4b\x92\x89\x3a\x58\x83\x55\x93\x64\xe1\x49\x90\x86\x07\x04\x74\x90\xeb\xef\xa3\x9c\x03\x4b\x9b\xf4\xfb\x3b\x1e\xdf\x3f\x93\x38\xe5\x8b\xc4\x2c\xc3\x14\x6f\xaa\x99\x50\x36\x6d\x9e\x91\x29\x53\x62\x42\xd4\x50\x26\xc1\x2c\x53\x11\x9e\x0a\x64\x59\x20\x3b\xa7\xb6\xa0\xe7\xcb\x02\x98\xe6\x4c\xd5\x29\xd3\x14\xb7\x8f\xe1\x4c\x08\xb9\xf8\x81\x2f\xf9\x86\xff\xb0\x5d\x2f\x71\x7a\x81\x91\x43\x46\x33\x28\x19\xcb\x54\xc4\x81\x91\x3f\x9c\xab\x00\xa7\x62\x0e\x23\xeb\x7c\xcd\x93\xf9\xa7\xf4\xb2\xac\xf6\x68\x2a\xf8\xba\xc3\xe9\x9d\x4a\xc6\x84\xa9\x41\xf6\xc6\xf6\xfa\x29\xda\x35\x26\xd1\x04\x54\x5b\xf4\x6a\x9d\x4d\x8b\x8d\x84\x47\x1c\xc0\x79\x8f\x67\x19\xab\x5a\xa9\xcf\x73\x0d\x47\x4f\x26\x4e\xc9\x3a\x86\x2a\x77\x14\xb0\xbc\x87\xee\x24\x7c\x8d\xa2\x27\x1f\x70\x16\xe5\xeb\x38\x78\x1a\x39\x81\x33\x79\xee\xe4\xc3\x61\x14\x9e\xef\x38\x5e\xf2\x31\xcd\x68\x99\x45\x1e\x9c\x5b\x24\xeb\xed\x86\x45\xf3\x39\x2d\x29\x68\xa7\x1c\x70\xfa\x9f\xde\xdc\x30\x3c\xa2\xe5\xb0\x3c\xc5\x65\xb8\x1c\x70\xb5\xfd\x38\x16\x1e\x1a\xc3\x8e\xbc\x5d\x6e\x10\x62\xb1\x11\xc1\xe6\x55\xb4\x89\xef\xd8\x76\x3d\x68\xdd\xbb\x23\xaa\xe1\xec\xc2\x5d\xbd\x2a\xd2\x29\x2e\x2a\x15\x61\xa5\xe8\x6d\x87\xee\x8a\xaa\xdc\x70\x88\x75\x30\x88\x48\xa7\xe9\x69\xb8\x61\x21\x9a\xfd\x78\x68\xad\x23\x4d\x98\xfb\x31\xf6\x42\xfb\x3a\xb4\x70\x6b\x3b\xe1\xbd\x1a\x3c\x73\xd9\x4e\x84\x3e\x77\xbd\xbd\x9c\x39\x15\x6c\x8b\xc4\x40\x41\xb4\xc3\xb0\xfd\x26\x76\xe8\x1f\x81\xdf\x51\x7a\x18\xec\xc7\xaf\x60\x2b\x2c\xda\x3b\xbb\x0f\xd5\x0d\xaa\x52\xb3\xdc\xfd\xc5\x55\x71\xa2\xe1\x0e\xd7\x12\xf6\xa0\xf8\xf5\x62\xfc\xbd\xc5\x54\x65\x02\x8a\x7d\x8c\x44\xaa\x12\x45\x81\xce\xec\x9d\x68\x16\xd0\x0b\x0b\x14\xc3\x13\xbd\x05\xdc\x9b\xfd\x7a\xdb\xa4\xd6\xa4\xe5\x13\xad\xbd\x5a\xaa\x13\x1a\x1d\x0b\x8c\x6e\xcb\xe1\xe0\xa3\x86\x65\xdb\xeb\x31\xb5\x56\xb5\x30\x07\x61\xcd\x56\x2a\xcf\x46\x1c\x12\xfc\x88\x51\x3b\xfe\x7d\xca\x6f\x6e\x16\xf1\x02\xb1\x17\xc9\x07\x18\xc6\x16\xc9\x27\x9e\xad\x54\x00\x52\xf9\x09\x6b\x86\xc1\xc0\x0f\x30\x74\x43\x26\x3d\x23\x14\x8c\xc9\xd1\x46\x38\x05\x96\x0d\x23\xed\x4f\x68\x16\x31\x66\x87\x50\x53\xe7\x57\xf2\x8f\x70\x6d\xfe\x8d\xb0\x93\x00\x2d\x1c\x03\x41\x85\x2e\x1e\x60\x72\x2d\xef\xef\x51\x96\x00\x4b\xaf\x45\x09\x60\xbb\x3d\xb6\xcd\xf9\xfc\xe5\xf4\x0d\x8b\xb4\x6b\x13\x8a\xe1\x3f\xba\x9a\xda\x54\xcc\x1b\x51\x3c\xd0\x3e\x6f\x64\xca\x72\x75\xd6\x90\x09\xd9\x1e\xd6\xba\xc7\x86\x03\xe2\x0a\xdc\x88\x08\xc7\x7b\x1a\xdc\xdf\x94\x52\xfa\x39\x4d\x60\x48\x5e\x7f\x95\x6c\x36\x29\x15\xaa\x09\x49\xa6\x00\xcc\xba\xe6\x36\x09\xc9\xbc\xdb\xc5\x7c\xbd\xb9\x6c\x54\x23\x4c\xae\x06\x53\xe5\xce\x48\xa7\x8a\x28\x69\x4e\x15\xd5\x48\x2c\x57\x2b\xbf\xa9\x2c\x5e\x56\xb8\x94\x43\x35\xb3\x64\x55\x6e\x94\xa0\x53\xd9\x85\x66\x54\x82\xeb\xba\xc6\x80\x34\x6f\x52\x68\x82\xaa\x2b\x1c\x97\x10\xd8\x8e\x08\xc1\xae\xf1\xf7\x1a\x03\xec\x5a\xb8\xfd\x5a\xdc\x1b\x53\xa1\x58\x38\xb1\xc2\xbd\xa3\x45\x78\xc1\x39\x24\x48\x3f\xb6\xec\x09\xf5\x66\x92\xae\x79\x09\x51\xe3\x16\x32\xf1\x62\x1b\xd9\x21\xaa\x45\xff\x1b\x4d\xbc\xaf\x75\xf7\xb4\x9a\x5c\x7a\x31\xf5\xcb\x3f\x8a\x62\xa7\xec\x9b\xa2\x40\x59\xc3\x0e\xa4\xa2\x45\x09\x55\x35\xaa\xe6\x80\x6a\xc0\x7b\x7d\x50\x0d\xf6\x98\x35\x9d\xc0\xa9\xc8\x5f\x2e\x39\xe3\xf0\x13\xd9\xb3\xd0\x3f\x64\x4f\xce\x3f\xaa\x24\x70\xa9\xfa\x1f\x76\x44\xee\xe0\x0c\xc8\x18\xd6\x76\x9b\x48\xf7\x34\x9c\xa0\xbb\x25\x06\x3f\xc3\xc2\xb9\x3f\xae\xa2\xfa\xf6\xcc\xb6\x7c\x2a\x30\xb0\x67\x3d\x35\x74\xa8\xf7\xa2\x22\xad\xb4\xce\x6a\xd5\xf7\xc9\x4f\xa0\x99\xb2\x35\x91\xcf\xc4\xcc\xc8\xb8\xb7\x49\xc7\x8f\xc4\x81\x62\xc3\xac\xfe\x2b\x18\x3f\xa8\x54\xe1\xc9\x99\xea\xe8\x46\x0d\xe8\x9a\x1f\x67\xc0\xb3\xbc\x61\xd4\xeb\xcf\xaa\xd8\xfb\xc7\x7d\xd3\x82\xbc\xdf\x24\xd4\x35\xe4\x1f\xa4\x36\x91\xb3\x73\x0c\x2d\x13\xb1\x1a\xe7\x20\xcd\x4e\xe8\x7e\x1c\xce\x1b\x18\x94\xf8\x55\x58\xfd\xc9\xce\x8c\x38\xaa\xf7\x3a\x81\xd3\xc3\xb0\x48\x81\xa8\x79\x04\x1a\x30\xda\x00\x93\xb1\xc7\xbc\xf6\xd0\xc7\x12\xd7\x3f\xc1\xd0\x6b\x76\x1f\xef\xbe\xc8\xd3\x78\x11\x6d\xd4\x25\x0c\xcd\xe8\x47\x83\xb6\x36\x87\x26\xf6\xc4\xae\xab\xaa\x05\xc7\xc9\xf4\x62\xea\x3c\x2d\x9c\x91\xa3\x05\x64\x90\xa9\x67\xa3\x7d\x13\xfb\xb9\x5a\xd7\x07\x6b\x50\xc7\x58\xb7\xa7\x99\x9c\xac\xd6\x2b\x32\xeb\x07\xbb\x3e\xae\xa0\x98\x22\x70\xe0\xb6\x8d\x5a\x31\x3b\x91\x5c\x2b\x1a\x42\xcf\xf5\x86\xb3\x16\x4c\xcb\x8d\xfa\xe0\x71\xcf\x9c\xdd\x21\x56\x95\x58\x6f\x67\x41\x31\x1f\x18\xf9\x00\x08\x70\x6d\x27\xe8\xd8\x77\xe2\x1b\x82\xe9\x4f\x05\x36\xf9\xae\x66\xfc\x59\x45\x4b\xb5\x68\xdd\x36\xdd\x20\xf8\xaf\x7c\x15\x2d\x92\xb9\x7e\x75\x5d\x75\xed\xbf\x0e\x77\x89\xae\x07\xde\x3c\xb5\xf8\xa2\x54\xad\xaa\xc8\x9f\x25\x06\xc3\x8d\x13\x99\x42\x13\x31\x3d\x40\xbd\x46\xcc\xc5\x1c\x34\x7a\xf6\xc8\xae\xe1\xf9\x9a\x6d\x32\x2e\xae\x16\x21\xad\x96\x17\xbe\xe8\x2e\x8e\x52\x7b\x19\xee\x13\xa3\xf5\x8f\xe0\x0b\x00\x12\x55\x9d\xd4\x5e\x6e\x6b\xab\x39\x2b\xbb\x50\x0f\x39\xee\xa6\xd5\x65\xfa\x46\xed\x16\xc9\x9a\xfc\x97\xcf\x57\xda\x06\x02\xe5\xc0\x44\xe4\xb4\x00\x99\x19\x3d\x7c\x06\x7a\x18\xef\x73\x58\xe6\xe0\x9d\x5a\x31\x20\x3a\xb8\x19\x10\x32\x32\x28\xb5\xf0\xe9\xd5\xd5\x35\x9b\xbb\x45\x72\xcf\xe2\x28\xe3\x37\x5b\xba\xe2\x64\x96\x6e\x37\xec\xe1\x8e\x27\xec\x02\xfd\x74\x24\x46\x1b\x11\x37\x29\x8b\xbe\xa4\x8b\x39\xdb\x26\x78\xb1\x11\x5e\xf5\x82\x17\x42\xd1\x72\xbf\x70\xc6\x3f\x33\xda\x34\x0d\x4f\x78\xa9\x4c\x44\x4f\x73\xa6\x85\xcd\x66\x58\x59\xe1\x15\xa7\x0f\x90\xb1\x0b\xe7\xd2\xc7\x67\x9f\xf0\x5a\x1d\xc9\xd2\x5d\xb4\x5e\x43\xf1\x78\x77\x17\x5e\x47\x85\x3b\x9e\x37\x58\x35\x0c\xeb\xdc\xc8\x98\x13\x54\x30\xcd\x70\xb7\x07\xa6\xd3\x7c\x43\x6d\x86\x06\x97\x8c\xa8\x8b\x39\x88\x9c\xa9\x3c\x41\x0f\x1b\x0e\xcb\x8b\xc1\x60\x68\x7e\x96\x21\xc0\x98\x55\xdb\x67\x86\x1b\x27\x1f\x44\xde\x82\xd1\xc9\x01\x78\xfa\xfb\xdd\x02\xa4\x8d\x12\xd4\x2b\x94\x51\x85\x48\xb0\xec\xdb\x73\xa8\xec\x37\xdf\x00\xce\x9f\x99\x2f\x5d\x59\xcb\xfe\x31\x4d\xef\x73\x30\xa4\xf7\x1c\x83\x50\xb7\x7c\xd3\x70\xa4\x23\x19\x4f\x53\xbb\x40\x55\x74\x6b\x29\x74\x49\x38\xa6\x18\xc9\x1a\xb0\x0f\x3c\x03\xd9\xe4\x48\x29\x8e\x12\xf6\x8f\x2d\xd8\xb5\xdb\x2c\x9a\x35\xe1\x91\x28\x16\x36\x4b\xc1\x42\x83\xf4\xd2\x24\x06\xfc\xb7\x90\xba\x8a\x1e\x67\x5c\x51\x80\x32\x97\xe9\x42\xf2\x14\x25\x69\x82\x5b\xfb\x41\xb0\xa0\x75\x40\x4a\x86\xc0\x2c\xfb\xaf\x5b\xb1\xc9\x88\x38\xc3\x76\xe2\x7c\x05\x5c\x64\x69\x72\x3b\x00\x2d\x11\x2a\x44\xc7\x07\x96\x30\xaf\xe5\x79\x8e\x81\x35\xe8\x4f\x74\xd7\x95\xac\x9b\xbc\xc0\x06\x2f\x0d\xca\xe0\x05\x7e\x07\x05\x7d\x3c\x5d\x00\xfa\xb5\x4a\xb3\x2c\x7d\x78\x4d\xc7\x11\x98\xd0\x42\x60\xfd\x4f\x74\x4b\xc9\x9f\xd8\x8d\x3c\x2e\x40\x57\x95\xe5\x74\x57\x19\x50\x5e\xa5\x20\x03\xd2\x12\xac\x72\x0a\xf3\xab\xd5\xe2\x9f\x1c\xc3\x79\xd0\x95\x57\xd1\x3d\x4a\xe4\x9e\x67\x09\x5f\xb2\xf8\x2e\x4a\x6e\xb9\x3a\xa7\x9d\x43\x3b\x5a\x7a\xbb\x63\x5b\x86\xd8\x92\xd3\x61\x8c\x43\xaa\x45\xad\xea\xb2\x79\x8f\x14\x80\xb4\xfb\x33\x38\x1b\x22\xfa\x4c\x2a\x9e\x41\x76\x6e\xcf\x44\x02\xea\x0a\x1e\x8d\x11\xfa\xc2\x84\x02\x3d\x61\xb7\x7b\x2e\x27\x0d\x4d\x6f\xbd\xa3\xe3\x37\x46\xb6\x26\xec\x1e\x0b\x79\xb8\x61\xfc\x4f\x99\xc2\x16\x1e\x5a\xcd\xd7\x1e\x7b\xe7\x08\x53\xf6\x65\x7a\x49\x41\x86\x6e\x81\x75\xc8\x69\xdf\x50\x72\xf8\x10\xf2\x9f\x1f\x35\xda\xb8\xf8\x37\x65\xe5\x1b\x65\x65\x56\xaa\xc6\x76\xaa\x7a\x19\x47\xb9\x4e\xe0\xe7\x80\x23\x8e\x51\xc6\x2e\xae\x7d\xe9\xc2\x53\x10\xd1\x61\xbe\xf0\xe1\x8d\xfe\xfb\x13\x6d\x77\x61\x8f\x7d\xdc\x34\xe4\x3e\x92\x7b\xd2\x45\x5e\xcc\x05\x81\xa8\x79\x53\xc4\xd3\x0e\xa6\x1d\x9e\x0b\xbf\x7b\x68\x79\x8a\x49\x39\x5f\x91\xdb\x3a\x0e\x71\xc5\xfa\xd1\x10\x5c\xf2\x3d\xf4\xa3\x3e\x4c\x8c\xc0\x75\x37\xcc\x78\x9f\x20\x9f\x1d\x4a\xc5\x33\x53\x19\xc6\x7d\x6b\x86\xc1\xec\xf8\x40\x5a\x31\xd2\x2a\xdd\x34\x93\x96\x1c\xa3\x1c\x42\x37\x5a\xca\x3e\x56\x1f\x74\x75\x68\x23\x77\x40\xfb\x63\xf3\xb7\xa1\x76\x36\x77\x9b\x20\xbe\xaa\x9b\x54\xd8\xfe\xea\x6e\x81\x3d\xa1\x9d\xd0\x01\x02\x20\xdd\x6f\xc7\xde\x2b\x83\x17\xef\xa3\x78\x93\x66\x18\x29\xcb\x1b\x33\xcb\x5a\x9e\xda\xc1\x7c\x43\xc9\x39\x8d\xeb\xc2\x05\x4a\xf2\x0d\x5d\x90\x29\xa3\xc2\x6a\x3f\x33\x0c\xe3\xeb\xed\x46\x58\x4e\x81\xc4\xe7\x6a\xa1\x0e\xbc\x07\xf0\x42\xd9\x35\x12\xbe\xae\x78\xde\xdf\x4b\x72\x58\xee\x65\x5c\x3d\x15\xf8\x04\x4e\xb0\xf7\xbc\x1f\xd8\xe6\x57\x05\x3c\x37\xc2\x2b\x20\x4f\x00\xb5\x55\x57\xee\xbb\x6e\xac\xc4\x6f\x52\x01\x0d\x6e\x39\x21\xc0\x5f\x15\x60\x14\x19\x08\x69\x8c\x30\x0a\x10\xb1\xc8\x5d\x86\x18\xa5\x83\xdb\xce\x6b\x81\x34\xd5\x7c\x12\xf0\xb6\x3f\x80\xbb\x9f\x88\x0b\x15\x13\x1e\x83\xc3\x86\x07\xda\xe6\x5b\x8e\x4e\x3e\xde\xa2\xc8\xe7\x3c\x41\x67\x2d\xcf\xb7\x5c\xf9\xd5\x82\x65\xf4\x9a\xac\xd6\xc2\xe8\x0c\x98\xda\x31\xad\x0a\xee\xd1\x61\x07\xa5\x7e\x9f\xb2\x28\xc9\xd7\x69\xce\x7b\x72\x58\x97\xee\xf7\xff\xfa\xfe\x07\x44\x12\x25\x14\x8b\xfb\x11\x48\x53\x24\x4d\xc1\xa5\x1e\x39\x04\xea\xc6\xd2\xb1\x8a\x4b\x71\x0e\xe3\x52\x66\xcf\x4d\x0f\xab\xd6\x42\x86\x01\xb0\x06\x75\xd4\xa0\xe7\xd3\x3d\xa4\xa7\xec\x1e\x6f\x2e\xad\x2b\x84\x4f\x5b\xdc\x4e\xed\x7b\xc3\x56\xa9\x27\x0c\x72\xc1\x1c\xbf\x05\x35\x1a\x92\x2d\x18\x1a\x62\x74\xa0\x82\x06\x3c\xc4\x3a\x68\x8c\xa2\xc3\xee\x0d\x7c\xc3\x4e\xa7\xa7\x49\x2b\xb4\x61\x1f\xdb\xd3\x64\xd0\x0e\x6e\xd8\x04\x86\xb5\x69\xab\x4b\x97\xd4\xda\x65\x66\x0c\xb3\xe0\xe5\x1d\x4e\x9b\xc0\x2c\x37\xc0\x65\x4d\x13\xa6\xa9\x7d\x44\xd8\x15\x4c\x74\x17\x8f\x78\x1e\x64\xd6\xf7\x59\xdc\xeb\xef\xca\xe7\x36\x26\x8a\xe6\xc6\x33\x24\xf6\x8c\x48\xc7\x86\x53\xde\x20\x2d\x1f\xcf\x54\xb4\xd1\x39\x05\xcc\xb1\x4d\x0b\xdf\x63\xa3\x2c\xf0\x30\x30\x90\xc0\x98\x8d\x81\x8c\x3b\x86\xe9\xcd\x89\xbd\x83\x5f\xff\x20\x6a\x6e\x27\x39\x0c\xd8\x06\x44\x8d\x68\x99\x5b\x49\xd2\x72\x3b\x69\xf5\x0f\xa1\x85\xf2\xdf\xc3\x93\xa0\xd3\xdf\x4f\xa7\x9b\x21\x57\xd5\x6e\x0f\xa5\x49\x27\x3f\x13\x5b\x6e\x39\xb0\xe5\x92\x82\x81\xca\x78\xe4\x78\x44\x26\xc0\xd2\xfa\x22\x5e\xd7\x42\x4c\x3a\x10\xc6\xd3\x84\x4f\xee\x09\x10\x6a\xef\x10\x1e\xd6\xc8\xf3\x3b\xbb\xc5\x30\x70\x82\x76\x74\x0f\x75\xf0\x04\x91\xcf\x8c\xed\xec\x9f\x8e\x46\xc1\xc8\x1b\x9e\xbc\x0a\xc6\xe3\xc9\x68\xd4\x03\x7f\xdc\x27\xd9\xb4\x55\x87\xb6\x32\x12\xfc\x24\x38\x7d\x35\x39\xa1\x03\x5c\x22\x85\x78\x3c\x39\x0b\x5e\x9d\xe2\x9a\x40\x91\x18\xe2\x5d\x1a\x04\xdb\xc3\x9b\x27\x4d\x0e\x8c\xc9\x79\x39\xd2\x71\x71\x30\x18\x15\x25\x8f\xe8\x95\xd4\xa9\x98\xfc\x01\xe5\xde\x08\x27\xa0\xf4\x76\xce\x1b\xb5\xe7\x62\xd4\xc3\x71\x51\x41\xd1\x10\xaa\xdf\xf1\x5f\x12\xa0\x89\xa0\x4a\x94\x67\xa6\x55\x9e\x14\x02\xeb\x18\x25\xf7\x8f\x90\x47\xf9\xba\xb6\x1a\x1c\x2b\x8d\xba\x77\x5c\x24\x3b\x60\x5b\x18\xfd\xae\x22\xee\x19\x15\x01\xa1\x06\xaf\x8f\x86\xd5\xad\x12\x02\x4c\x79\x31\xf2\x20\x58\xa3\xb1\xd6\x0d\x7f\xed\xff\x87\x0b\xc5\x85\xef\xf4\x1f\xf4\x99\xf0\x98\x63\x19\x02\xbd\xe4\xc3\xb8\xb1\x2b\xa2\x26\x10\xe9\xeb\xf2\xfa\x06\xc7\x36\xe0\x86\xd6\xbc\xc0\xe3\x5d\x78\xba\x4b\xdf\x6b\x5b\x1e\xf9\x92\xdd\x4b\x8f\xb1\xa8\xe8\x08\xc5\x0d\xcb\x73\xe4\x25\x4e\xae\x3e\xfe\x42\x1e\x78\xfe\x5c\xcd\x0b\xd7\x95\xab\x0a\xb4\xac\x69\x03\xb0\xb8\xc4\x7f\x2f\x64\xa1\x12\x2f\x48\xc4\xf2\xf2\x92\xbf\x01\xa8\xc3\x70\xa7\x8f\x65\x59\x79\x58\x9c\x9a\x5f\x53\xa3\x15\x24\x9a\xe4\xd4\xee\xdd\x06\x9d\xa7\x3c\x5c\x3f\x37\xe1\xa9\xfb\x76\x95\x0f\x78\x62\x7f\xac\xd8\x1c\x02\xca\x5a\x48\xa1\x4a\x4e\x36\xa6\x25\x75\xa5\x20\xc4\xa7\xec\x5f\xff\x2a\xee\x22\x98\xaa\x2d\xc5\x2a\x72\xae\xe2\xe4\xb8\xc5\x84\xd3\x3c\xe9\xf2\x49\x6c\xf6\x25\xd6\xc4\x4e\xa4\x67\x79\x9f\x1e\xc7\xeb\x0e\xf4\x79\xc9\x6f\x09\x86\x6c\x41\x51\x0b\x3e\x6a\x4a\x5e\x52\x2f\x39\xf8\x56\x2f\x9f\x2b\x06\x7e\x4b\xee\x71\xdb\x14\x3e\x56\x8f\xfa\x97\xd2\x6e\x37\x5c\x65\xd1\x47\x45\xb2\x1c\xf6\xf8\xac\x9f\x51\xa4\xf9\x34\xfe\x37\xad\x99\x3f\x3d\x84\x0f\x18\x44\xc6\x13\x24\x15\x4c\x48\x27\xc7\x00\xb1\x0d\x67\x4b\x9e\x60\x2e\x3e\x0b\x63\xfc\x99\x57\x70\xa3\x10\x5c\xc1\x10\xfc\xc1\x98\x06\xf3\x79\xef\x20\xbf\xbe\xc9\xbc\x6d\x5a\xb5\x6b\xaf\x67\x07\xb0\x83\x12\x18\x4c\x4c\xb2\x31\x9d\x6b\x79\xaa\x96\x62\x96\x22\xc8\xa9\x4a\x3b\x34\x72\x43\x47\x7b\x68\x33\x6e\x05\x9c\x18\x31\xc7\x12\x1b\xed\xd3\xdd\x32\xa6\x36\xf5\xf7\xb6\x69\x05\xc1\x0f\x2d\x92\x92\xc9\xa9\xab\x01\x9b\xd8\xaf\x80\xdd\xa4\xe9\xa5\x69\x5a\x89\x79\xbb\x69\x03\x7c\xd7\x09\x8f\x27\xa5\x9a\x28\x74\x7e\xca\x8c\xe5\x37\x51\x7c\x13\x7c\x05\x12\x1d\x00\x23\xa4\x38\x18\xd6\x80\x37\xf2\x5f\x81\x34\xcd\x60\xab\xaa\x02\xaf\x87\x10\x7b\xf2\x4c\x60\x35\xcd\xeb\xe8\xda\xb4\x1d\xa8\xa1\x44\xe8\x9a\xa8\xcd\x53\xa4\x4e\xf6\x23\xed\x1e\xf7\xed\x2e\x33\x51\x21\x51\xa0\x1f\x85\x00\x36\xa5\x1b\xa5\xcd\x14\x89\xa2\x42\x71\xad\x48\xef\x78\xfc\x0a\xba\x01\x17\x37\xb5\x94\x25\xf0\x5a\xf9\x95\x3c\x23\x05\x21\x90\xb8\x55\x4c\xf1\x3e\xac\xe2\x02\x95\xd6\xca\xf7\xf6\xb0\x5f\xef\xf1\x9d\xc0\x78\x19\xc2\xac\xaa\xe1\x22\xc9\x24\xd7\x10\x77\xc6\xd5\x2a\x86\x1f\xb3\x63\x78\xff\x88\x69\x53\x47\x5b\x4b\xd4\x06\x14\x03\xa2\x15\x43\x6e\x0b\xde\xd1\x38\xdd\x18\x78\x20\xb2\xb5\x24\x99\xbe\xa7\xc5\xea\x43\x91\x96\xbe\x07\x93\x4a\x88\x7a\xed\xcd\x2c\xf2\xf6\x97\x5d\xea\x4b\x64\x24\x84\x61\xf4\x83\x34\x66\x32\x38\x99\x9c\x9c\x4e\xc6\xfe\xf8\x6c\x7c\xe6\x07\xa7\x26\x33\x56\x35\x4f\x26\xeb\x14\x85\x2f\xff\x87\x4e\xa5\xd4\x14\x46\xa6\x1e\xa6\xc2\x5f\x03\x6c\xb6\x0c\x25\x44\x3b\x4f\x02\x73\x6f\x49\x1f\x16\x46\x9f\x20\x12\x97\x8c\xd4\xfa\x95\xbc\x16\x90\xf5\x59\x77\x0f\x6b\x43\xda\xbf\x6f\x1f\xb7\xd3\x14\x9b\x20\x72\xfc\x4a\xcf\x17\x9a\x07\xce\x53\xb1\x45\x4e\xb9\xda\x86\x43\x45\x68\xd7\xa4\xe5\xb1\x5b\xec\x8e\xad\x5b\x1d\x6d\x16\x5b\x2e\xdd\xc0\x5c\x50\x9f\x63\x55\x32\x70\xf3\xe3\x0c\xe6\x59\x71\xb4\x8c\xb7\x4b\x3c\x3d\x57\x5f\x93\xc6\x99\x24\x86\x31\x22\xb1\xf8\x72\x3d\xbb\x56\xab\xd3\x1f\xb7\x33\xb1\xf0\x02\xd3\x3b\x24\xb5\x48\xde\xd2\xea\xf4\x5f\xe9\xf7\xff\x14\xbb\xb8\xd5\x64\x79\x4b\x5b\x90\xde\x8a\x23\x87\x00\x26\xf6\x22\x01\xa4\xc3\xee\x1c\x36\xe7\x40\x08\x98\xe1\xf8\x9b\xf0\x87\xdf\xe8\xf7\x77\x20\x25\x26\xd5\x77\xc5\x66\x9b\xfa\xb6\x9b\x2f\xb4\xe6\x31\xaa\xef\xae\xd9\xbe\xdb\xe9\x9b\x71\xb6\xc5\xee\x22\xf6\xa5\x9a\xf3\xa5\xcc\x21\x26\x20\x0f\x71\x5d\x84\x13\xc9\x33\xf1\x15\x32\x71\x0b\xab\x80\xc1\x9b\x9a\x6c\x00\xb3\xef\x42\x4a\x10\x80\x74\x86\xd2\xb6\x00\x71\x78\xd7\xd3\x33\xb0\x42\x28\x8e\x2f\xc5\xeb\xef\xec\xbc\x75\x79\x0d\xf8\x24\x86\x86\x58\xa8\x80\x46\xc1\x21\x01\xc9\xbd\x78\xfb\xbd\x63\x5f\x09\x4c\x97\xaa\xf5\x66\x62\xd2\xe6\x39\x6c\xab\x26\xf5\x96\x4d\x47\xda\x92\x3f\x6d\xd8\x43\x9a\xdd\xcb\xa3\xab\xea\x53\x80\x6a\x3b\x4d\xce\x1e\xf9\x86\x02\x14\x00\xaf\xed\x56\x82\x39\x7e\x11\x8f\xa2\x83\x76\xb9\xdc\x02\x51\x44\x99\x08\xa9\xaa\x6b\xa5\x82\x28\xd5\xa8\x07\xb2\xa8\x0e\x06\xdd\x72\x84\xce\x94\xba\x0f\x69\x62\x03\xc8\xb4\x73\x6f\x03\xa0\xef\xdd\xe8\x5e\x81\x3e\x66\x1e\x38\xe9\x57\x56\x49\x91\x55\x6f\xd2\xf7\x02\x16\xf5\xf1\xaa\x32\xdf\xf1\x46\xfd\x57\xf0\x12\x99\x8c\x1e\x10\xc0\x4c\x13\x91\x09\x12\x21\x52\x81\x22\x45\x37\xc9\x01\x8e\x21\x6a\xeb\x4e\xdc\x2e\x8a\x2e\x64\xb9\x82\x1e\x14\xed\x46\x61\xfd\x12\x58\xbc\xa4\x95\x2e\x0c\xaa\xde\x05\x5b\x24\xd7\x23\x33\xe5\xbd\x4a\xb4\x40\x4b\x57\x2b\x89\xab\x5e\x5d\xda\x8d\x57\x9a\x12\x71\x57\x2c\x7d\xd1\x12\x35\x2e\xa7\x8f\x6d\x6e\x93\x05\xc5\x75\x36\x3a\x64\xee\x34\xef\xf6\x13\x17\x6a\xd2\xad\xe9\x55\x6e\xaa\xe1\xd3\x1b\x0a\x9f\xd2\x31\x92\xf7\x0e\x91\xa4\x73\xb8\x37\xeb\x6c\xb1\xe2\xc2\x92\x94\xc1\x04\x6d\x56\x32\x9d\xe2\xa5\xae\xe5\x96\x40\x71\x41\x92\xe8\x4e\x48\x4b\x18\x0c\xbc\xdc\xed\x46\xed\x51\x24\xd2\x4c\x8f\x0f\x21\xe0\xb4\x0c\xc4\x41\x41\x7f\xa8\x1c\x37\xaf\x30\x35\x6d\x2d\x4b\x30\x0a\x54\x7f\xa8\x41\x53\x6e\xb5\x49\x05\x80\xc0\x90\xb1\xde\x6a\x27\xd0\x04\x55\x0d\x7e\x98\x6e\x11\xd5\x10\x8e\xe9\x05\xf2\x64\xbd\xde\x2e\xf2\x1a\xaf\x3e\x7e\x93\xa4\xb8\xd9\xac\x55\x61\xc5\x49\xfe\x2a\x2e\x99\x57\x46\x7f\x4d\x17\x19\xb7\xa0\xf9\xb4\xa9\x21\x28\x10\xb5\x9b\xf4\x5a\x49\xb4\xb1\xad\x68\xd4\xfa\xc5\x07\xf5\x89\x6b\x2d\x62\x8f\x4f\x6f\xb4\x9c\x35\x7e\x41\xb4\x68\xec\xe1\xe7\xca\xab\x16\xa3\x6b\x28\xdf\x5a\x45\xea\x71\x08\xd3\x93\x29\xb5\x4c\xf8\x2c\xa3\x67\x6d\x3b\xf9\x68\x0b\xaf\x8e\x2b\x2c\x23\xe8\xcf\xf0\x73\x71\xa9\x6f\xc1\xeb\x71\x97\xc5\x8a\x65\x2b\x30\x28\x45\x55\x2d\x4f\x2d\xfb\x51\xde\xb8\x37\xb4\x14\x98\xa1\xb9\xc6\xb8\x53\x45\x23\xe0\x8e\x69\x39\x6c\x2c\x16\x62\xf6\x61\xbb\x58\x9e\x58\x3e\x13\x67\x4b\xc7\x0d\x6e\xe4\x11\x14\x99\x3f\x29\x68\x1a\x28\xfa\x54\xfc\x44\x56\x61\x22\x0e\x08\xe9\xfc\xf9\xb4\x80\x18\x68\x00\xe3\x7d\x34\x5d\x5c\x76\xf2\x3c\x42\x3c\xb1\xb5\xad\x3a\x3a\xab\xb8\x0a\x15\x9c\x51\xe9\xfe\x99\x2d\xb8\xc6\xbf\x41\x29\xc9\xa0\xa3\x0c\xb0\xe1\x2e\xf3\x26\x85\xf0\xaa\xcd\xe2\x06\x67\xc8\xec\xa9\x58\x96\x7d\x25\x79\x28\x84\xdc\x45\xd8\x0d\xa4\x88\x03\x03\xe7\xee\x99\x5c\xf0\xed\xb3\x53\x09\x72\x52\xe1\xbb\x93\xba\x04\x6f\xe7\x9a\xe4\x26\x72\xbd\xd3\x1a\xd3\x8a\xea\xfe\xb0\xa6\x27\xd1\xa4\x80\x48\xb2\x13\xc9\x61\x20\xef\x32\xa1\xbb\x04\xf4\xa2\xbd\x11\x36\x08\xfc\x8a\x16\x19\x29\x99\xf9\x81\x68\x14\x97\x9d\x7a\x84\x8b\x44\x03\x3a\xb6\x2f\x25\x8b\x4c\xfb\x98\xf7\x8a\xf5\xa9\x05\x4f\x89\xfe\x19\x0a\xba\x5b\x54\x86\x96\x25\x7e\x05\xff\x81\x6a\x04\x12\x47\x20\x0b\x18\x37\x59\x87\x0a\x7b\xa2\x27\xbd\xf2\x5e\xc9\x3a\x07\xfe\x58\xb2\xfe\xea\x64\xa2\x78\x3f\xf1\xe5\x95\x03\xde\x58\x31\xff\xca\xd7\x99\x3f\x84\x6d\xd9\x06\xda\x1a\x69\x69\x3b\x75\x77\xa1\x9e\x47\xdb\x67\x71\x96\x21\x3e\x03\x5b\xb9\x4c\x9e\x9c\x04\xe1\x34\x2e\xfe\x29\xbe\x93\x5a\x6c\xa1\x2d\x57\x4b\x6b\xb4\xea\xc7\x1c\x70\xd4\xc7\x74\xba\xc2\x72\x06\x33\x87\x19\x9d\x6d\x98\xd3\xf1\x86\x0c\x97\x21\xc4\x28\xa9\x79\x04\xf0\x93\x0b\x7f\x00\x9f\x2a\xc3\xf8\x4d\x7d\xd1\x01\x21\x6a\xfe\xc1\xcd\xb4\xee\x06\x20\x50\xc7\xd8\x7f\xd3\x32\xf0\xdf\x34\x07\xfd\x9b\xda\x88\x1f\x55\xa6\x09\x38\xea\xdf\x14\x43\xbe\x38\x4c\x41\x0b\x17\x50\x9c\x3e\x8c\x45\x53\x92\x04\x5e\xaa\xcc\xea\x02\x14\x68\xc9\xac\x42\xb8\x18\x48\x6e\x9c\xc8\xa9\x30\x10\x1b\xe0\x84\x3c\x6b\xc0\xb8\x38\x1d\x83\x12\xfd\x70\x99\xcc\x6a\x15\x29\x67\x6d\x58\x72\x32\xd3\x26\x70\x33\x9a\xc0\x79\xf5\x09\x5c\xb3\xea\x40\x73\x2e\x67\x6a\x26\xfe\x67\x75\x96\x4c\x15\x98\x37\x00\x85\x24\xf1\x13\x05\x47\x4b\xb3\x3e\x0d\xd3\xaa\xa8\xc9\x44\x13\x09\xe5\x58\xb6\x38\x03\xff\x04\xb3\x9d\x3c\xce\x16\x6b\x3a\x8b\xb8\xc0\x8f\x03\x96\x29\x80\xb4\xd0\xdf\x63\x7a\x27\xfc\x32\x11\x15\x7d\xfa\x3c\xb5\x7b\x85\x4e\xc8\x59\x5e\x63\x09\x5f\xe3\x7c\xdf\xa4\xa8\x8e\x70\x8c\xd3\x50\x0e\xe8\x68\xeb\x1b\x7d\xb8\xe6\x3e\x18\x96\xf8\xe5\x60\x8b\x97\x4f\xc9\x73\x9c\xe2\x57\x0d\x4f\x3d\x03\xe5\x9a\x2b\x60\xa2\x1e\x14\xd4\xab\xdb\x73\xda\xa8\xee\x19\xb5\x0d\x45\xc8\x12\x02\x1b\x77\x4b\x09\xe2\xf6\x1e\xc9\xfc\x17\x06\xa4\x96\xad\x2d\x4d\x63\xad\x4c\xb4\xda\xcf\x52\x37\xc0\xa5\xd9\x25\x1d\x6e\xd1\xac\x03\xf5\xe9\x80\xeb\x58\x23\x25\x97\x72\x7b\x9f\x8a\x69\x3d\xe0\xf5\x43\xea\x8a\xf9\xc2\x0d\xa7\xbb\xe3\x91\x2a\x86\xef\x76\x57\x0c\x18\x7d\xfd\x2d\x3d\x4f\xfb\xf8\xe7\x91\xa8\x88\xcc\xf0\x1e\x33\xef\xc5\x1b\xa5\xab\x6f\x85\x40\x72\xf1\x85\x90\x22\x3d\xba\x82\x99\xc0\xeb\x6f\x23\x2d\x61\x38\x43\x50\x09\x48\x9f\x86\xb8\x9c\x11\x82\x05\xc0\x33\xb5\xbc\xde\x0b\xe3\x62\x1b\x01\xe0\x87\xd6\xcc\x8e\x7b\x58\x8b\xfa\x57\xda\xdf\x75\x5d\x45\xaf\x41\x1c\x73\x11\x94\x8e\x77\xad\xce\x72\x21\x8d\x04\xa8\xf2\x39\x7e\xd6\x47\xff\xec\xb3\xe1\x5a\x26\xf1\x89\x1b\x50\x22\xce\x2c\x11\x18\xc5\x30\x23\x49\x2e\xc6\x8f\x33\xe8\xcd\x41\xb0\xcc\x9a\x89\xcb\xd7\xb9\x29\x84\x2a\x2f\xc2\x06\x01\x47\x4e\x4d\x82\xb8\x59\x41\x7d\xc0\x45\xe6\xe1\xa5\xd0\xe2\x69\x08\xf9\xc3\xa1\x2e\x2f\x4d\x2d\xde\x66\x95\xaf\x19\xc1\x2b\xb4\x6c\xcd\xdb\x50\xdf\x04\x20\xe7\x62\x47\x8a\xad\x35\x04\xa0\x1c\xf3\x15\x1a\x2c\xa1\xf6\x6d\x99\xb7\x59\xfc\x29\x4a\x2e\x7f\xe5\x34\x5a\x5c\xac\x50\x75\xe9\x90\x35\x7d\xdf\xe3\x5d\xe3\x43\x09\x95\x0c\xfa\xcc\x8e\x0a\xa8\x44\xc4\x38\xe4\x89\x36\xcb\x95\x47\xc4\xeb\x4c\x57\x48\x34\xf4\x27\xd6\x73\x2f\xf0\x3e\x67\x6d\xbf\x4e\x4b\xa6\xd5\xfc\xaa\x4e\x0f\xb4\xb9\xb2\x13\x46\xf3\xb8\xe8\x8c\xa2\x23\x2e\x8a\x16\x6e\x14\xa5\xd0\xee\xa5\x08\x8d\x9b\x35\xc3\xaf\x58\x89\xa1\x1f\x81\x20\x67\x66\x93\xe0\xa4\x5f\x81\xe0\x74\xd5\x22\x65\xa3\x6a\x5d\xd8\x22\x11\x17\x72\x45\x22\x5d\xd5\x51\x11\x94\x76\x3b\x08\x5e\x9f\xd1\xac\x08\x85\x7e\xea\xf7\x98\xeb\xbb\xe6\x45\xc7\xaa\x90\x3d\x66\x64\xa3\xdb\x02\x74\x96\x0c\x5b\x90\xbd\x3a\x9c\x61\xb5\x06\xcf\xfb\x47\xe8\xac\xd6\xa8\xda\xd6\xac\x6f\x5a\xb6\xf3\x86\x7e\x5f\xbf\x53\xde\xaf\x63\x97\x5f\x89\x33\xdf\xc3\xe0\x57\xef\xa5\x37\xd0\x18\x1b\x69\xf8\xe5\x97\x0a\x6b\x88\x7e\x27\x9e\xab\xdd\x94\x6f\xe6\x9b\x55\x2e\xd4\x2f\x86\x81\x43\x6e\x47\x72\x25\x5f\xee\x85\xe2\xd0\x5c\x5c\x9d\x55\x32\x28\xff\x2f\x00\x00\xff\xff\xf9\x31\x76\x63\x19\x8d\x00\x00") +var _resourcesPowerM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x7d\x7b\x77\xdb\xb8\xf1\xe8\xff\xf9\x14\xd8\xf4\x9c\x2d\x45\x51\x0f\x52\x92\x63\x27\xf5\x76\xd3\xdd\xe4\xfe\x7c\xef\x3e\xd2\xdd\xec\xf6\x9e\xa3\x92\x36\x49\xc1\xb6\x6a\x99\x54\x48\x29\x96\xeb\xfa\xbb\xdf\x99\x01\x40\x82\x0f\x50\x52\xda\xde\x9c\x13\x99\x04\x66\x06\x83\xc1\x60\x30\x18\x3c\xf8\x21\x7d\xe0\xd9\xeb\xd7\xdb\x3c\xbc\xe1\xec\x9c\xbd\xbc\x8a\xc2\x9c\x07\x7c\xb7\xbe\x62\xd7\xcb\x64\x91\x33\x4a\xb8\x62\x59\xb8\xcc\xf9\x82\x6d\x52\xb6\xb9\xe5\x6c\x8d\x58\x2c\xbd\x66\x57\x08\x39\x7c\xf9\xe6\x85\x65\xff\xba\xbc\x5f\xaf\x96\xd7\x8f\x2c\xe1\xf9\x06\x40\x21\x27\x4d\x78\xb2\xc9\xed\xde\x0b\x2a\x65\x2e\x7e\xc3\x4b\x27\xba\xbc\x48\x36\xfc\x86\x67\xbe\x13\x17\x8f\xec\xf5\x39\x0b\x03\x2b\xb2\xe3\xde\x9b\x26\xc2\x2f\x3c\x5c\x1d\x0e\xfd\xeb\xe3\x7d\x94\x1e\x01\xff\x4b\xb8\x59\xa6\x89\x28\xa1\x0d\xf4\x22\x01\x61\x2c\x37\x8f\x0e\x1b\x53\xf6\x45\xb2\xe0\x1b\x9e\xdd\x2f\x93\x70\xc3\x15\xd0\xe0\x20\xa8\x4b\x95\xeb\xb6\x10\x1f\x1e\x46\xbd\x03\xec\xb2\xc8\x6e\xa1\x3f\x70\x29\x67\x5c\xe6\x68\x14\x1c\x76\xd9\x49\xb6\x92\x6e\x86\x74\x1d\x16\x5e\x56\x19\x88\x2e\xff\xfc\xd3\xf6\x3e\xe2\xd9\x5f\x91\x8a\x60\x86\x20\xfe\x76\xbb\x8c\x6f\xe7\x2f\x18\xfc\x8b\xd8\x9f\x80\x3d\x87\x9e\xbf\x4b\x41\x93\xf8\xae\xe0\x5b\x02\x9c\x9f\x9f\x17\x20\x55\xce\x0b\x0a\x32\x77\xac\xa3\x74\x61\x7c\x53\xe6\xea\x65\x7d\xcc\xb6\x12\xe4\xb7\x04\xd4\x98\xc7\xa0\xcf\x12\x82\x53\x95\xfe\x02\x7d\xe2\x85\x5f\xd6\xaf\x56\xaf\x56\xc1\xe8\x52\x18\x1c\x22\x86\xf1\xe1\x15\x3f\x57\xc0\x06\xd1\xfd\xa9\xbd\x9e\x47\x08\x68\xfc\x85\x92\x91\xfd\xcf\x61\xaa\x8b\xcd\x13\x90\xd6\xe2\xd2\xa7\x9a\x47\x81\x65\x25\x83\x1f\xd3\xc5\x3c\x71\x16\x7e\x6f\xb4\xe8\x31\x1b\x13\x55\x0a\x26\x8c\xde\xb0\x9f\xb3\x79\x02\xac\x2c\x40\x70\xf4\xb7\x22\xf9\x41\x97\xe8\x2d\x9b\x00\xd9\x82\x13\x0c\x70\x80\xe6\xc8\xb2\xbf\x5f\xe6\x9b\x6c\x19\x6d\x37\x9c\x85\xc9\x23\xbb\x03\x53\x87\xe6\x4c\xd8\xb5\xeb\x34\x63\xc9\xf6\x9e\x67\xcb\x98\x7d\x0e\x57\x5b\x9e\xb3\x65\xc2\x3e\x2e\xef\x79\xfe\x1a\xb1\xad\xeb\x65\x96\x6f\x5e\x5b\xaa\x72\xec\x5f\x8c\xec\x13\xfd\x95\xd5\xec\xfd\xd9\xb2\xfe\xf0\xd5\xf9\xc0\xed\x7d\xdd\xc3\x4a\x2d\x93\x84\x67\x97\x97\xbd\x00\x8a\xb8\x44\x46\x89\x06\xbe\x41\x26\x91\x9e\x13\x88\x8f\x49\xc8\xf7\xcf\x60\x67\xb3\x07\x30\xba\x0e\x4b\x93\xd5\x23\x5b\x94\x1c\x2f\x65\xb1\xc4\x2d\xd5\x87\x88\x5d\x96\xc5\xc8\x72\x14\x7f\x07\x14\xa7\xf8\x66\xb9\x30\xe3\xcb\x38\x2c\xa5\xf5\xf1\x96\xe7\x9c\x6d\xc2\x3b\xce\xb6\x6b\xb6\x01\xf4\x21\xfb\x90\xe6\xf9\x32\x02\xc6\xe2\x34\xf9\xcc\xb3\x0d\x0e\x0d\xbf\xad\x85\xb8\x86\x85\xc9\x2f\x5a\x9d\xcc\xac\x5f\x98\xa0\x22\x3d\x72\xc2\xa2\x35\x1b\xc0\x5c\xd5\xe0\xcf\x50\x1a\xb4\xde\x67\x5e\x45\x0e\x03\xee\x44\x01\x2f\x08\x40\x27\x81\x02\x46\x1e\x41\x0d\x2e\xf4\x64\x95\x7a\xd1\x52\x58\x41\x1d\x4a\x2d\x4b\x2a\x71\xe4\x40\x21\x13\x6c\xf9\x1e\xc9\xb2\xaa\xc3\xc9\x0e\x34\xf2\x51\x1b\x4f\x54\x85\x65\x2e\xbc\x3f\xfa\x28\xef\xbf\x71\x76\x1f\x3e\xb2\x87\x30\x21\xc9\x2d\xf8\x3a\xe3\x20\x72\x90\xf2\xed\x92\xd4\xed\x3a\xfc\x9c\xd2\x10\x8b\xe3\xed\x0d\x87\xb6\x82\xc6\x29\xd5\x18\x45\x2c\x3b\xfb\x7c\xec\xb8\x7e\xc0\xf5\xd6\xfe\xf5\x61\xb9\x01\x93\x82\xdd\x08\xf4\x67\xea\x63\x97\x1d\x3b\xa2\x2f\x83\x30\x2e\xf0\xaf\xe7\x48\xa3\x32\xc1\x3e\x04\x4c\x29\x72\x19\xbf\x74\x96\xf7\x97\x7e\x90\xe8\x24\x81\xd6\x76\xc5\xe7\x4f\xc0\xce\x26\x04\x4f\xe1\x6d\x16\x7f\x0c\x13\x00\x06\x58\xff\xd9\x61\xbf\x7e\xca\x36\xf0\x16\x78\xfd\xe5\x7d\xe0\x01\xb2\xad\xe8\x7d\x97\xe6\xf3\xc4\x26\x3c\xdf\xf9\x75\x99\x14\x2f\x7e\x7b\xa1\xd4\x95\xfe\x7b\x25\x8a\x96\xa8\x19\xca\xfe\xa5\x3e\x3a\x5e\x06\xb5\xec\x56\xcb\xf2\xf1\xe7\xef\x7f\xb6\xe2\x34\x7b\x7c\x08\x57\x77\x3c\xeb\xbd\x66\xbf\xf0\xfb\xf4\xb3\x6c\xc2\x30\xc7\x96\xcb\x38\xcb\x6f\xd3\xed\x6a\xc1\x22\xb0\x34\xec\x3e\xcd\xca\xc6\x84\x5e\x93\xcb\x96\x7c\x47\xdd\x55\x55\xfc\xa7\xf9\x3b\xd9\x2f\xdf\x05\xd6\x0f\xe9\x0d\xa8\xa8\xdf\xcf\xc0\xab\xc2\x8e\x4d\xde\x09\x28\xe1\xbb\x00\x53\x10\x44\x42\x50\xc6\x9b\x17\x6f\x37\xd2\x4c\xe4\x42\x23\x7d\x90\xdc\xd3\x0f\x60\x3c\xc2\x68\x05\xba\xf0\x93\xb0\x6b\xef\xb7\x49\x8c\x6a\xe4\xb0\x9f\x13\x7e\xb1\x00\x37\x8d\x1c\x84\x0f\x59\xba\x21\x9b\xfe\xfc\xe6\xc5\x47\x20\x9f\x5f\x09\xf3\x09\x24\xc8\xe8\xbf\x23\x27\x8f\xbf\xdb\x85\xf8\x27\x17\x63\x16\x65\x80\xc0\xee\x81\xca\xfc\xe5\x3b\xe5\xf6\xa1\xee\x4a\x4b\x05\xd2\x80\x7a\xc7\x20\xd3\xad\xf0\x0c\xc3\x78\xb3\x7a\x7c\xfd\xd2\x77\x4a\x02\xbf\x86\xf7\x1c\x8b\x84\xde\x3a\x72\xbd\x99\xc3\xac\xc1\xac\x17\x0c\x26\x3a\x4c\x51\xc8\xfb\x55\x0a\x3d\x2c\xb9\x01\x13\x08\x45\x94\xae\x26\x95\x73\x1b\x26\x8b\x15\x14\x03\x7d\xe0\x96\x5d\x57\x21\xb1\x97\x2d\x51\xea\xb5\xc2\x41\x66\xc9\x0d\x15\xff\xd2\x1d\x9e\x9d\xcd\xc6\x27\xbc\x3f\x19\xbb\xe3\x97\x0e\x7b\x39\x9c\x05\x03\x77\x0c\xff\x86\x2f\x5b\x99\x79\xbb\xdd\xa4\xf7\x50\x48\x1c\xae\xc0\x1c\x86\xeb\x35\xfc\xe6\xe9\x3d\x67\xe0\x39\xc3\x08\x52\x35\xa8\x2c\x03\x9d\xce\x0d\x55\xbf\x0f\xa6\x43\xa8\x38\x68\xf3\xb0\x07\x1a\x4d\x10\x60\x42\xde\xbd\xdf\x66\xa8\x4b\x7b\xc4\x9e\xf1\xc5\x36\x56\xd5\xcf\xa1\xaa\x29\xb4\x38\x31\xa6\x0b\x28\x06\x8d\x5d\x40\x65\x1b\xf2\xd7\x44\x50\x51\x75\x14\xc1\x38\x18\xb7\x73\x5c\xf7\x37\xd8\x38\xb0\x60\xcc\x2b\x59\x27\x2d\x2a\x19\x86\x5e\x03\x09\x34\x9b\xc0\x46\xe1\xc8\x75\x8e\xed\x91\xab\xa9\x05\x0d\x54\x62\x68\x83\x8e\xd1\x2c\xd1\x65\x7d\x06\x66\xd4\xda\xf5\xdd\x5e\xe0\x9a\x6a\x30\x16\x5c\xbb\xc6\x2a\x42\x63\x22\xc4\xb0\x0e\x52\x68\x21\x68\xe0\x60\x56\x2b\xa0\xcc\x1c\x52\xf6\xd0\x04\x50\x65\x72\xb8\x8f\xcb\xe1\x01\x6c\x0e\xcd\x7c\x52\x4f\xa9\x95\xd2\xc6\x2a\x42\x1c\xd1\x12\xff\xe4\x59\xda\xd2\x10\x7a\x57\x41\xe6\x44\x25\xc7\xff\x86\x32\x75\x02\x0f\x4d\xaa\x47\x83\xfd\x2c\x18\x1b\xfb\x31\x31\x87\xa2\x31\x17\xa7\x60\x86\x07\x40\x89\x6a\x9a\x9b\xaa\xad\x9e\xc7\x40\x0f\x1b\xe0\xf5\x9a\x1a\xf5\xa8\x52\x8d\x3d\x44\x3a\x69\x9c\x9d\x09\x31\x18\x40\xbc\x19\x02\xcd\x82\x49\x7b\x11\xd2\x70\xcf\x6a\x56\x5b\x63\xa1\xb0\xeb\x26\x80\xba\xe9\x6f\x67\xc4\x1b\x9e\xbd\x9a\x4d\x4e\x79\xdf\x9d\x9d\x9e\x21\x4b\x93\xb3\xe0\xec\xec\xcc\x2c\xed\xc9\x70\x72\x32\x3e\xf3\xf8\xc0\x9d\x9d\x8d\x25\xc2\xa0\x13\xe3\xd0\x51\xe0\x30\x9c\x0e\x99\x22\x9c\xdb\x61\xa8\x24\x80\xb7\x0f\x60\x8f\xfa\xba\xc0\xc9\x5e\x88\xbd\x85\x9c\x89\x7f\x1d\x70\x43\xc9\x6e\x97\x94\xaa\xb4\xf6\x42\x0e\x83\x89\xb9\x72\x53\x82\xb1\xdc\xa1\xed\xd9\x2e\x8e\x9a\x66\xed\xc7\x81\xc9\x3c\x62\xc8\x3e\xe4\x36\x48\xb4\xc2\xec\x35\x29\x4d\x98\x06\x2b\x83\x03\x78\xd9\xd7\x24\x04\x74\x60\xab\x00\x2c\x08\xe8\x40\x59\x0e\xba\x84\x39\xc6\x31\x45\x83\xa3\x21\xbf\xa2\xe1\x0a\x54\x4d\x84\x1c\x39\x01\xf2\x84\x9b\x3d\x1a\xb1\xff\xe1\xe1\xa2\x95\x7a\x11\x31\x28\xe2\x49\x47\x62\x40\x19\x5e\x37\x42\x9d\xab\xc1\x01\x6c\xb5\xd5\xa4\x52\x8c\x36\xb2\x2a\x1f\xb8\x65\x32\xdd\x24\x0c\x4e\x9f\xc3\xc0\xe5\xb3\x71\x12\x63\xf0\x0a\x85\x53\xd8\x33\x00\xc8\xbc\x61\x01\xd5\xee\x0a\x28\xbf\x52\x73\x31\xdb\x01\x6b\x6e\x68\x6b\xc3\x9a\x1c\xbf\x56\xe0\x27\x17\xa6\x6b\xbf\xf0\xf5\x2a\x8c\xf9\xdb\xd5\x0a\xa7\xd2\x61\xb0\xbe\x1c\xb2\xc1\x37\xec\x69\xfd\xec\xb7\x63\xc1\x84\xd5\x03\xa2\xaa\x88\x5e\x2b\xaf\x63\xec\x4c\x5e\x6f\x2f\x5c\x2d\xd4\x49\xfd\xe6\x58\x9c\x2f\x40\x59\x1c\x82\xa2\x44\x08\xb5\xed\x06\x6d\x08\x5d\x54\xfd\x0b\x6a\x7e\x7c\xc5\x8f\xaf\xb7\x8e\xa1\x75\x0e\x46\x7e\x67\xb2\xb9\x1d\x64\x69\xba\x61\xe1\xea\x26\xcd\x60\xa6\x76\x3f\x64\xad\xdd\x03\xfa\x99\x7b\x12\x58\xee\x68\xda\x5e\x32\xaa\xb3\x04\x18\xb6\x43\x50\xcc\x92\x7a\xe9\xdc\x1d\xbb\x08\xe9\xf5\xfc\xf3\xaf\xce\x8b\x35\x88\x6e\x1c\xf0\x89\x0e\x42\x19\x53\x1f\x20\xc8\xb6\xec\x53\x6c\xdf\x76\xb7\x47\x61\x4e\x8c\x2a\x3e\xee\x12\x80\xc3\x4e\x3b\xb0\xc9\x5a\x39\xec\x95\x00\x19\x8d\x8c\x06\x4e\x02\x9e\xed\x05\x84\x2a\x0a\x91\x0f\x8c\x3c\xb5\x5b\x07\x13\x8b\x06\x68\x83\x20\x81\x0c\x88\xf2\x55\x17\xc1\xb2\xce\x83\x83\x2b\xbd\x0f\xd2\x7b\x45\x60\x13\x33\x5b\x12\x62\x20\x41\x1a\x2a\x2f\x07\x83\x47\x9c\x6e\x65\xe1\x02\xe3\x05\x79\xbb\xce\x4f\xd1\x14\x20\x3f\xd8\xf7\xbc\xd3\x5e\x47\xf3\x4e\xa5\x0d\x90\xd0\x83\x3d\xe0\xee\x0c\xa5\xe2\x41\x36\x9b\xbd\x52\x58\x67\x53\xef\x64\xf2\x6a\xf6\x9f\x47\x9b\xb0\x49\xc1\xd9\x24\x98\x76\x31\x56\x01\x05\xc0\xe9\x51\xac\x00\x75\xc2\xb0\x67\xd8\x42\xf0\x57\x82\xd8\xae\x54\xe7\x23\x68\xcd\x6c\x45\xac\x4e\x64\x1f\xe3\x93\x0e\xb6\x0f\x04\x0b\x45\x1e\x8e\x8f\x66\xa0\x81\xb0\xe1\x45\x93\x77\x89\x4b\x64\x7b\x1a\xe8\xa0\x83\xee\x05\xa8\x2e\xc2\x4d\x7b\x5d\x3d\xb0\x7d\x2c\x75\x47\x63\x83\x94\x87\x04\x33\xc4\xb9\xe9\x0c\x1d\xa6\x8b\x7b\x09\x87\x01\xa2\xff\x93\xa4\x0f\xc9\xfb\x70\xb9\xda\x66\x95\xc8\x56\x59\x83\x49\xff\x42\xc4\x7a\xbd\x33\xbf\xc7\xde\x41\x51\x96\xe5\xb1\x0b\xf6\xf7\xf9\x87\xa5\xdf\xc3\xc6\x05\xfa\xd6\x84\xf5\xd9\x85\x5d\xc0\x05\x93\x2e\x6d\x7b\x7a\x1a\xcc\x1c\x77\x24\x75\xf7\xd9\x79\x1a\x4c\xe1\xd5\x13\x82\xc2\xd7\x09\xbc\x4e\xca\x5c\x4f\xe4\xaa\x57\xd7\x01\x87\xe6\x69\xec\xd4\x0c\x17\xa4\xb9\xce\xa0\x94\x38\xbc\x7b\xf0\x5e\x26\x28\x1a\x98\x33\xa9\xe6\x4c\xca\x9c\x29\xd2\xa0\x81\xa4\xa4\x33\xab\x42\xcf\x14\x34\xf8\x55\x1f\x31\xb0\x3b\x7f\x4a\x50\xc8\x49\x4f\x1a\x32\x48\xc7\x14\x8c\x0e\xcd\x9e\xc9\x4b\xfd\xeb\x76\xc9\x37\x4a\xee\x2f\x9e\xdf\xbc\x78\xf1\x43\x7a\xa3\x2f\xfc\x63\x18\x99\xfb\x6a\xd9\x1f\x03\x40\xd0\xbc\x5b\x0c\x54\xaf\xd2\x9b\x90\x86\x68\xb1\xe2\x4f\xeb\xfd\x08\x5d\xac\x0f\xfc\xf9\x27\x7e\x13\x16\xcb\x33\x17\xf6\x87\x25\x34\x06\x42\x0c\x12\x5f\x80\xd6\x24\x25\x97\xea\xc4\x8b\x80\xe8\xc8\x1a\xec\xc7\xae\x2f\x02\xea\x79\x63\xb9\x1c\x54\x49\x2c\x62\xfd\xf8\xf2\x4e\xad\x57\xd3\x0b\x78\xa6\x6a\xa5\x96\xd2\xd7\x22\xbd\x58\x30\x72\x71\x71\x4a\xd0\xa4\xd0\xbb\x5f\x09\xba\x43\x52\x35\xe4\x5e\x8f\xb8\x37\x63\xec\x80\x72\x40\x84\xbd\xec\x4f\x0e\x13\x4c\xb7\x77\x62\x4f\x66\x07\x38\x30\xb4\xc3\x60\x3e\xf8\xf5\x4c\xfc\xf5\x35\x9d\xc0\xfe\xa3\x2b\x05\xf5\xa7\xaa\x56\xe4\x9f\xb6\x18\x65\x27\xe7\xad\xd4\x07\xb1\x1c\xf2\x9a\x85\x95\x60\xb8\x1a\xf2\xd8\x9a\x67\xd7\x50\x69\x89\x8c\x13\x21\x4d\x64\x58\xc8\xbe\x65\x0a\x5d\x6a\xc4\x54\x68\x52\x3e\xca\x1d\x60\xab\xc8\xa7\x6a\x6b\x4a\x80\x22\xbf\xa0\x63\x47\x97\x1f\x56\xdb\x9c\x80\x28\xe7\x6d\x94\x03\x98\x2f\xe0\xad\x70\x24\xde\x7b\x76\xe4\xe3\x9a\x74\xc8\xbe\x22\xfd\x91\x44\x70\xed\xa6\xba\x4a\x19\x06\xc3\x99\xcc\xde\x5d\xd6\xd7\xf9\x2d\xfb\xa7\x34\xbb\x27\x19\x3d\x70\xf6\x40\x2b\x44\xb4\xb8\x87\xab\x47\xb8\xd8\xba\x58\x66\x1c\x17\x49\x1c\x06\x32\x62\xd9\xf2\xe6\x16\x7c\xe6\xf4\x81\xbd\xdc\x5d\xbe\x64\xcb\x9c\x88\xc4\x30\xa5\x5c\x2e\x78\xc6\x17\x62\x61\x29\x5f\xf3\x18\x27\x9b\x40\x22\x4c\xd8\x98\xa5\x19\x73\x0b\xaf\x7a\x77\x7e\x7e\x8e\x9e\xa4\x53\xbc\xb9\x8e\x5a\xdc\x17\xde\x2e\xdb\x09\xf7\x15\x97\xef\x85\x62\x22\xf3\xc7\x68\x26\x55\x16\x7c\x5c\x26\x1f\xda\x47\x0f\x99\x0d\x13\xee\xf6\x7c\x66\xb3\x2a\xa1\x81\x81\x92\x2b\xf3\x0d\x84\xc6\x32\x7b\xec\x1b\x97\x23\x6a\xac\xc3\x7c\x5e\x14\xe8\x0d\x76\xc1\xa3\x2f\xe6\x57\x16\x3c\xf6\x3d\x70\x0d\x49\x4d\x75\x03\x7a\xa1\xf7\x94\x8b\x2b\x68\x16\xea\x20\xcb\xfb\xf0\x06\x86\xc6\xec\x11\x37\x11\x80\xde\xb1\x0c\x17\x77\x73\x5c\x63\x03\xcf\xef\x4a\x55\x9e\xba\xcd\x05\xea\x45\xb9\x8e\xcb\xdc\xaa\x31\xb9\x10\xdd\x22\x8d\xef\xf8\x42\xeb\x03\x38\x99\x0e\x17\x4d\x43\x72\x71\x4c\x63\x61\x1c\xea\xc2\x10\x51\xa0\xac\xa9\x6e\x18\xd6\x62\xb9\x9f\x17\xcb\x7b\xa5\xf5\x77\xd8\xbd\xbe\xcd\xea\x05\x7b\xbf\x0a\x37\x1b\x9e\xcc\x3f\x80\x8f\xb0\xdd\x88\xd0\x07\x1b\x7d\x0b\x83\xf4\x87\x70\xf1\x0b\xaa\xf2\xfc\x0f\x80\x04\x83\xf9\xd7\x90\x2c\x8a\x97\x04\x3e\x84\xd9\x46\x6c\xd3\x98\x27\x04\x22\x44\x72\xc3\x93\xdf\xc3\x0c\xba\xdf\x62\xc1\xc1\x0e\x5d\xa2\xa1\x70\xca\x55\x2d\x7a\xa7\x2e\x46\x5b\x1b\xbe\xfd\xd6\x92\x80\x2c\x28\x81\x7a\x44\x06\xf8\x0f\x93\xc5\x5e\x42\x2f\x18\xda\x82\x6f\xbf\x15\x83\xab\xf5\xe3\x76\x05\x8d\x97\xde\x2f\x61\x34\xfc\xf6\xdb\x12\x7e\x3e\x17\xf4\x7e\x4b\x96\x9f\xb6\xfc\x6a\xe9\x83\x79\xc0\xfa\xd4\xf8\x75\xba\x30\x40\xcd\x9e\xaa\x69\xaa\x5f\xfe\xc0\x93\x9b\xcd\xed\xbc\xc0\xf5\x9f\x41\x14\x9c\x40\x7f\xc1\x55\x44\xac\x30\x36\x77\x4e\x86\xab\x5c\xae\x2f\xec\x10\x7b\xfd\x0d\x49\xb7\xac\x37\xd6\x0f\x6b\x00\x2c\xb5\xb4\xa8\xa3\x8a\xcc\x7d\xd1\xa5\xe2\x4b\x5b\x10\x07\x4a\xd0\x7c\xb1\xfd\x07\x68\xb3\x1e\xb6\x65\x8e\x5a\x21\x88\xea\xbd\x40\x16\x83\xab\x49\x30\x68\xa0\x1a\xdc\xaf\x37\xb4\xa2\x24\xf8\xa6\x0d\x83\x19\xa9\xbe\x6a\x09\xb9\x72\x0d\x3e\xca\x90\x69\x95\xd3\x00\x1c\x26\x0d\xa8\xf5\x21\x5b\xca\xc5\x4e\xa4\xb5\x48\x41\x06\x09\x0c\x43\xf9\x76\xbd\x4e\xc1\x54\xe5\x1c\x4c\xe2\x82\x85\xd9\xcd\x16\x57\x45\x87\x2f\xfd\x37\x8a\x88\xdf\xab\x74\x2c\x91\x4c\xbd\xab\xd9\x8d\x24\xf9\x23\xfa\x52\x18\xa0\xfb\x39\x01\x9b\xef\xe1\x06\x26\xf1\xcc\x22\x78\xeb\xc3\xaf\x9e\x17\xc3\xf3\x09\xe6\xd1\xd3\x84\x60\x6c\xf9\x1c\xb2\x98\x30\x26\x98\x4b\x4f\x71\x00\x73\x5d\x59\x05\x2b\x44\x62\x98\x88\xcb\x27\xed\xb3\x07\x22\x24\x48\x87\x6c\x41\xcf\x0b\x7a\xe6\xf4\x8c\xce\x3a\x51\xc1\x1d\x49\x16\x42\x61\x2e\xef\xa1\x7f\x28\x25\xd2\x4e\x76\x21\x6a\x22\xff\xc6\xf2\xaf\x47\x85\x70\x7a\x8a\x8a\xa7\x58\x3e\x41\xa1\x12\x8b\x4b\x2c\xf8\xab\x18\xa0\x6a\xd8\x96\x28\x1e\xb2\xf7\x30\x00\x6e\x2f\x32\x4d\x45\x06\x11\x0a\x2c\x58\x90\x78\x20\x7d\xd1\xd3\x44\x14\x10\xe5\x60\x81\x71\xcb\x76\x52\x23\x12\x0b\xfd\xc6\xa3\x45\x9b\x74\x47\x0b\xc3\x70\x43\x48\x50\x62\xd8\xa3\x27\x68\x50\x13\x31\xa2\x86\x4b\x09\x7b\x89\x4a\x39\x3a\xcc\xb3\x25\x92\x26\x8b\xfd\xc3\xd6\x4f\xdb\xd5\x0a\x67\x3f\x27\x63\xd2\x22\x5b\x69\x60\xe0\xa1\xb4\xac\xc9\x31\xc9\x61\x30\x23\x75\x9d\x91\x08\xf1\xd7\x9a\x21\x0c\x41\x4c\x7b\xfa\x7b\xac\xbd\x47\x44\xa7\xfa\xae\xe7\xc7\xb5\xfc\x58\xa3\xe7\x8e\x35\x26\x26\xf5\xa4\xb8\x9a\x34\xd1\x6a\xa0\x25\xc5\x7a\x52\xd4\x44\x8c\x2a\x50\xde\x58\x55\x49\x83\x2b\x12\x63\x8d\x11\x4a\x8c\x8a\x0a\xc0\x6c\xeb\x8d\x39\x1e\x65\x59\xae\x9a\xa5\x4e\x60\x5c\x03\x3f\x0a\xf4\x44\xcd\xf6\x60\x5e\x5d\x64\xe9\xe9\x3d\x78\x9b\x30\x39\xeb\x04\x07\xa3\xd2\x03\xc4\xb0\x2b\x92\xde\xae\x56\x4d\x23\x8b\x81\xf4\x7d\x76\x16\x72\x18\x38\x99\x6c\xc5\x3f\xf3\x55\x5e\x5a\x5d\x0a\xc2\x0b\x9b\xfa\x63\xb8\x96\xd6\xd0\x41\x35\x84\x59\x6d\x31\x7d\x7a\xf6\x5b\x6c\x26\xa0\x76\x9a\x4d\xc8\x3f\xc6\x72\xd2\xe4\xcd\xed\xef\x02\x35\x1f\xa1\x75\x76\x6b\x87\x6b\x09\x4a\x22\x58\xa4\x2e\x94\x0f\xe9\xea\x51\x0c\xc6\x7f\x2d\xc5\x02\x72\xd1\xd2\x71\xdb\xdb\xe7\x10\x65\x93\x71\x98\xc4\x82\xff\x81\x3e\x2e\x5b\xd2\x7c\x05\x1d\xb5\x10\xc6\x3f\x05\x8d\xdb\xed\xae\x00\x9a\x86\x25\xda\x16\xa9\x53\x5a\xd3\x00\x08\xe4\x2e\x85\x63\xc0\x80\x1d\x24\x56\x8c\xa5\x6b\x68\x7e\x1d\x01\x7c\x9b\xcf\xe8\xdb\xf8\xad\xc4\x86\xf6\xe7\xcb\xe0\xe7\xb5\x9c\x4b\x42\x2b\x95\x7b\xe1\xcb\x22\x2e\xae\xe7\xef\x33\xce\x01\x1e\x69\xb1\xaf\xbf\x66\x6a\x48\x47\x0c\x80\x14\x1e\xfb\xfb\x70\x95\xf3\xf6\x62\x14\xb1\x1a\xa9\x3a\xa6\x01\xa9\x49\x50\xb5\x05\x12\xa1\xdd\xfe\x9c\xdf\xd3\x2e\x22\xb6\x4d\x16\x69\x4c\xe3\x2d\xcc\x43\xe4\x9e\x36\xb1\xf7\x2a\x49\xb1\x0d\x96\xe8\x42\x15\x73\x13\xf2\x06\x5f\xd3\xfe\x50\xbd\x64\xb9\x47\x52\x4b\x72\xd8\xef\x12\x37\x9f\xaf\x7d\xbf\xb6\xb1\xad\x00\x34\xe8\xa2\x06\x51\x6a\xa3\xd1\x8a\x0a\x99\xe8\xc5\x7b\xa0\x90\x83\xc9\xae\x0f\x03\xd6\xae\xdd\x70\xb7\xe3\x18\xc1\x49\xe0\x4d\x78\x5c\x48\x3d\x0a\x63\x70\x24\x47\xe3\x23\xe9\x3f\x1e\x41\x1e\x04\x74\x0c\x33\xc7\xc0\x3e\x76\x88\xb2\x8d\x11\x33\xdb\x06\xc1\x53\xe3\xf6\x71\xa3\xe8\xce\x3f\x06\xf7\x78\x0c\x55\xda\x17\x62\xee\xec\x3d\x88\x06\xe5\x15\x78\x8f\x47\xe1\x0d\x67\x4a\x32\xa8\x97\xf0\x73\x54\x89\xa2\xbb\xbc\xbc\xe5\xab\x55\xfa\xf2\x0b\x30\x1f\x0f\xc5\xd9\x1d\x01\xfb\x78\x04\xac\x67\x9b\x29\xb7\x35\x8f\xbd\x0b\x70\x73\xf1\x51\x32\x16\x08\xf6\x91\xa6\xa2\xc4\x3a\xce\x60\x14\x78\xc7\x74\x6b\xcf\x3e\x46\x68\x8f\x1d\x42\x33\x40\xff\xf3\x70\x68\xac\x00\xea\xbe\x01\xa5\xa5\xca\x8f\xc1\x51\x8d\x48\xa2\x39\x5c\xf3\x10\xfa\x60\xf6\xa1\xb1\x44\x43\x1f\xd3\x93\x10\xa7\x03\xc3\xa0\x87\xb4\xe7\xe5\x18\x35\x3f\x18\xfa\x18\x58\xb2\x54\x36\xf6\x07\xf5\x74\xb8\x60\x3d\xc7\x1b\x1e\xd1\x6a\xa1\x13\x1e\x01\x9d\x38\x87\x8f\x25\x85\xe1\x3c\x18\x85\xb4\xc2\x10\x84\x6c\x42\x5b\x03\xef\x74\x6c\xc3\x0c\xc9\x86\x59\x34\x36\x1d\x4c\x36\x06\x13\x77\x06\x49\x27\x32\x69\x0a\x49\x67\xf0\x0e\x73\xc2\x93\x89\x2d\x26\xdb\x67\x63\x4a\x28\x71\x26\x33\x8d\xc8\xb4\x9c\x3f\x1c\xce\xf7\x7f\x8b\x93\x92\x83\x83\x16\xf8\x5a\x35\xb4\x18\x15\x8e\x51\x6b\x42\x32\xa2\xb4\x69\xc6\xe8\xb1\xb2\xfc\xa1\x62\x61\xb5\xd9\x16\xa5\x91\x03\x5d\x99\x52\x60\xb0\x77\xc1\x6f\xc0\xbb\xa6\x85\x90\xf5\x95\x70\x7b\xa1\x9a\x78\x30\x4e\x6d\xa3\x2e\x5c\xe0\x62\x8a\x51\x50\xc4\x39\xda\xe5\xa8\x98\x60\x84\x19\x78\xe0\xb7\x3c\x5c\x08\x77\xb8\x02\x46\xd9\x22\xd7\xaf\x53\x68\xa2\x82\xd3\x8f\x39\x74\xbc\x6f\x2c\x32\xe6\x24\x13\x75\xa6\x06\xab\x26\xc9\xc2\x93\x20\x0d\x0f\x08\xe8\x20\xd7\xdf\x85\x39\x07\x96\x36\xe9\x77\xb7\x3c\xbe\x7b\x26\x71\xca\x17\x89\x59\x86\x29\xde\x54\x33\xa1\x6c\xda\x37\x23\x53\x7c\x62\x42\xd4\x50\x26\xc1\x2c\x53\x11\xf6\x05\xb2\x2c\x90\x9d\x53\x5b\xd0\xf3\xbc\x00\xa6\x39\x53\x75\xca\xe4\xe3\xce\x31\x9c\x09\x21\x17\xdf\xf3\x15\xdf\xf0\xef\xb7\xeb\x15\x4e\x2f\x30\x72\xc8\x68\x06\x25\x63\x99\x8a\x38\x30\xf2\xd5\xb9\x0a\x70\x2a\xe6\x30\xa8\xce\xd7\x3c\x59\x7c\x4c\xe7\x65\xb5\xc7\xbe\xe0\xeb\x16\xa7\x77\x2a\x19\x13\x7c\x83\xec\x8d\xed\xf5\x63\xb8\x6b\x4c\xa2\x09\xa8\xb6\xde\xd5\x3a\x9b\x16\x7b\x08\x8f\x38\x7b\xf3\x1e\x8f\x31\x56\xb5\x52\x9f\xe7\x1a\x4e\x9d\xcc\x9c\x92\x75\x0c\x55\xee\x28\x60\x79\x07\xdd\x49\xf8\x1a\x45\x4f\x3e\xe0\x18\xca\x97\x71\xf0\x34\x76\x26\xce\xec\xb9\x93\x0f\x87\x51\x6c\xbe\xe3\x64\xc9\xaf\x69\x46\x2b\x2c\xf2\xcc\xdc\x32\x59\x6f\x37\x2c\x5c\x2c\x68\x3d\x41\x3b\xe0\x80\xd3\xff\xf4\xfa\x9a\xe1\xe9\x2c\x87\xe5\x29\xae\xc0\xe5\x80\xab\x6d\xc5\xb1\xf0\xbc\x18\x76\xe4\xed\x6a\x83\x10\xcb\x8d\x08\x36\xdf\x87\x9b\xf8\x96\x6d\xd7\xc3\xd6\x6d\x3b\xa2\x1a\xce\x2e\xd8\xd5\xab\x22\x9d\xe2\xa2\x52\x21\x56\x8a\xde\x76\xe8\xae\xa8\xca\x8d\x46\x58\x07\x83\x88\x74\x9a\xae\x86\x1b\x14\xa2\xd9\x8f\x87\xd6\x3a\xd4\x84\xb9\x1f\x63\x2f\xb4\xa7\x43\x0b\xb7\xb6\x13\xde\xad\xc1\xb3\x01\xdb\x89\xd0\xe7\xae\xb7\x97\x33\xa7\x82\x6d\x91\x18\x28\x88\x76\x18\xb6\xd7\xc4\x0e\xbc\x23\xf0\x3b\x4a\x0f\x26\xfb\xf1\x2b\xd8\x0a\x8b\xb6\xcd\xee\x43\x1d\x4c\xaa\x52\xb3\x06\xfb\x8b\xab\xe2\x84\xa3\x1d\xae\x25\xec\x41\xf1\xea\xc5\x78\x7b\x8b\xa9\xca\x04\x14\xfb\x18\x89\x54\x25\x8a\x02\x8d\xec\x9d\x68\x16\xd0\x0b\x0b\x14\xc3\x15\xbd\x05\xdc\x9b\xfd\x7a\xdb\xa4\xd6\xa4\xe5\x11\xad\xbd\x5a\xaa\x13\x1a\x1f\x0b\x8c\x6e\xcb\xe1\xe0\xe3\x86\x65\xdb\xeb\x31\xb5\x56\xb5\x30\x07\x41\xcd\x56\x2a\xcf\x46\x9c\x0f\xfc\x15\xa3\x76\xfc\xbb\x94\x5f\x5f\x2f\xe3\x25\x62\x2f\x93\x0f\x30\x8c\x2d\x93\x8f\x3c\xbb\x57\x01\x48\xe5\x27\xac\x19\x06\x03\x3f\xc0\xd0\x0d\x99\xf4\x8c\x50\x30\x26\x87\x1b\xe1\x14\x58\x36\x8c\xb4\x3f\xa2\x59\xc4\x98\x1d\x42\xf9\xce\x2f\xe4\x1f\xe1\xb2\xfc\x1b\x61\x27\x01\x5a\x38\x06\x82\x0a\xdd\x39\xc0\xe4\x5a\xde\xdf\xc2\x2c\x01\x96\x5e\x8b\x12\xc0\x76\xbb\x6c\x9b\xf3\xc5\x4b\xff\x0d\x0b\xb5\x1b\x13\x8a\xe1\x3f\xbc\xf4\x6d\x2a\xe6\x8d\x28\x1e\x68\x9f\x37\x32\x65\xb9\x3a\x6b\xc8\x84\x6c\x0f\x6b\xdd\x63\xa3\x21\x71\x05\x6e\x44\x88\xe3\x3d\x0d\xee\x6f\x4a\x29\xfd\x94\x26\x30\x24\xaf\xbf\x48\x36\x9b\x94\x0a\xd5\x84\x24\x53\x00\x66\x5d\x73\x9b\x84\x64\xde\xed\x62\xbe\xde\xcc\x1b\xd5\x08\x92\xcb\xa1\xaf\xdc\x19\xe9\x54\x11\x25\xcd\xa9\xa2\x1a\x89\xc5\x6a\xe5\x37\x95\xc5\xcb\x0a\x97\x72\xa8\x66\x96\xac\xca\x3d\x12\x74\x20\xbb\xd0\x8c\x4a\x70\x5d\xd7\x18\x90\xe6\x75\x0a\x4d\x50\x75\x85\xe3\x12\x02\xdb\x11\x21\xd8\x15\xfe\x5e\x61\x80\x5d\x0b\xb7\x5f\x89\x2b\x63\x2a\x14\x0b\x27\x56\xb8\x77\xaf\xcf\x15\xe3\xf0\x2e\xdd\xd8\xb2\x23\xd4\x5b\x49\x7a\xe6\x25\x44\x8d\x59\xc8\xc4\x2b\x6d\x64\x7f\xa8\x96\xfc\x6f\xb4\xf0\xbe\xc6\xdd\xd3\x68\x72\xe5\xc5\xd4\x2d\xff\x20\x8a\xf5\xd9\xd7\x45\x81\xb2\x86\x1d\x48\x45\x83\x12\xaa\x6a\x53\xcd\xff\xd4\x80\xf7\xba\xa0\x1a\xec\x31\x4b\x3a\x13\xa7\x22\x7f\xb9\xe2\x8c\xa3\x4f\x68\x47\x81\x77\xc8\x6e\x9c\x7f\x54\x49\xe0\x4a\xf5\x3f\xec\x90\xbc\xc1\x08\xc8\x18\x96\x76\x9b\x48\x77\x34\x9a\xa0\xb7\x25\xc6\x3e\xc3\xba\xb9\x37\xad\xa2\x7a\x76\x64\x5b\x1e\x15\x38\xb1\xa3\x9e\x1a\x39\xd4\x7b\x51\x91\x56\x5a\x67\xb5\xea\x7b\xe4\x26\xd0\x44\xd9\x9a\xc9\x67\x62\x66\x6c\xdc\xd5\xa4\xe3\x87\xe2\x28\xb1\x61\x52\xff\x05\x8c\x1f\x54\xaa\x70\xe4\x4c\x75\x1c\x84\x0d\xe8\x9a\x1b\x67\xc0\xb3\xdc\x51\xd8\xeb\x47\x55\xec\xfd\xc3\xbe\x69\x3d\xde\x6b\x12\xea\x1a\xf1\x0f\x52\x9b\xd0\xd9\x39\x86\x96\x09\x59\x8d\x73\x90\x66\x27\x74\x3f\x0e\x16\x0d\x0c\x4a\xfc\x22\xac\xfe\x6c\x67\x46\x1c\xd7\x7b\x9d\xc0\xe9\x61\x54\xa4\x40\xd4\x1c\x02\x0d\x18\x6d\x80\xc9\xd6\x63\x5e\x7b\xe4\x63\x85\xcb\x9f\x60\xe7\x35\xb3\x8f\xb7\x5e\xe4\x69\xbc\x0c\x37\xea\xfa\x85\x66\xf0\xa3\x41\x5b\x9b\x42\x13\x7b\x62\xcb\x55\xd5\x82\xe3\x5c\x7a\xe9\x3b\x4f\x4b\x67\xec\x68\xf1\x18\x64\xea\xd9\x68\xdf\xc4\x5e\xae\xd6\xe5\xc1\x1a\xd4\x31\xd6\xed\x29\x92\x73\xd5\x7a\x45\xa2\xfe\x64\xd7\xc7\x05\x14\x53\x00\x0e\xbc\xb6\x71\x2b\x66\x27\xd2\xc0\x0a\x47\xd0\x73\xdd\x51\xd4\x82\x69\x0d\xc2\x3e\x38\xdc\x91\xb3\x3b\xc4\xaa\x12\xeb\xed\x2c\x28\xe6\x27\x46\x3e\x00\x02\x3c\xdb\x19\xfa\xf5\x9d\xf8\x86\x58\xfa\x53\x81\x4d\xae\xab\x19\x3f\xaa\x68\xa9\x16\xac\xdb\xa6\x1b\x04\xff\x85\xdf\x87\xcb\x64\xa1\x5f\x5a\x57\x5d\xfa\xaf\xc3\xcd\xd1\xf3\xc0\x3b\xa7\x96\x9f\x95\xaa\x55\x15\xf9\x93\xc4\x60\xb8\x6f\x22\x53\x68\x22\xa4\x07\xa8\x57\x88\xb9\x5c\x80\x46\x47\x8f\xec\x0a\x9e\xaf\xd8\x26\xe3\xe2\x52\x11\xd2\x6a\x79\xd5\x8b\xee\xe1\x28\xb5\x97\xd1\x3e\x31\x5a\xff\x00\xbe\x00\x20\x51\xd5\x49\xed\xe5\xae\xb6\x9a\xb3\xb2\x0b\xf4\x88\xe3\xce\xaf\xae\xd2\x37\x6a\xb7\x4c\xd6\xe4\xbf\x7c\xba\xd4\xf6\x0f\x28\x07\x26\x24\xa7\x05\xc8\x44\xf4\xf0\x09\xe8\x61\xb8\xcf\x61\x99\x83\xb7\x69\xc5\x80\xe8\xe0\x5e\x40\xc8\xc8\xa0\xd4\xc2\xa5\x57\x97\xd6\x6c\x6e\x97\xc9\x1d\x8b\xc3\x8c\x5f\x6f\xe9\x72\x93\x28\xdd\x6e\xd8\xc3\x2d\x4f\xd8\x05\xba\xe9\x48\x8c\xb6\x21\x6e\x52\x16\x7e\x4e\x97\x0b\xb6\x4d\xf0\x4a\x23\xbc\xe4\x05\xaf\x82\xa2\xd5\x7e\xe1\x8b\x7f\x62\xb4\x5d\x1a\x9e\xf0\x3a\x99\x90\x9e\x16\x4c\x8b\x9a\x45\x58\x59\xe1\x14\xa7\x0f\x90\xb1\x0b\x16\xd2\xc5\x67\x1f\xf1\x42\x1d\xc9\xd2\x6d\xb8\x5e\x43\xf1\x78\x6b\x17\x5e\x44\x85\x7b\x9d\x37\x58\x35\x8c\xea\x5c\xcb\x90\x13\x54\x30\xcd\x70\xb3\x07\xa6\xd3\x74\x43\x6d\x83\x06\x97\x8c\xa8\x8b\x29\x88\x9c\xa8\x3c\x41\x0f\x1b\x8d\xca\x2b\xc1\x60\x68\x7e\x96\x11\xc0\x98\x55\xdb\x27\xc2\x7d\x93\x0f\x22\x6f\xc9\xe8\xcc\x00\x3c\xfd\xed\x76\x09\xd2\x46\x09\xea\x15\xca\xa8\x42\x24\x58\xf6\xcd\x39\x54\xf6\xeb\xaf\x01\xe7\x4f\xcc\x93\xae\xac\x65\xff\x90\xa6\x77\x39\x18\xd2\x3b\x8e\x31\xa8\x1b\xbe\x69\xf8\xd1\xa1\x0c\xa7\xa9\x3d\xa0\x2a\xb8\xb5\x12\xba\x24\x1c\x53\x0c\x64\x0d\xd9\x07\x9e\x81\x6c\x72\xa4\x14\x87\x09\xfb\xc7\x16\xec\xda\x4d\x16\x46\x4d\x78\x24\x8a\x85\x45\x29\x58\x68\x90\x5e\x9a\xc4\x80\xff\x16\x52\xef\xc3\xc7\x88\x2b\x0a\x50\xe6\x2a\x5d\x4a\x9e\xc2\x24\x4d\x70\x53\x3f\x08\x16\xb4\x0e\x48\xc9\x08\x98\x65\xff\x65\x2b\xf6\x18\x11\x67\xd8\x4e\x9c\xdf\x03\x17\x59\x9a\xdc\x0c\x41\x4b\x84\x0a\xd1\xc1\x81\x15\x4c\x6b\x79\x9e\x63\x5c\x0d\xfa\x13\xdd\x72\x25\xeb\x26\xaf\xae\xc1\xeb\x82\x32\x78\x81\xdf\x61\x41\x1f\xcf\x15\x80\x7e\xdd\xa7\x59\x96\x3e\xbc\xa6\x83\x08\x4c\x68\x21\xb0\xfe\x47\xba\x9f\xe4\x8f\xec\x5a\x1e\x14\xa0\x4b\xca\x72\xba\xa5\x0c\x28\xdf\xa7\x20\x03\xd2\x12\xac\x72\x0a\xd3\xab\xfb\xe5\x3f\x39\x46\xf3\xa0\x2b\xdf\x87\x77\x28\x91\x3b\x9e\x25\x7c\xc5\xe2\xdb\x30\xb9\xe1\xea\x84\x76\x0e\xed\x68\xe9\xed\x8e\x6d\x19\x60\x4b\xfa\xa3\x18\x87\x54\x8b\x5a\x75\xc0\x16\x3d\x52\x00\xd2\xee\x4f\xe0\x6c\x88\xe0\x33\xa9\x78\x06\xd9\xb9\x1d\x89\x04\xd4\x15\x3c\x14\x23\xf4\x85\x09\x05\x7a\xc2\x6e\xf7\x5c\x4e\x1a\x9a\xde\x7a\x47\xc7\x6f\x8c\x6c\x4d\xd8\x3d\x16\xf2\x70\xc3\xf8\x9f\x32\x85\x2d\x3c\xb4\x9a\xaf\x3d\xf6\xce\x11\xa6\xec\xb3\x3f\xa7\x18\x43\xb7\xc0\x3a\xe4\xb4\x6f\x28\x39\x7c\x08\xf9\xcf\x8f\x1a\x6d\x5c\xfc\x9b\xb2\xf2\x8c\xb2\x32\x2b\x55\x63\x37\x55\xbd\x8c\xa3\x5c\x27\xf0\x73\xc0\x11\xc7\x20\x63\x17\xd7\x9e\x74\xe1\x29\x86\xe8\x30\x4f\xf8\xf0\x46\xff\xfd\x89\x76\xbb\xb0\xc7\x3e\xee\x19\x1a\x3c\x92\x7b\xd2\x45\x5e\xcc\x05\x81\xa8\x79\x4f\xc4\xd3\x0e\xa6\x1d\xee\x00\x7e\xf7\xd0\x72\x15\x93\x72\xbe\x22\x77\x75\x1c\xe2\x8a\xf5\xc3\x11\xb8\xe4\x7b\xe8\x87\x7d\x98\x18\x81\xeb\x6e\x98\xf1\x3e\x41\x3e\x3b\x94\x8a\x6b\xa6\x32\x8a\xfb\x56\x84\xb1\xec\xf8\x40\x5a\x31\xd2\x2a\xdd\x34\x93\x96\x1c\xa3\x1c\x42\x37\x5a\xca\x3e\x56\x1f\x74\x75\x68\x23\x77\x40\xfb\x63\xf3\xb7\xa1\x76\x36\x77\x9b\x20\xbe\xa8\x9b\x54\xd8\xfe\xe2\x6e\x81\x3d\xa1\x9d\xd0\x01\x02\x20\xdd\x6f\xc7\xde\x2b\x83\x17\xef\xc3\x78\x93\x66\x18\x29\xcb\x1b\x33\xcb\x5a\x9e\xda\xc0\x7c\x4d\xc9\x39\x8d\xeb\xc2\x05\x4a\xf2\x0d\x5d\x8d\x29\x83\xc2\x6a\x3b\x33\x0c\xe3\xeb\xed\x46\x58\x4e\x81\xc4\x17\x6a\x9d\x0e\xbc\x07\xf0\x42\xd9\x15\x12\xbe\xaa\x78\xde\xdf\x49\x72\x58\xee\x3c\xae\x9e\x07\x7c\x02\x27\xd8\x7d\xde\x0f\x6c\xf3\xcb\x02\x9e\x1b\xe1\x15\x90\x2b\x80\xda\xaa\x2b\xb7\x5d\x37\x16\xe2\x37\xa9\x80\x06\xb7\x9c\x10\xe0\xaf\x0a\x30\x8a\x0c\x84\x34\x46\x18\x05\x88\x58\xe3\x2e\x43\x8c\xd2\xc1\x6d\xe7\xb5\x40\xf2\x35\x9f\x04\xbc\xed\x0f\xe0\xee\x27\xe2\x2a\xc5\x84\xc7\xe0\xb0\xe1\x51\xb6\xc5\x96\xa3\x93\x8f\xf7\x27\xf2\x05\x4f\xd0\x59\xcb\xf3\x2d\x57\x7e\xb5\x60\x19\xbd\x26\xab\xb5\x30\x3a\xfe\xa5\x36\x4c\xab\x82\x7b\x78\xd6\x41\x69\xdf\xc7\x2c\x4c\xf2\x75\x9a\xf3\x9e\x1c\xd5\xa5\xf7\xfd\xbf\xbe\xfb\x1e\x71\x44\x01\xc5\xd2\x7e\x08\xc2\x14\x49\x3e\x78\xd4\x63\x87\x40\x07\xb1\xf4\xab\xe2\x52\x9a\xa3\xb8\x14\xd9\x73\xd3\xc1\xaa\x35\x90\x61\xfc\xab\x41\x1d\x35\xe6\x79\x74\x01\xe9\x29\xbb\xc3\x2b\x4b\xeb\xfa\xe0\xd1\x06\xb7\x53\xfb\xce\xb0\x51\xea\x09\x63\x5c\x30\xc5\x6f\x41\x0d\x47\x64\x0a\x46\x86\x10\x1d\x68\xa0\x01\x0f\xb1\x0e\x1a\xa2\xe8\x94\x7b\x03\xdf\xb0\xcf\xe9\x69\xd6\x0a\x6d\xd8\xc5\xf6\x34\x1b\xb6\x83\x1b\xb6\x80\x61\x6d\xda\xea\xd2\x25\xb5\x76\x99\x19\xa3\x2c\x78\x6b\x87\xd3\x26\x30\x6b\x30\xc1\x45\x4d\x13\xa6\xa9\x7d\x44\xd4\x15\x2c\x74\x17\x8f\x78\x1a\x24\xea\x7b\x2c\xee\xf5\x77\xe5\x73\x1b\x13\x45\x73\xe3\x09\x12\x3b\x22\xd2\xb1\xe1\x78\x37\x48\xcb\xc3\x13\x15\x6d\x74\x4e\x01\x73\x6a\xd3\xb2\xf7\xd4\x28\x0b\x3c\x05\x0c\x24\x30\x64\x63\x20\x33\x98\xc2\xec\xe6\xc4\xde\xc1\xaf\x77\x10\xb5\x41\x27\x39\x8c\xd7\x4e\x88\x1a\xd1\x32\xb7\x92\xa4\x35\xe8\xa4\xd5\x3f\x84\x16\xca\x7f\x0f\x4f\x82\x4e\x7f\x3f\x9d\x6e\x86\x06\xaa\x76\x7b\x28\xcd\x3a\xf9\x99\xd9\x72\xc3\x81\x2d\x57\x14\x0c\x54\xa6\x63\xc7\x25\x32\x13\x2c\xad\x2f\xc2\x75\x2d\xc4\xa4\xff\x60\x3c\x4b\xf8\x34\x38\x01\x42\xed\x1d\xc2\xc5\x1a\xb9\x5e\x67\xb7\x18\x4d\x9c\x49\x3b\xba\x8b\x3a\x78\x82\xc8\x67\xc6\x76\xf6\x4e\xc7\xe3\xc9\xd8\x1d\x9d\xbc\x9a\x4c\xa7\xb3\xf1\xb8\x07\xee\xb8\x47\xb2\x69\xab\x0e\x6d\x64\x24\xf8\xd9\xe4\xf4\xd5\xec\x84\x8e\x6f\x89\x14\xe2\xf1\xe4\x6c\xf2\xea\x14\x97\x04\x8a\xc4\x00\x2f\xd1\x20\xd8\x1e\x5e\x39\x69\xf2\x5f\x4c\xbe\xcb\x91\x7e\x8b\x83\xb1\xa8\x30\x79\x44\xa7\xa4\x4e\xc5\xe4\x0e\x28\xef\x46\xf8\x00\xa5\xb3\x73\xde\xa8\x3d\x17\xa3\x1e\x8e\x8b\x0a\x8a\x86\x50\xfd\x72\xff\x92\x00\xcd\x03\x55\xa2\x3c\x2e\xad\xf2\xa4\x10\x58\xc7\x28\xb9\x7f\x84\x3c\xca\xd5\xb5\xd5\xe0\x58\x69\xd4\xbd\xe3\x22\xd9\x01\xdb\xc2\xe0\x77\x15\x71\xcf\xa8\x08\x08\x35\x78\x7d\x34\xac\x6e\x94\x10\x60\xca\x89\x91\xc7\xc0\x1a\x8d\xb5\x6e\xb8\x6b\xff\x3f\x3c\x28\x4e\xae\xd3\x7f\xd2\x67\xc2\x43\x8e\x65\x04\x74\xce\x47\x71\x63\x4f\x44\x4d\x20\xd2\xd5\xe5\xf5\xed\x8d\x6d\xc0\x0d\xad\x79\x81\x87\xbb\xf0\x6c\x97\xbe\xd3\xb6\x3c\xf0\x25\xbb\x97\x1e\x62\x51\xc1\x11\x0a\x1b\x96\xa7\xc8\x4b\x9c\x5c\x7d\xf5\x85\x1c\xf0\xfc\xb9\x9a\x17\xac\x2b\x9f\x82\xd1\xb2\xfc\x06\x60\x71\x7b\xff\x5e\x48\xa5\x12\x2f\x48\xc2\xf2\xd2\x92\xbf\x02\xa4\xc3\x70\x9b\x8f\x65\x59\x79\x50\x1c\x99\x5f\x53\x9b\x15\x14\x9a\xd4\xd4\xd6\xdd\x06\x9d\xa7\x3c\x58\x3f\x37\xe1\xa9\xf7\x76\x14\x0f\x68\x62\x6f\xac\xd8\x18\x02\xaa\x5a\xc8\xa0\x4a\x4d\x36\xa5\x25\x35\xa5\x20\xc4\x7d\xf6\xaf\x7f\x15\xd7\x10\xf8\x6a\x3b\xb1\x0a\x9b\xab\x20\x39\x6e\x2f\xe1\x34\x49\x9a\x3f\x89\x8d\xbe\xc4\x99\xd8\x85\xf4\x2c\xaf\xd1\xe3\xaa\x47\x4a\xec\xdf\x12\x0c\xd7\x82\x96\x16\x6c\xd4\x34\xbc\x24\x5e\x32\xf0\x8d\x5e\x3c\x57\xe5\xff\x96\xdc\xe1\x8e\x29\x7c\xac\x9e\xf2\x2f\x65\xdd\x6e\xb5\xca\xa2\x8f\x8a\x62\x39\xec\xf1\x59\x3f\x9e\x48\x73\x69\xfc\x6f\x5a\x2f\x7f\x7a\x08\x1e\x30\x80\x8c\x87\x47\x2a\x98\x90\x4e\x5e\x01\x62\x1b\x8e\x95\x3c\xc1\x3c\x3c\x0a\x62\xfc\x59\x54\x70\xc3\x00\xfc\xc0\x00\x9c\xc1\x98\x46\xf2\x45\xef\x20\xa7\xbe\xc9\xbc\x6d\x5a\xb1\x6b\xaf\x67\x07\xb0\x83\x12\x18\xce\x4c\xb2\x31\x1d\x69\x79\xaa\x96\x62\x96\x22\xc8\xa9\x4a\x3b\x30\x72\x43\xa7\x7a\x68\x1f\x6e\x05\x9c\x18\x31\xc7\x11\x1b\xed\xd3\xdd\x32\xa6\x36\xf5\xf6\xb6\x69\x05\xc1\x0b\x2c\x92\x92\xc9\xa3\xab\x01\x9b\xd8\xaf\x80\x5d\xa7\xe9\xdc\x34\xa7\xc4\xbc\x9d\xdf\x00\xdf\x75\xc2\xe3\x21\xa9\x26\x0a\x1d\x9d\x32\x63\x79\x4d\x14\xcf\x04\x5f\x81\xc4\xd1\xdf\x08\x29\xce\x84\x35\xe0\x8d\xfc\x57\x20\x4d\xd3\xd7\xaa\xaa\xc0\xeb\x21\xc4\x9e\x5c\x13\x58\x4d\xf3\x3a\xba\x36\x6d\x05\x6a\x28\x11\xfa\x25\x6a\xe3\x14\xa9\x93\xfd\x48\x1b\xc7\x3d\xbb\xcb\x4c\x54\x48\x14\xe8\x47\x21\x80\x4d\xe9\x46\x69\x33\x45\xa2\xa8\x40\xdc\x28\xd2\x3b\x1e\xbf\x82\x6e\xc0\xc5\x0d\x2d\x65\x09\xbc\x56\x7e\x25\xcf\x48\x41\x08\x24\x6e\x15\x53\xbc\x0f\xab\xb8\x3b\xa5\xb5\xf2\xbd\x3d\xec\xd7\x7b\x7c\x27\x30\xde\x83\x10\x55\x35\x5c\x24\x99\xe4\x1a\xe0\xae\xb8\x5a\xc5\xf0\x13\x76\x0c\xaf\x1e\x31\x6d\xe8\x68\x6b\x89\xda\x80\x62\x40\xb4\x62\xc8\x6d\xc1\x3b\x1a\xa7\x1b\x03\xcf\x42\xb6\x96\x24\xd3\xf7\xb4\x58\x7d\x28\xd2\xd2\xf7\x60\x52\x09\x61\xaf\xbd\x99\x45\xde\xfe\xb2\x4b\x7d\x09\x8d\x84\x30\x84\x7e\x90\xc6\xcc\x86\x27\xb3\x93\xd3\xd9\xd4\x9b\x9e\x4d\xcf\xbc\xc9\xa9\xc9\x8c\x55\xcd\x93\xc9\x3a\x85\xc1\xcb\xff\xa1\x03\x29\x35\x85\x91\xa9\x87\xa9\xf0\x97\x00\x9b\x2d\x43\x09\xd1\xce\x93\xc0\xdc\x5b\xd2\x87\xa5\xd1\x27\x08\xc5\xfd\x22\xb5\x7e\x25\x2f\x03\x64\x7d\xd6\xdd\xc3\xda\x90\xf6\x6f\xd9\xc7\xad\x34\xc5\x06\x88\x1c\xbf\xcd\xf3\x99\x26\x81\x8b\x54\x6c\x8f\x53\x9e\xb6\xe1\x3c\x11\xda\x35\x69\x79\xec\x16\xbb\x63\xeb\x56\x47\x9b\xc2\x96\xcb\x36\x30\x11\xd4\x27\x58\x95\x0c\xdc\xf8\x18\xc1\x24\x2b\x0e\x57\xf1\x76\x85\x07\xe7\xea\xeb\xd1\x38\x8d\xc4\x18\x46\x28\x16\x5e\xae\xa2\x2b\xb5\x32\xfd\xeb\x36\x12\x8b\x2e\x30\xb7\x43\x52\xcb\xe4\x2d\xad\x4c\xff\x85\x7e\xff\x6f\x7d\x1b\xd2\x96\x76\x1f\xbd\x15\x87\x0d\x01\x4a\x6c\x43\x02\x40\x87\xdd\x3a\x6c\xc1\x81\x0e\xf0\xc2\xf1\x37\xe1\x0f\xbf\xd1\xef\xef\x40\x49\x4c\xa8\x6f\x8b\x7d\x36\xf5\x1d\x37\x9f\x69\xb9\x63\x5c\xdf\x58\xb3\x7d\xb7\xd3\xf7\xe1\x6c\x8b\x8d\x45\xec\x73\x35\xe7\x73\x99\x43\x4c\x40\x1e\xe2\x0e\x10\x4e\x24\x47\xe2\xd3\x63\xe2\xea\x55\x01\x83\x77\x34\xd9\x00\x66\xdf\x06\x94\x20\x00\xe9\xf4\xa4\x6d\x01\xe2\xe8\xb6\xa7\x67\x60\x85\x70\x72\xf5\xb9\x78\xfd\x9d\x9d\xb7\xae\xac\x01\x9f\xc4\xd0\x08\x0b\x15\xd0\x28\x38\x24\x20\xb9\x17\x6f\xbf\x77\x6c\x29\x81\xd9\x52\xb5\xde\x4c\x4c\xd9\x5c\x87\x6d\xd5\x84\xde\xb2\xe9\x30\x5b\xf2\xc7\x0d\x7b\x48\xb3\x3b\x79\x68\x55\x7d\xff\x4f\xed\xa4\xc9\xd9\x23\xdf\x50\x70\x02\xe0\xb5\x8d\x4a\x30\xbf\x2f\x62\x51\x74\xc4\x2e\x97\xbb\x1f\x8a\x08\x13\x21\x55\x55\xad\xd4\x0f\xa9\x19\xf5\x18\x16\x55\xc1\xa0\x59\x8e\x50\x99\x52\xf3\x21\x4d\x6c\xfd\xf0\x3b\x77\x35\x00\xfa\xde\x2d\xee\x15\xe8\x63\x66\x81\xb3\x7e\x65\x7d\x14\x59\x75\x67\x7d\x77\xc2\xc2\x3e\xde\x51\xe6\x39\xee\xb8\xff\x0a\x5e\x42\x93\xc9\x03\x02\x98\x69\x22\x32\x43\x22\x44\x6a\xa2\x48\xd1\x15\x72\x80\x63\x08\xd8\x0e\x66\x83\x2e\x8a\x03\xc8\x1a\x08\x7a\x50\xf4\x20\x0c\xea\x17\xbf\xe2\xc5\xac\x74\x53\x50\xf5\xfe\xd7\x22\xb9\x1e\x94\x29\x2f\x54\xa2\xa5\x59\xba\x53\x49\x5c\xef\x3a\xa0\x7d\x78\xa5\x21\x11\xf7\xc3\xd2\x57\x2c\x51\xe1\x72\xfa\xc0\xe6\x36\x59\x52\x48\x67\xa3\x43\xe6\x4e\xf3\x52\x3f\x71\x89\x26\xdd\x94\x5e\xe5\xa6\x1a\x39\xbd\xa6\xc8\x29\x9d\x1f\x79\xef\x10\x49\x3a\x80\x7b\xbd\xce\x96\xf7\x5c\x18\x92\x32\x94\xa0\xcd\x49\x7c\x1f\x2f\x72\x2d\x37\x03\x8a\x9b\x91\x44\x6f\x42\x5a\xc2\x5e\xe0\xad\x6e\xd7\x6a\x77\x22\x91\x66\x7a\x68\x08\x01\xfd\x32\x06\x07\x05\x7d\x55\x39\x67\x5e\x61\xca\x6f\x2d\x4b\x30\x0a\x54\xbf\xaf\x41\x53\x6e\xb5\x49\x05\x80\xc0\x90\x61\xde\x6a\x27\xd0\x04\x55\x0d\x7d\x98\x6e\x0e\xd5\x10\x8e\xe9\x05\xf2\x48\xbd\xde\x2e\xf2\xfe\xae\x3e\x7e\x87\xa4\xb8\xd2\xac\x55\x61\xc5\x11\xfe\x2a\x2e\x59\x57\x46\x7f\x4d\x97\x17\xb7\xa0\x79\xb4\x9d\x61\x52\x20\x6a\x57\xe8\xb5\x92\x68\x63\x5b\xd1\xa8\xf5\x8b\x0f\xea\xb3\xd6\x5a\xb0\x1e\x9f\xde\x68\x39\x6b\xfc\x6a\x68\xd1\xd8\xa3\x4f\x95\xd7\x32\x3e\xd7\xd0\xbd\xb5\x8a\xd1\xe3\x00\xa6\x27\x53\x6a\x99\xf0\x49\x54\xa2\x6d\x07\x1f\x6d\xdd\xd5\x51\x85\x5d\x04\xed\x19\x7d\x2a\xae\xf1\x2d\x38\x3d\xee\x7a\x58\xb1\x5e\x05\xe6\xa4\xa8\xa8\xe5\xaa\xf5\x3e\xca\x9b\xf6\x46\x96\x02\x33\x34\xd6\x14\x77\xa8\x68\x04\x06\x53\x5a\x07\x9b\x8a\x15\x98\x7d\xd8\x03\x2c\x4f\xac\x9b\x89\x23\xa5\xd3\x06\x37\xf2\xe8\x89\xcc\x9f\x15\x34\x0d\x14\x3d\x2a\x7e\x26\xab\x30\x13\x07\x83\x74\xfe\x3c\x5a\x39\x9c\x68\x00\xd3\x7d\x34\x07\xb8\xde\xe4\xba\x84\x78\x62\x6b\x5b\x74\x74\x56\x71\xf9\x69\x72\x46\xa5\x7b\x67\xb6\xe0\x1a\xff\x4e\x4a\x49\x4e\x3a\xca\x00\x0b\x3e\x60\xee\xac\x10\x5e\xb5\x59\x06\x93\x33\x64\xf6\x54\xac\xc7\xbe\x92\x3c\x14\x42\xee\x22\x3c\x98\x48\x11\x4f\x0c\x9c\x0f\xce\xe4\x4a\x6f\x9f\x9d\x4a\x90\x93\x0a\xdf\x9d\xd4\x25\x78\x3b\xd7\x24\x37\x91\xeb\x9e\xd6\x98\x56\x54\xf7\x87\x34\x5d\x89\x26\x05\x44\x92\x9d\x49\x0e\x27\xf2\x0a\x13\xba\x42\x40\x2f\xda\x1d\x63\x83\xc0\xaf\x68\x91\xb1\x92\x99\x37\x11\x8d\x32\x60\xa7\x2e\xe1\x22\xd1\x09\x9d\xd6\x97\x92\x45\xa6\x3d\xcc\x7b\xc5\xfa\xd4\x82\xa7\x44\xff\x0c\x05\xdd\x2d\x2a\x43\xcb\x12\xbf\x82\xff\x89\x6a\x04\x12\xc7\x44\x16\x30\x6d\xb2\x0e\x15\x76\x45\x4f\x7a\xe5\xbe\x92\x75\x9e\x78\x53\xc9\xfa\xab\x93\x99\xe2\xfd\xc4\x93\x37\x0d\xb8\x53\xc5\xfc\x2b\x4f\x67\xfe\x10\xb6\x65\x1b\x68\x8b\xa3\xa5\xe5\xd4\x9d\x85\x7a\x1e\x6d\x9b\xc5\x19\x86\xf8\xf0\x6b\xe5\xfa\x78\x72\x11\x84\xc7\xb8\xfc\xa7\xf8\x32\x6a\xb1\x75\xb6\x5c\x26\xad\xd1\xaa\xcf\x2b\x70\xcc\xc7\x74\xba\xb9\x32\x82\x69\x43\x44\x67\x1a\x16\x74\xac\x21\xc3\x15\x08\x31\x46\x6a\xfe\x00\xfc\xe4\xc2\x1b\xc0\xa7\xca\x20\x7e\x5d\x5f\x70\x40\x88\x9a\x77\x70\xed\xd7\x9d\x00\x04\xea\x18\xf9\xaf\x5b\x86\xfd\xeb\xe6\x90\x7f\x5d\x1b\xef\xc3\xca\x1c\x01\xc7\xfc\xeb\x62\xc0\x17\x87\x28\x68\xd1\x02\x8a\xd3\x07\xb1\xd0\x27\x49\xe0\x5d\xca\xac\x2e\x40\x81\x96\x44\x15\xc2\xc5\x40\x72\xed\x84\x4e\x85\x81\xd8\x00\x27\xe4\x59\x03\xc6\x55\xe9\x18\x94\xe8\xfb\x79\x12\xd5\x2a\x52\x4e\xd9\xb0\xe4\x24\xd2\x66\x6f\x11\xcd\xde\xdc\xfa\xec\xad\x59\x75\xa0\xb9\x90\xd3\x34\x13\xff\x51\x9d\x25\x53\x05\x16\x0d\x40\x21\x49\xfc\x28\xc1\xd1\xd2\xac\xcf\xc1\xb4\x2a\x6a\x32\xd1\x44\x42\x39\x96\x2d\x8e\xbe\x3f\xc1\x5c\x27\x8f\xb3\xe5\x9a\xce\x20\x2e\xf1\x73\x80\x65\x0a\x20\x2d\xf5\xf7\x98\xde\x09\xbf\x4c\x44\x45\xf7\x9f\x7d\xbb\x57\xe8\x84\x9c\xe2\x35\xd6\xee\x35\xce\xf7\x4d\x89\xea\x08\xc7\x38\x0d\xe5\x80\x8e\xb6\xbe\xd1\x87\x6b\xee\x83\x61\x6d\x5f\x0e\xb6\x78\xe7\x94\x3c\xbf\x29\x7e\xd5\xf0\xd4\x33\x50\xae\xb9\x02\x26\xea\x93\x82\x7a\x75\x5f\x4e\x1b\xd5\x3d\xa3\xb6\xa1\x08\x59\xc2\xc4\xc6\x6d\x52\x82\xb8\xbd\x47\x32\xff\x85\x01\xa9\x65\x4f\x4b\xd3\x58\x2b\x13\xad\x36\xb2\xd4\x0d\x70\x69\x76\x49\x87\x5b\x34\xeb\x40\x7d\x3a\xe0\x16\xd6\x50\xc9\xa5\xdc\xd7\xa7\xe2\x59\x0f\x78\xeb\x90\xba\x59\xbe\x70\xc2\xe9\xca\x78\xa4\x8a\xa1\xbb\xdd\x25\x03\x46\x5f\x7f\x43\xcf\x7e\x1f\xff\x3c\x12\x15\x91\x19\xdc\x61\xe6\x9d\x78\xa3\x74\xf5\x75\x10\x48\x2e\xbe\x09\x52\xa4\x87\x97\x30\x0f\x78\xfd\x4d\xa8\x25\x8c\x22\x04\x95\x80\xf4\x31\x88\x79\x44\x08\x16\x00\x47\x6a\x65\xbd\x17\xc4\xc5\xfe\x01\xc0\x0f\xac\xc8\x8e\x7b\x58\x8b\xfa\x77\xd9\xdf\x75\xdd\x40\xaf\x41\x1c\x73\xff\x93\x8e\x77\xa5\xce\x70\x21\x8d\x04\xa8\xf2\x05\x7e\xc8\x47\xff\xd0\xb3\xe1\x36\x26\xf1\x51\x1b\x50\x22\xce\x2c\x11\x14\xc5\x10\x23\x49\x2e\xc6\x0f\x32\xe8\xcd\x41\xb0\xcc\x8a\xc4\x9d\xeb\xdc\x14\x3e\x95\xf7\x5f\x83\x80\x43\xa7\x26\x41\xdc\xa7\xa0\x3e\xd9\x22\xf3\xf0\x2e\x68\xf1\x34\x82\xfc\xd1\x48\x97\x97\xa6\x16\x6f\xb3\xca\xf7\x8b\xe0\x15\x5a\xb6\xe6\x6d\xa8\x4f\x01\x90\x73\xb1\x23\xc5\xd6\x1a\x02\x50\x8e\xf9\xee\x0c\x96\x50\xfb\x9a\xcc\xdb\x2c\xfe\x18\x26\xf3\x5f\x38\x8d\x16\x17\xf7\xa8\xba\x74\xb8\x9a\xbe\xe8\xf1\xae\xf1\x7d\x84\x4a\x06\x7d\x58\x47\x85\x53\x42\x62\x1c\xf2\x44\x9b\xe5\xca\x23\xe2\x75\xa6\x2b\x24\x1a\xfa\x13\xeb\xb9\x17\x78\x8d\xb3\xb6\x51\xa7\x25\xd3\x6a\x7e\x47\xa7\x07\xda\xac\x6f\x81\xd1\x1c\x2e\x3a\x9a\xe8\x88\xeb\xa1\x85\x17\x45\x29\xb4\x6b\x29\x44\xdb\x66\x45\xf8\xd9\x2a\x31\xf2\x23\x10\xe4\x44\x36\xc9\x4d\xba\x15\x08\x4e\x17\x2c\x52\x36\x6a\xd6\x85\x2d\x12\x71\x0d\x57\x24\xfa\xad\x9c\xbe\x0b\xa0\x8c\x4b\x42\x88\x2e\x7b\x76\x7c\xd9\x13\xb7\xae\x05\x16\x88\xae\x47\x37\x4e\x82\x1a\xfa\xfd\x8b\x22\x09\x29\x62\x92\x89\x9c\xfa\xee\x0a\x7e\x61\x02\x3a\xf7\x71\x24\x6b\x2d\x59\xde\x5a\x82\xd7\x7a\x34\xcb\xa3\xc0\x54\xfd\x7a\x75\x7d\x37\xbf\xe8\xf8\x15\xaa\xc7\x8c\xbc\x74\x8b\x81\xce\x91\x61\x6f\xb4\x5b\x87\x33\xac\x24\xe1\x3d\x04\x21\x3a\xd3\x35\xaa\xb6\x15\xf5\x4d\x4b\x8a\xee\xc8\xeb\xeb\x57\xdd\x7b\x75\xec\xf2\xbb\x75\xe6\xfb\x21\xbc\xea\x75\xf9\x06\x1a\x53\x23\x0d\xaf\xfc\x76\x62\x0d\xd1\xeb\xc4\x1b\x68\x17\xf8\x9b\xf9\x66\x95\x7b\xfe\xdb\x29\x2d\x9a\x0a\xb4\x60\x4d\x15\xaa\x17\xb2\xb0\x49\xc3\xfb\x17\x78\x71\x87\x49\xc4\x28\x20\xec\x02\xb8\x0f\x5c\x7e\xb2\xa8\xd1\xa0\x00\x01\x94\xfe\x3e\xbf\x50\xdf\x21\xfa\xdf\xbe\x4d\xdf\xca\x1b\x95\x73\xd0\x83\xae\x99\x1a\x48\x49\x0e\x2e\x94\x4c\xcd\x02\xaa\x0b\x97\x4c\xf4\xff\x0b\x00\x00\xff\xff\xb1\xed\x12\x7d\x5d\x8e\x00\x00") func resourcesPowerMBytes() ([]byte, error) { return bindataRead( @@ -481,7 +481,7 @@ func resourcesPowerM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/power.m", size: 36121, mode: os.FileMode(420), modTime: time.Unix(1524352562, 0)} + info := bindataFileInfo{name: "resources/power.m", size: 36445, mode: os.FileMode(420), modTime: time.Unix(1541056837, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1246,7 +1246,7 @@ func resourcesStringM() (*asset, error) { return a, nil } -var _resourcesSystemM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x1b\x6b\x73\x13\x39\xf2\x7b\x7e\x85\xca\x9b\xda\x0a\x30\x84\xd8\x49\x60\x49\x8e\xad\x62\x79\x1c\xd4\xb1\x21\x47\xc2\xed\x07\x97\x89\xe5\x19\xd9\x9e\x65\x3c\xe3\x1d\x69\x08\x2e\xca\xff\xfd\xba\x5b\xf3\x90\x34\x1a\xdb\xe1\xb8\xa5\x16\x36\x23\xf5\x4b\xad\x56\xbf\xa4\xbc\x0a\xe7\xd9\x50\x7c\x5d\xe6\x37\x23\x76\xf6\x8c\x1d\xec\x31\xf8\x73\x99\xc7\xa9\xa2\xd1\xd1\x39\x0d\xe0\x8f\x7b\xf7\xce\xf7\xf6\x5e\xc1\x0f\x22\x2a\x42\x71\x25\xd4\xbb\x6c\x36\x8b\xd3\xd9\xd9\x59\x21\xf9\x4c\xb0\x67\xac\x37\xf6\x4c\x0f\x27\x59\x96\x04\x2c\x11\x5f\x44\x32\x1a\x33\x29\x94\x64\x6a\x2e\x58\xa2\xa7\x99\x54\x5c\x09\xa6\x32\x36\x46\xc0\x31\xe3\x69\xa4\xe7\x11\x81\xc6\xe9\xa7\xf1\x61\xef\x7c\xef\xb9\x52\x79\x3c\x29\x94\x90\x43\x0f\xa7\x11\x88\xf0\xed\x32\xcf\x94\x08\x95\x88\xd6\xa6\xb4\x2f\xc5\x34\x4e\x63\x15\x67\xe9\x75\xbc\x10\xd2\x2b\xb2\x03\x33\x04\x61\x97\xa8\x07\x2d\xae\x82\x31\x16\xa7\x20\x7f\x98\xa5\x91\x64\xe2\x0b\x4f\x0a\xae\x70\x05\x5f\x78\x1e\x67\x85\x64\x51\x4d\x40\x76\x09\xeb\xf0\x68\x4b\xdc\x20\x99\x32\x1a\xa4\xe4\x6a\x01\x82\xe5\x42\x15\x79\x2a\x19\x67\xe3\x77\xb1\x54\x63\x96\x4d\x19\xaf\x81\xd8\x34\xcb\xd9\x18\x20\x5d\xa5\x35\x3f\x12\xe7\x37\x59\x12\x3d\x4f\x60\x73\x90\x06\x9f\x24\x22\x60\xa6\x30\xd7\x42\x2a\x69\xf0\x46\x14\xb2\x86\x57\x57\xf1\x62\x99\x88\x57\x5f\x39\xfe\x4f\x0e\x69\x50\x4f\xf0\x85\x40\xb4\x61\xb3\xaa\x80\x7d\x10\x3c\x6a\xe8\x06\xcc\x10\xe8\x6d\x4a\xfa\x58\x8d\x46\x81\x8f\xc8\x46\x01\x2d\x42\xc6\xca\xfc\xa4\x5e\x27\x5c\x99\x74\x2e\x8a\x85\xc8\xe3\xf0\x75\x91\x86\xb8\x1d\x01\x7b\x9f\x8a\xb7\x91\x48\x15\x48\x03\x1f\x79\x24\x72\x58\x9a\xec\x64\x78\x99\x14\x36\xab\x17\xd9\x62\x01\xe8\xc3\xde\x35\x58\x0b\x98\x02\x2f\x12\x85\xd6\xee\x6c\x4d\xac\xcd\x49\x2c\x96\x6a\xc5\x12\x10\xe7\xac\xe7\x17\xd8\x66\x57\xa4\x64\x5d\x22\xba\x82\xfd\x1f\x11\xfc\x28\x60\xaf\x5e\x17\x39\x50\xcb\x3d\x3b\x51\x8b\xf3\x3e\x4d\x56\x0c\x6c\x61\x92\x25\x92\x85\x3c\x65\x73\xfe\x45\x18\x12\x75\xf0\x37\x78\x0f\x46\x96\x28\x03\xbf\x86\x0d\x08\xfe\xc9\x41\xc1\x81\x52\xe8\x3d\xb4\xf2\x97\x5a\x3d\xa6\x89\x97\x43\x8e\x7d\x2b\x43\x97\x78\xe0\x04\x6a\x93\x2c\x9b\xdd\xce\x45\xca\x0a\x29\x22\xc6\xe1\x1c\xa4\x6c\xfc\x7e\x89\x1b\xc9\xc1\x85\x2c\x61\x75\x22\x4f\xd9\x6d\xac\xe6\x59\xa1\xe0\x94\xd4\xfb\xb1\x14\x61\x3c\x8d\x45\xe4\x1c\x8c\x92\x7b\xeb\x3c\xea\x23\x50\xce\xde\xc5\xfe\xfb\x01\xab\x56\xa4\x4f\xba\x57\x67\x47\x0d\x94\xb6\xa7\x7a\x63\x89\xb1\x8f\x70\x05\x3f\xcd\xb2\x51\x83\x8d\x5f\xa6\x82\x5f\x24\x82\xe7\xa6\x7a\x69\x00\x95\x0b\x82\xc1\xbf\x83\x80\x1d\x1e\x1e\x82\xa2\x43\x1c\xd7\x7a\xd6\x36\x62\x7a\x31\x36\xcd\xb3\x85\x36\xd7\xd2\xdb\x65\x29\x03\xf7\xa7\xc4\x57\xe5\x28\x90\xe8\xdb\x4e\xa5\xad\x47\x02\xba\x8b\x16\x79\xc0\xb8\x57\x71\xa7\x30\x01\x84\x4e\xbd\x93\x8f\x03\x36\x81\xc9\xc7\xde\xc9\x27\x01\x0b\x61\xf2\x49\x27\x59\xef\xc4\x45\x81\x2b\xd2\x4a\x04\xa1\x9e\x3e\x05\x16\xfe\x2d\xbd\x22\x2d\x06\xec\x0d\x38\xbd\x21\xdf\x01\xa6\x83\xce\x5b\xd0\xf2\x4c\xe4\x25\x50\xe8\x07\x32\xc5\xea\x00\xb1\x78\x85\x96\x91\x80\x61\x3a\xe1\x5b\x8f\xe8\xc0\xef\x09\x32\x78\x9e\xc8\x1c\xa6\x71\x2e\x15\x13\x89\x40\x17\xc3\x26\x02\xa3\xa0\x2f\x48\x62\x1c\x72\xcc\x07\xcf\x2f\xd2\x1f\x07\x75\xa4\xd7\xd0\x1e\x72\xb9\x90\x60\xdc\x8e\xa5\x69\x19\x6d\x53\xbb\x12\x7f\x15\x22\x0d\x05\x0e\xf8\x0c\x4f\xe3\xec\x60\x79\xe5\x10\xfa\xcc\xb7\xa9\x54\x79\x41\xc1\x61\xd8\xfb\x76\x74\x78\x74\xd4\x7f\xfc\xe4\xf4\x08\x76\xfe\xf4\x48\xff\xa9\xfe\xbf\xee\x05\xac\x57\xaa\xee\xaa\x58\xa0\x81\x7c\x83\xbf\xfd\xa3\x6a\x7e\x34\xea\x99\x7a\xff\x1d\xe2\x0a\x68\xfc\x02\xb6\xc8\x54\x3e\x9c\xbf\xb3\xb3\x85\x9c\xa1\xe2\xa7\x22\xc7\xf5\xa0\xee\x97\x3c\x57\x71\x58\x24\x70\x72\x16\x1a\xb1\x33\xbc\x1b\x84\x6b\xfd\xbc\xc6\xad\x72\x62\xb0\x4f\x45\x06\xee\x0e\x7a\xaa\xa3\x8b\x89\x37\xc6\xe0\x46\x1e\x19\xb2\x36\xa9\xb2\x5c\xd0\x2e\xea\x15\x96\xb2\x4b\x34\x80\x49\x11\x27\xea\x21\xda\x89\x0e\x4b\x1d\x21\xe8\x3b\x55\x12\xb0\xb6\x82\x2d\xb3\xcf\x79\x68\x29\x9e\x06\x2a\xa3\x57\xf8\x21\x3b\xad\xd6\x35\x46\x84\xde\xe6\xf6\x08\xe8\x2e\x6e\x0f\x4f\xdb\x90\x36\x2f\xcb\x17\x14\x19\x30\x9e\x60\xdc\x65\xf5\xe8\x31\x7e\xf5\xd9\x03\x36\x60\x8f\x1e\x31\x2d\x87\x4f\x89\x44\xcb\x4f\xf0\xd8\x22\x78\x62\x7d\x11\xcc\x89\xcb\xf4\x31\x7e\x1d\x20\xd7\xe3\x7b\xff\x5f\xd6\x10\xa0\x4e\xda\xac\x07\xc0\xb4\x62\x5f\xb3\xde\x1e\x33\x31\x97\xd2\x9b\xcc\x01\x77\x02\x7f\x3b\x9c\x65\x03\xd8\xdf\x90\x91\x92\x3c\x03\xca\x71\x8c\x25\xd4\xa8\x38\xe3\x47\xde\x8c\xdd\x7c\xdd\x3f\x35\x27\x07\x47\x16\x6d\x98\xec\xa0\xfe\xbf\x90\x37\x3e\x41\x3d\x27\x16\xc0\x89\xc3\xff\xc1\xc9\xf7\x49\xd0\xcc\x1e\x7f\x3a\xb6\x38\x3c\x71\x04\x1c\x3c\xb1\x65\x3c\x3d\xb1\x85\x84\x6f\x57\xca\xd3\x13\x47\x4c\xe0\xb1\x41\xd4\x1a\x0f\xad\x81\x9b\x84\xc8\x44\x1a\x52\x93\x07\x1d\x41\xdc\x30\xaa\x07\x90\x7e\x81\xd7\x87\x48\xbe\x85\x19\xc2\x55\xb1\x0a\xc3\x04\x61\x30\x6b\x5a\x8f\xd6\xb4\x1d\x0c\x44\x68\x0c\xfe\x5f\x69\x76\x9b\xbe\xe6\x71\x52\xe4\x1d\x55\x98\xb1\x23\xfc\xbe\xbd\x4c\xd8\xa0\xb5\xcb\xfb\xd3\xa0\xe2\x6e\xa9\xc3\x99\xb3\x56\x7d\x5f\x0b\x65\xf8\xd7\x0b\xd3\xb7\x5e\x54\x7e\x15\x53\x72\xa8\x79\x24\xc6\x06\x08\xf7\x5f\x44\xae\x4a\x97\x8a\x23\x9c\xa5\xba\x1e\xd3\x59\xbe\xe3\x65\x2f\x3a\xf2\xf2\x8b\xc6\xa9\x76\x9e\xfd\xc1\x21\xd4\x7a\x5d\x35\xcb\xd1\xe1\x29\xce\xf6\x1f\x39\xf3\xc0\x39\x9d\xe9\x18\x04\x20\x18\xde\x0f\x1e\xf6\xef\x7d\x3a\xe8\x3f\x7a\x4c\x8e\xe7\x02\xff\x79\xbb\xa8\xc2\x96\x5e\x77\x55\x5b\x9a\xcb\xaf\xc6\x28\x34\x42\x91\x52\x97\x5d\x10\x60\xb8\x82\x72\x2c\x49\x74\x96\x34\x2d\xeb\x50\xd2\x0f\x2f\x54\xb6\x80\xc0\x83\xd3\x2b\xb6\xe0\x4b\x96\x81\xbe\xa8\x5a\x74\x3b\x0b\x15\x83\x0e\x0d\x55\xd3\x77\x2a\xdd\xc1\x3f\xeb\xff\x8e\x60\xb3\x7f\xcb\xb2\x44\x0c\xbf\x5d\xe7\x85\xc0\x9d\x6f\xfe\x7d\xcd\x13\x29\xd6\x5d\xd5\x36\x4e\x9a\xf0\x40\xe9\x32\x93\x50\x56\x7c\x01\x62\x0f\x81\x36\xc4\x96\xd3\x2e\x6c\x0f\xba\x85\xdf\x10\xb8\x03\x05\xf0\x3f\xa6\xe0\x1d\x04\x01\x0a\xca\x87\x87\x7d\xa4\xbc\x43\x60\xa9\x49\x3c\xa4\x00\x6d\xd0\x3c\x71\xbe\x4f\xf1\xdb\xaf\x05\x1d\x65\x3d\xe4\xbd\xb0\xb8\x3d\x83\xf5\xa8\x83\x52\x39\xeb\xd7\x8a\x25\x6d\x7f\x8b\xb4\xc7\x9d\xd2\x12\x0f\x00\x58\x5b\xc7\xfe\x9f\xc2\xaa\xe7\xe1\x73\x38\x8d\xc1\x30\xc7\x2c\xc9\x38\xd4\x02\x63\xfc\xd2\xed\x3d\xb3\xba\x4f\x38\x56\x12\xd8\x1f\x93\x12\xec\xdf\x31\x6f\xa0\xd2\xee\x91\xfd\x9e\x45\x85\x7d\xcc\xf4\xc8\xf0\x5b\x92\xc1\x91\x91\x20\x62\xe9\x74\xca\x0c\x0e\xf2\xb9\xd2\xd5\xd4\x15\x0c\x41\x52\xe7\x0e\x8f\x07\xcc\x6b\xd4\x56\x46\x4d\x84\xb7\x25\x78\x1a\xaa\x39\x63\x1d\x7e\xf9\xe0\x3e\xb6\x86\xc0\xd1\x4d\x04\x94\xdc\x3c\xc7\x66\x06\x24\xc3\x2b\x70\x27\x73\x48\x6e\xa1\xf0\x09\x39\xa4\xcf\x46\x31\x2e\xd9\x4c\x28\x70\x00\xf9\x67\xdd\xe6\x90\x42\xa4\xf7\xef\x19\x04\x8b\x25\x24\xa7\x90\x0e\x4b\xf0\x57\x01\x5b\xe6\xd9\x04\x96\xb3\x3a\x34\x60\x8c\xed\x57\xfb\xfd\xe0\x4f\xf8\x3b\x00\x05\xed\x6b\x99\x2f\x48\x98\x67\xfd\xf3\x4a\x83\x2a\xf8\x73\x1d\xe0\xbf\x81\x05\xd1\x65\x51\x6a\x7f\x00\x24\x07\xc1\xf1\x8f\x24\x79\x02\x24\x4f\x82\x53\x0f\x49\xb5\x7f\xfc\x0c\xb6\x45\x7d\x3f\xed\x5f\x82\x41\xf0\xb4\x45\xf9\x17\x2f\xe5\x67\x83\xbb\xd1\x7e\x0a\xb4\xfb\x47\x3b\x12\x3f\xeb\xa4\x6e\x9c\xa9\x83\xfb\xec\xfa\xfd\xcb\xf7\x67\xec\x75\xfc\x15\xcc\x02\x62\xc8\x9c\x87\x9f\x0f\x19\xec\xef\x6f\x60\xb0\x9f\x87\x3c\x9f\xc9\x9b\x1b\xdd\xba\x2f\x89\xe3\xd0\xc8\x32\x62\x02\xed\xb6\xe1\xbd\x37\x5c\xce\xcd\xd3\x84\xdf\xad\x1e\x40\x0a\x75\x3d\x75\x24\x40\x04\x39\xef\x2c\x88\x10\xb7\x7d\x62\x7f\x13\xb3\x38\xbd\x04\xd1\x81\x85\xc9\xc9\x1c\x1f\x96\x8d\x25\x60\x5a\x2c\x23\x3a\xb4\x78\x10\xca\x51\xf2\x1b\xf5\xdd\x41\x35\xb8\xe4\x78\x9c\x33\x96\x61\x8f\x93\x26\x8a\x3c\xc7\x1e\x82\x89\x75\xb5\x92\x90\x7a\x38\x72\x9a\x9c\x5b\xf2\xda\x62\xdd\xe8\x74\xc0\xb8\x1e\xd9\xaf\xfb\xf9\xef\x93\xe8\x45\xc9\xea\x19\xdb\x2f\x7f\xd4\x57\x26\xfb\xcd\x44\x78\xde\x89\x76\x89\x2b\x68\x50\xf1\xd3\x46\x2f\x01\xbe\x85\x90\x84\xe8\x95\x8c\x7b\xa8\x52\x9b\xe0\xe5\xe7\x99\xc5\x8e\xae\x6a\xd2\xc8\xa3\xf2\x66\x74\x48\xdb\xeb\xea\x94\x12\x10\xfc\xce\xf2\x18\xb4\x40\x4e\x12\x32\x32\x09\xc9\x5f\xa1\x1a\xff\xb9\xd4\x34\x9a\x9d\xc8\xc5\x52\xa4\x51\xab\xb1\xda\xb0\x6b\x69\xd9\x94\xc4\xd0\xad\xa1\x4f\x8f\xbe\xba\x35\x09\x08\xd8\x0e\xf3\x6a\xef\x52\x4b\x37\xec\xda\x81\xc0\xab\xca\xd1\xd6\x6d\xd3\x0c\x37\xed\x85\x86\xb8\x57\x9d\x81\x96\xf1\x6f\xb6\x7a\x9f\xd1\xfa\xad\x75\x57\x33\x1d\xb4\xec\xf4\xed\x74\x58\xe6\xbb\xfc\x33\x58\xbb\x0e\xef\xfd\x35\xb0\x41\x21\x7b\x8d\xaf\xdb\x6f\x5b\x3a\xfb\xc7\xaf\xcc\x41\x86\xc4\x40\x8f\xbc\x13\xe9\x4c\xcd\x87\xe1\x68\x3d\xf2\xd2\x08\xb5\x9f\xb3\xf7\xab\x32\x5c\xc7\x62\x87\x1d\x4e\x01\x4c\x35\x17\x98\x1a\xd3\xe0\x9c\xa7\xd8\x60\xa2\x20\x1a\x61\x5c\xd5\x2a\x6e\xdd\x1c\xa6\x91\xcf\x16\x4d\x23\x14\x95\xe2\xae\xb3\x0f\xe4\x00\x37\x9d\x6e\xaf\x9a\xcf\xfd\x74\x68\x7d\x74\xbb\x7a\x0d\xd5\x50\x96\xf3\x7c\x65\x2e\xd5\x9e\x21\x1f\xdc\xd7\xc9\x4c\xdd\xb0\x37\xae\x24\x25\xe9\x19\x34\x80\xc9\x13\x78\xbd\xba\x55\x45\xcd\xab\x3a\xa5\xaa\x4f\x34\x68\x4d\x42\x32\x6f\xa5\x60\x63\x34\x50\x57\x43\xb6\x18\x2d\x65\x79\xa4\xac\x83\x50\x73\x73\x8c\x41\x68\xef\x4a\x28\xff\x8d\xa6\x35\x81\xf7\x12\x81\x71\x25\x85\xe5\x62\x14\xe9\x45\x8e\x9b\x61\xaa\x14\x7d\x7d\x4f\x8b\x98\xdb\xf9\x34\x25\x77\xb8\xde\x54\xcd\x71\xe4\x51\x7e\xd0\x2a\x1c\x38\xec\xe7\xc2\xe7\x7a\xb4\x99\x82\xbc\xc1\x72\xcb\x30\x23\x13\x12\xc5\xfa\x98\x62\x33\xd9\x1a\x2d\x31\x47\xe4\x23\x6c\xe2\x09\x91\xab\x48\x6b\xb9\x42\x9e\xda\xab\x1d\xfe\x54\x51\xf8\x39\x60\xc9\xa8\xba\xfa\xf1\x2b\xdd\x99\xf2\xa8\xdd\xb8\x0e\xb2\x14\x4f\x17\x41\x3e\xd5\x3b\x24\x37\x29\xbf\xc5\xbd\x53\xfd\x2d\x48\x63\x03\x36\x53\xd9\xba\x05\x2f\x32\xac\x7b\xa9\x77\xdd\xbd\x0f\x2e\x8f\xae\x9d\x70\xe1\x5a\x7b\x51\x2e\xdf\x3e\xe2\x34\x54\xde\x73\x36\x66\x5e\x6b\x6a\x6c\x36\x09\xfc\xf6\x5e\xc2\x76\xa7\x74\x35\x93\xcd\x46\xdd\xa0\xa0\xb0\x1f\xd3\x65\x5b\xdc\x7a\xb0\x14\xd8\x34\x10\xaf\xc8\x9d\x96\x52\x53\xea\x16\xdb\x60\xb6\xcd\x1c\x6c\xd1\xff\x5d\xc4\x76\xf5\x49\x03\x43\x2c\x3e\xf3\x02\xbd\x9c\x18\xd7\x97\xc1\xe4\x40\xd1\x6f\xf2\x74\x55\xdf\x4a\x38\xb2\x12\x7a\xb7\x9c\x25\x75\x6d\x09\x02\xf8\xe3\xed\x0a\x9a\x88\x29\x42\x35\x56\x55\xc1\xb9\xc0\x2a\xd8\x74\xcb\x71\x5a\x15\xc5\x20\x11\xf6\xc0\xb0\xc1\xe3\x48\x52\x51\x69\xe7\xd4\x78\xad\x0c\xd1\x06\x82\x00\xc7\x77\x01\xce\x35\x9e\x39\x45\xee\x18\x2c\x32\x5e\xc4\xca\x57\x14\x63\x62\x07\x3f\xc5\x39\x5e\xae\x4c\x15\x84\xd3\x31\xc1\xd2\x0e\x42\xd1\x4a\x15\xc8\xa5\xc8\xe7\x7c\x29\xd9\xad\xa0\x47\x04\x55\x0b\x4f\x07\x5e\x11\x7e\xa6\x28\x03\xd9\xff\xf5\x3c\x87\xe2\x17\x3f\x26\x82\x2d\xf0\x0e\x68\x26\x52\xec\xec\x61\x51\x4a\x15\xf0\x8a\x08\xfc\x59\x40\xdd\x4f\x98\x2c\x9e\x22\x55\x09\xbb\x93\x40\x95\x3b\xc9\x72\x65\x84\x28\x50\x4b\x08\x8c\x60\x21\x90\x88\x42\x45\x2d\x80\x8c\x7d\x1b\x68\x2e\x75\x43\xa5\xee\xea\xe4\x26\x60\x4a\xef\x60\x6b\x0a\x66\x20\x23\x7c\x8e\x92\x00\x49\xd4\x01\xac\x0c\x04\x25\x99\x61\x65\x58\x94\x53\x35\x56\x75\xed\x4a\x59\xd1\xaa\x20\xf7\x98\x16\x55\xd2\x4c\xad\xbd\x0f\xc5\x24\xa6\x92\xcd\x2f\x42\xc0\xa6\x8d\x21\x91\xf6\xac\xad\xc4\x01\x32\x64\xa9\x32\x50\x3f\x4f\x12\xd8\x2b\x11\x16\xfa\xd1\x0a\x9c\x97\x25\x9f\xe9\x67\x48\xb8\x15\xfa\x8d\x44\x84\x3b\x50\xa7\xea\x58\xb7\xa5\x55\x6a\x10\x57\xf7\xab\x90\x25\xcd\xe6\xea\x90\xe9\xe7\x21\xd9\x42\x54\x89\xc3\x34\xc9\x6e\x29\xc1\xca\xb3\x44\x3f\xce\x42\x6f\x49\xd6\xaa\xfb\x35\xe9\xac\x40\xe9\x78\xa8\x0a\xea\x4f\xca\x62\xb9\xc4\x3d\xab\xc5\x22\x8e\x79\x5e\x2c\xb5\x6a\x62\xe0\xc3\xd2\xec\xd6\xbd\x3a\xc3\x95\xb5\xcd\xfa\x05\x57\xa1\x55\x8d\xd2\x00\x69\x20\xc4\x9f\xd0\x46\x8d\xfc\x05\x0f\xb1\x56\x52\x3a\x36\x0f\x57\x80\x56\x05\x93\xb0\x40\x7c\x20\x73\x1b\x4b\x61\xb5\x9d\xf4\xd5\xb2\x2e\x63\x5b\x31\x0d\xf9\x6c\x8a\x64\xe5\x6b\x06\x04\xbb\x4b\x63\x15\xd2\x63\xbd\x18\x7e\xce\x26\xe7\x4c\x6f\x6d\x38\x3a\x67\xd1\x39\x13\xfe\xae\x42\x8d\x82\x17\xca\x93\xa0\xc6\x09\x58\x64\x77\x0a\x5e\x82\x02\xfe\x43\x36\x67\x3d\xaa\xa9\x47\x5b\xef\xc6\xd0\xd7\xe0\xf2\xd1\x56\x0c\x63\xf5\x79\xee\x86\xca\xb6\x46\x58\x03\xb9\x43\x67\xde\x78\xbc\x00\xe4\x86\x8b\x15\x3d\x62\xe9\x7e\xe6\x40\x00\x43\x7d\x56\x38\x7b\x84\x3a\xf4\x42\x43\xc6\x5c\xd6\x1e\xc6\xf2\x4b\xea\x06\xc2\xc1\x7d\xfd\x18\xaf\x3c\x39\xe2\x2b\x18\x34\x93\x78\xfd\xdd\xbc\x80\xc1\x5e\x07\x98\x2e\x13\xd3\x29\x2c\xd4\xdf\x56\xfb\x3b\x84\x23\xb1\xf0\x91\x84\x96\xaa\xae\xc4\x39\x8b\xe2\x29\x5d\x8c\x2b\xf6\xe1\xcd\x15\x0c\x82\x7b\xc0\xbb\x82\xdb\x3c\x56\x62\x57\x79\x27\x3f\x42\xde\x3f\xe6\x10\xc9\xb4\x57\x4c\xc5\xad\xab\xc3\x7a\x11\xef\xde\x5c\x05\x55\x31\x52\xae\x26\xd3\x8e\x05\xe4\xb7\x5a\x9b\x40\xa8\x59\x9c\xcc\xd0\x73\x95\x21\x22\xcc\x0a\x18\xc2\x57\x5f\x4c\x8a\x25\xcf\xf1\xfd\x68\x2d\xdd\x9d\x36\x29\xf4\x2f\x7a\xb0\xdb\xa2\x37\x91\xff\x03\xb6\x87\xae\x08\x35\x9f\x91\x9f\xd1\xf1\x0f\x64\x34\xf9\x5b\x18\x71\x6c\x5b\x6e\xe6\x75\xf2\xe3\x78\x1d\x6f\xe3\x75\xfa\x63\xd7\x15\xfe\xfd\xbc\xf0\x5f\xbc\x97\xf2\xf3\x7c\x7c\x57\x9e\x5b\x10\xcc\xbb\x08\x00\x87\x43\x24\xe3\x59\x8a\x01\x7e\xd3\xb9\x31\x48\x45\x5f\x9e\x13\x0a\xce\x8e\x6a\x27\x6f\xfe\xc1\xf0\x70\xa9\x1f\x60\x5a\xd0\xf8\xa4\x82\x9d\xfd\xca\xfa\x83\xe3\x60\x77\xa4\x1b\x8d\x74\x3c\xe8\x5b\x38\xeb\x0e\x6f\x05\xb4\x99\xcb\xd4\x7b\x1e\x06\x7d\x07\xb0\xbe\x82\x33\x1e\x50\x42\x58\x6a\x97\xcf\x10\xaa\x24\x3e\xa2\x74\x9f\x50\x62\x66\x66\xbe\x9d\x04\xd5\x66\x61\x0c\xbe\x29\x6a\x52\xb1\xf2\x56\xc7\x5b\x43\x27\x49\x77\x74\x6d\x38\xaf\x16\x75\xab\x85\x4a\x50\x14\xf9\xa0\x5c\xa0\x59\x89\x12\xad\xf5\x79\x39\xa3\x5f\x08\xfe\xa4\x9b\x6d\xf7\x7e\xa6\x85\x7e\x43\x5a\xeb\xbd\x91\xf5\x38\x13\x78\xdc\xe9\xaa\xb8\x94\xd6\x7e\xab\xbc\x58\xe1\x65\x07\x26\x1c\xc6\x82\xd6\x1b\x8f\x48\x89\x30\x3c\xa5\x95\xf9\x5f\x6e\xba\xb0\x4f\x08\xf6\x97\x2d\x61\xcb\x2b\x97\xdf\x28\x3a\xdc\xfe\x66\xa4\x56\x16\x53\x83\x77\x3c\xf8\xbd\xbb\x5c\x47\xdb\xe4\x32\xec\xb6\xee\x45\xfe\xce\xe5\xe7\x8b\x2c\x7d\x51\x85\x59\x9e\x78\x7f\xe9\xa1\x0d\xd6\x7e\xfd\x09\xf9\x84\xb4\x1e\xc1\x35\x06\x9d\x66\x69\xd8\xa0\xd2\xc3\x3c\xb6\x00\x92\x60\xf4\x50\x6b\x1f\xb2\x8f\xd8\x89\xa5\x72\x20\xa5\x5a\x01\x53\xcc\x1d\x7e\x4d\xa2\x2d\xd5\xb6\xcc\x73\x03\xea\x0e\xa9\x28\x12\x6e\xb8\x3b\x9c\x03\xb6\x49\x5b\xfc\x41\xc7\x03\x5e\xa2\x59\x47\xe7\x0e\xe2\x3a\x06\x6c\x61\xe1\xe6\x12\x5b\xf9\xe9\x00\xb3\x91\x65\x15\x76\x76\x62\xed\x0d\x58\x1b\xa4\xf8\x3e\x4d\x36\xcb\x1c\xd9\xbe\xf8\x63\x1a\xff\x55\x08\xbb\x2b\x85\x23\x43\xcb\x4a\x0b\x1a\x2b\x5d\x6c\xab\xf7\x84\x73\x9b\x7e\xdb\x06\xdf\xd5\x8b\xae\x07\xec\xee\xaf\xb0\x60\x63\xdb\x2e\xd3\xaf\xaa\x22\x3d\xbb\xa5\x13\x43\x65\x38\x76\x9d\xa8\xa6\x02\xec\x25\x08\xeb\x76\xad\x7d\xe5\x2f\x82\x3a\x5d\xa4\xa5\x7b\x22\xdd\xfa\x95\x8e\x24\x16\xc5\x4d\x55\x87\xc1\x88\x02\x0e\x76\x02\xca\xf2\x2e\x2a\xe8\xba\xa0\x79\xd5\xda\x6e\x35\x2d\x37\x55\xbd\x7b\xcd\x2f\x2f\x39\xbf\xb8\x51\x8e\xd6\x35\x66\x1a\x89\xb2\x47\xd8\xf4\x90\x03\xa3\xd2\xd4\x4f\xbf\xfd\xbf\xd7\xd1\xfe\xc5\x8c\x92\xfa\x86\x0b\xec\xb7\x29\xa8\x79\xc1\x5d\xc9\x8c\x61\x8f\x68\x04\x17\x7c\xa7\x84\x0e\xe9\xba\x07\xfd\x2e\x4b\x67\xf8\x6c\xee\xe1\xaf\x85\x14\xd5\x47\xfb\x37\xeb\xe8\x5d\xb3\x7e\x98\x5c\x5f\xc2\x19\x08\xcd\xc1\xd2\xe0\xbd\xde\xe8\xdc\x19\x72\xb4\x5e\xce\xeb\xf6\xb5\x5f\x38\x12\xc2\x99\x32\x05\xa6\x33\x6d\xe9\xde\x00\xde\xfd\x60\x18\xf8\xef\x0b\xb5\x2c\xd4\x95\xca\x05\x5f\xd8\x96\xde\xc6\x33\xd0\xfe\xc0\xda\xb5\xba\xcc\x74\xce\x87\x31\x67\x91\x1f\xf6\xa4\x8a\x20\xe2\xf4\xf4\xbb\x26\x89\xf7\x09\xcd\x75\x68\xa9\x74\x85\xbf\xcd\xf8\xdf\x00\x00\x00\xff\xff\xda\x45\xd3\x15\xf0\x38\x00\x00") +var _resourcesSystemM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x3b\x6d\x73\x13\x39\xd2\xdf\xf3\x2b\x54\xde\xd4\x56\x80\x21\xc4\x4e\x02\x4b\xf2\xb0\xf5\xb0\xbc\x1c\xdc\xb1\x21\x47\xc2\xed\x87\x39\x13\xcb\x33\xb2\x3d\x9b\xf1\x8c\x77\x46\x93\xe0\x4a\xf9\xbf\x5f\x77\x6b\x5e\x24\x8d\xc6\x76\x38\x0e\x8a\x24\x96\xd4\xea\x6e\xb5\x5a\xfd\x26\xf9\x4d\x30\x4b\x7d\xf1\x75\x91\x5d\x0d\xd9\xc9\x0b\xb6\xb7\xc3\xe0\xdf\x79\x16\x25\x92\x7a\x87\xa7\xd4\x81\x1f\x77\x1e\x9c\xee\xec\xbc\x81\x0f\x22\x2c\x02\x71\x21\xe4\x87\x74\x3a\x8d\x92\xe9\xc9\x49\x91\xf3\xa9\x60\x2f\x58\x6f\xe4\x18\xf6\xc7\x69\x1a\x7b\x2c\x16\x37\x22\x1e\x8e\x58\x2e\x64\xce\xe4\x4c\xb0\x58\x0d\xb3\x5c\x72\x29\x98\x4c\xd9\x08\x01\x47\x8c\x27\xa1\x1a\xc7\x09\xd4\x4f\x9f\x46\xfb\xbd\xd3\x9d\x97\x52\x66\xd1\xb8\x90\x22\xf7\x1d\x94\x86\xc0\xc2\xdd\x79\x96\x4a\x11\x48\x11\xae\x74\x6e\x5f\x8b\x49\x94\x44\x32\x4a\x93\xcb\x68\x2e\x72\x27\xcb\x16\x8c\x0f\xcc\x2e\x50\x0e\x8a\x5d\x09\x7d\x2c\x4a\x80\xff\x20\x4d\xc2\x9c\x89\x1b\x1e\x17\x5c\xe2\x0a\x6e\x78\x16\xa5\x45\xce\xc2\x1a\x41\xde\xc5\xac\x45\xa3\xcd\x71\x33\x49\xe7\x51\x43\x95\x2f\xe7\xc0\x58\x26\x64\x91\x25\x39\xe3\x6c\xf4\x21\xca\xe5\x88\xa5\x13\xc6\x6b\x20\x36\x49\x33\x36\x02\x48\x5b\x68\xcd\x47\xa2\xfc\x2e\x8d\xc3\x97\x31\x6c\x0e\xe2\xe0\xe3\x58\x78\x4c\x67\xe6\x52\xe4\x32\xd7\x68\xe3\x14\xd2\x86\x37\x17\xd1\x7c\x11\x8b\x37\x5f\x39\xfe\xc9\x7d\xea\x54\x03\x7c\x2e\x70\x9a\xdf\xac\xca\x63\x9f\x04\x0f\x1b\xbc\x1e\xd3\x18\x7a\x9f\x90\x3c\x96\xc3\xa1\xe7\x42\xb2\x96\x41\x03\x91\xb6\x32\x37\xaa\xb7\x31\x97\x3a\x9e\xb3\x62\x2e\xb2\x28\x78\x5b\x24\x01\x6e\x87\xc7\x3e\x26\xe2\x7d\x28\x12\x09\xdc\x40\x23\x0b\x45\x06\x4b\xcb\x3b\x09\x9e\xc7\x85\x49\xea\x55\x3a\x9f\xc3\x74\xbf\x77\x09\xda\x02\xaa\xc0\x8b\x58\xa2\xb6\x5b\x5b\x13\x29\x75\x12\xf3\x85\x5c\xb2\x18\xd8\x39\xe9\xb9\x19\x36\xc9\x15\x09\x69\x97\x08\x2f\x60\xff\x87\x04\x3f\xf4\xd8\x9b\xb7\x45\x06\xd8\x32\xc7\x4e\xd4\xec\x7c\x4c\xe2\x25\x03\x5d\x18\xa7\x71\xce\x02\x9e\xb0\x19\xbf\x11\x1a\x47\x1d\xf4\x35\xda\x83\xa1\xc1\xca\xc0\x2d\x61\x0d\x82\x7f\xb1\xa6\x60\x47\xc9\xf4\x0e\x6a\xf9\x6b\x25\x1e\x5d\xc5\xcb\x2e\x4b\xbf\xa5\x26\x4b\x3c\x70\x02\xa5\x49\x9a\xcd\x6e\x67\x22\x61\x45\x2e\x42\xc6\xe1\x1c\x24\x6c\xf4\x71\x81\x1b\xc9\xc1\x84\x2c\x60\x75\x22\x4b\xd8\x6d\x24\x67\x69\x21\xe1\x94\xd4\xfb\xb1\x10\x41\x34\x89\x44\x68\x1d\x8c\x92\x7a\xeb\x3c\xaa\x23\x50\x8e\xde\x47\xff\xfb\x1e\xab\x56\xa4\x4e\xba\x53\x66\x07\x0d\x94\xd2\xa7\x7a\x63\x89\xb0\x0b\x71\x05\x3f\x49\xd3\x61\x33\x1b\x5b\xba\x80\x5f\xc5\x82\x67\xba\x78\xa9\x03\x85\x0b\x8c\xc1\xef\x81\xc7\xf6\xf7\xf7\x41\xd0\x01\xf6\x2b\x39\x2b\x1d\xd1\xad\x18\x9b\x64\xe9\x5c\xa9\x6b\x69\xed\xd2\x84\x81\xf9\x93\xe2\xab\xb4\x04\x48\xf8\x4d\xa3\xd2\x96\x23\x01\xdd\x47\x8a\xdc\x63\xdc\x29\xb8\x63\x18\x00\x44\xc7\xce\xc1\xa7\x1e\x1b\xc3\xe0\x53\xe7\xe0\x33\x8f\x05\x30\xf8\xac\x13\xad\x73\xe0\xac\xc0\x15\x29\x21\x02\x53\xcf\x9f\x03\x09\xf7\x96\x5e\x90\x14\x3d\xf6\x0e\x8c\x9e\xcf\xb7\x80\xe9\xc0\xf3\x1e\xa4\x3c\x15\x59\x09\x14\xb8\x81\x74\xb6\x3a\x40\x0c\x5a\x81\xa1\x24\xa0\x98\x96\xfb\x56\x3d\xca\xf1\x3b\x9c\x0c\x9e\x27\x52\x87\x49\x94\xe5\x92\x89\x58\xa0\x89\x61\x63\x81\x5e\xd0\xe5\x24\xd1\x0f\x59\xea\x83\xe7\x17\xf1\x8f\xbc\xda\xd3\x2b\x68\x07\xba\x4c\xe4\xa0\xdc\x96\xa6\x29\x1e\x4d\x55\xbb\x10\x7f\x15\x22\x09\x04\x76\xb8\x14\x4f\xcd\xd9\x42\xf3\xca\x2e\xb4\x99\xef\x93\x5c\x66\x05\x39\x07\xbf\x77\x77\xb0\x7f\x70\xd0\x7f\xfa\xec\xf8\x00\x76\xfe\xf8\x40\xfd\xab\xfe\xae\x7a\x1e\xeb\x95\xa2\xbb\x28\xe6\xa8\x20\x77\xf0\xd3\x3f\xa8\xc6\x87\xc3\x9e\x2e\x77\x8a\xae\x74\xb1\x37\xe1\x16\x9c\x4e\xfc\x53\x1f\x4f\x2d\x00\x01\x6e\x70\x0d\x99\x80\x50\x22\x07\x39\xd5\xe2\x24\x01\x63\x80\x91\xe7\x74\x68\x21\x64\xc2\x2e\x90\x69\x9e\xc6\x82\xa4\x5c\xed\xe4\x08\x15\x86\x82\x82\x86\x64\x39\xed\xea\x8a\x02\x40\x60\xf3\x8f\x2c\x92\xe2\x82\xa8\xf9\x1f\x0b\xb9\x28\x24\x34\x04\x9f\xfb\xbd\x5c\x86\x60\x4e\x61\xb5\x7d\xa5\x6a\x0a\xe8\xef\x69\x94\xf8\x97\xa9\x6a\xb0\x27\xff\xcf\xee\x34\xb4\xab\x21\xfb\xbf\x5f\x59\xef\xdf\x49\x6f\x68\xec\x22\xd1\x6f\x87\x3f\xbf\xc3\x34\x90\xca\x19\x68\xaf\x2e\x20\x30\x4d\x27\x27\xf3\x7c\x8a\x3a\x39\x11\x19\x6e\x35\xaa\xe5\x82\x67\x32\x0a\x8a\x18\x8c\xca\x5c\x4d\xec\x8c\x7c\x34\xc4\xb5\xea\xbc\x45\x2d\xb6\xc2\x13\x97\xf6\x68\x73\xb7\x50\xa1\xda\xf1\xea\xf3\x46\xe8\xf7\xc9\x59\xc1\xee\xe4\x32\xcd\x04\xed\x91\x5a\x61\xc9\x7b\x8e\x9b\x39\x2e\xa2\x58\x3e\xc6\x23\xa4\x3c\x76\x87\x77\xfe\x46\x91\x78\xac\x2d\x60\xc3\x22\x64\x3c\x30\x04\x4f\x1d\x95\x3d\x90\xd8\xc8\x3b\x0f\xb4\x7d\x4e\x11\x7a\x93\x47\x20\xa0\xfb\x78\x04\x34\x44\x3e\x6d\x5e\x9a\xcd\xc9\x69\xa2\xab\xc5\x90\x84\xd5\xbd\x87\xd8\xea\xb3\x47\x6c\xc0\x9e\x3c\x61\x8a\x0f\x97\x10\x09\x97\x1b\xe1\xa1\x81\xf0\xc8\x68\x11\xcc\x91\x4d\xf4\x29\xb6\xf6\x90\xea\xe1\x83\xff\x2d\x69\x30\x0e\x47\x6d\xd2\x03\x20\x5a\x91\xaf\x49\x6f\x0e\x27\x30\xcc\x54\x9b\xcc\x61\xee\x18\x7e\x3a\xfc\x48\x03\xd8\x5f\x13\xac\x13\x3f\x03\x0a\xff\xb4\x25\xd4\x53\x71\xc4\x3d\x79\xfd\xec\xa6\xf5\xf0\x58\x1f\x1c\x1c\x18\xb8\x61\xb0\x03\xfb\x7f\x83\x5e\x6b\x82\x78\x8e\x0c\x80\x23\x8b\xfe\xa3\xa3\x6f\xe3\xa0\x19\x3d\xfc\x72\x68\x50\x78\x66\x31\x38\x78\x66\xf2\x78\x7c\x64\x32\x09\x6d\x9b\xcb\xe3\x23\x8b\x4d\xa0\xb1\x86\xd5\x7a\x1e\x6a\x03\xd7\x11\x91\x8a\x34\xa8\xc6\x8f\x3a\xe2\x1b\x4d\xa9\x1e\x41\x64\x0a\x0e\x11\x82\x9c\x0d\xc4\x10\xae\x72\xe3\xe8\x41\x69\x06\x33\x86\x55\x6f\x8d\xdb\x9a\x81\x13\x1a\x85\xff\x47\x92\xde\x26\x6f\x79\x14\x17\x59\x47\x82\xaa\xed\x08\x7f\x68\x2e\x13\x36\x68\x65\xd3\xfe\x32\xa8\xa8\x1b\xe2\xb0\xc6\x8c\x55\x3f\x54\x4c\x69\xf6\xf5\x4c\xb7\xad\x67\x95\x5d\xc5\x6c\x05\xd2\x41\xf2\xdc\xe0\xb5\x6f\x44\x26\x4b\x93\x8a\x3d\x9c\x25\x2a\x55\x55\x09\x90\x65\x65\xcf\x3a\x52\x96\xb3\xc6\xa8\x76\x9e\xfd\xc1\x3e\xa4\xc1\x5d\xe9\xdc\xc1\xfe\x31\x8e\xf6\x9f\x58\xe3\xe4\xe5\x95\x0f\x02\x10\x8c\x7c\xf6\x1e\xf7\x1f\x7c\xd9\xeb\x3f\x79\x4a\x86\xe7\x0c\x7f\xbd\x9f\x57\x6e\x4b\xad\xbb\x4a\xbb\xf5\xe5\x57\x7d\xe4\x1a\x21\x7f\xab\x33\x52\x70\x30\x5c\x42\xa6\x1a\xc7\x2a\x80\x9c\x94\x29\x3a\xc9\x87\x17\x32\x9d\x83\xe3\xc1\xe1\x25\x9b\xf3\x05\x4b\x41\x5e\x94\x48\xdb\x45\x97\x8a\x40\x87\x84\xaa\xe1\x7b\x55\x35\xc0\x3e\xab\xff\x07\xb0\xd9\xbf\xa5\x10\x5f\xf9\x77\x97\x59\x21\x70\xe7\x9b\xdf\x6f\x79\x9c\x8b\x55\x57\x21\x02\x07\x75\x78\xc0\x74\x9e\xe6\x90\x71\xdd\x00\xb2\xc7\x80\x1b\x7c\xcb\x71\xd7\x6c\xc7\x74\x63\x7e\x83\xe0\x1e\x18\xc0\xfe\xe8\x8c\x77\x20\x04\x28\xc8\xac\x1e\xf7\x11\xf3\x16\x8e\xa5\x46\xf1\x98\x1c\xb4\x86\xf3\xc8\x6a\x1f\x63\xdb\x2d\x05\xe5\x65\x1d\xe8\x9d\xb0\xb8\x3d\x83\xd5\xb0\x03\x53\x39\xea\x96\x8a\xc1\x6d\x7f\x03\xb7\x87\x9d\xdc\x12\x0d\x00\x58\x19\xc7\xfe\x6f\xc2\x08\xf7\xa1\xe9\x4f\x22\x50\xcc\x11\x8b\x53\x0e\x69\xd2\x08\x5b\x23\x23\x52\xa7\x0a\x28\xc7\x24\xab\x8e\xa5\x2d\xf5\x06\x2c\x8e\xf8\x39\x0d\x0b\xf3\x98\xa9\x1e\xff\x2e\x4e\xe1\xc8\xe4\x2b\x95\x5f\x00\xe5\x32\x82\x83\x78\xae\x34\x35\x75\x72\x47\x90\x54\xd4\xc4\xe3\x01\xe3\x6a\x6a\x2b\xa2\x26\xc4\x9b\x02\x3c\x05\xd5\x9c\xb1\x0e\xbb\xbc\xf7\x10\xab\x66\x60\xe8\xc6\x22\x03\x6b\x90\x61\x9d\x07\x82\xe1\x25\x98\x93\x19\x04\xb7\x90\x13\x06\x1c\xc2\x67\xad\x4e\x91\xb3\xa9\x90\x60\x00\xb2\x6b\x55\x01\xca\x85\x48\x1e\x3e\xd0\x10\x16\x0b\x08\x4e\x21\x1c\xce\xc1\x5e\x79\x90\x48\xa5\x63\x58\xce\x72\x5f\x83\xd1\xb6\x5f\xee\xf6\xbd\x3f\xe1\x67\x00\x02\xda\x55\x3c\x9f\x11\x33\x2f\xfa\xa7\x95\x04\xa5\xf7\xe7\xca\xc3\xdf\x9e\x01\xd1\xa5\x51\x72\x77\x00\x28\x07\xde\xe1\xf7\x44\x79\x04\x28\x8f\xbc\x63\x07\x4a\xb9\x7b\xf8\x02\xb6\x45\x7e\x3b\xee\x5f\xbc\x81\xf7\xbc\x85\xf9\x17\x27\xe6\x17\x83\xfb\xe1\x7e\x0e\xb8\xfb\x07\x5b\x22\x3f\xe9\xc4\xae\x9d\xa9\xbd\x87\xec\xf2\xe3\xeb\x8f\x27\xec\x6d\xf4\x15\xd4\x02\x7c\xc8\x8c\x07\xd7\xfb\x0c\xf6\xf7\x37\x50\xd8\x6b\x9f\x67\xd3\x2a\xa9\x65\x25\x72\xec\x32\xd3\x50\x02\xed\xd6\xe1\x9d\x77\x3c\x9f\xe9\xa7\x09\xdb\xad\xf2\x48\xc2\x22\x55\xac\x01\x16\xf2\x59\x67\x42\x84\x73\xdb\x27\xf6\x37\x31\x8d\x92\x73\x60\x1d\x48\xe8\x94\xf4\x7e\xbf\xac\xb9\x01\xd1\x62\x11\xd2\xa1\x2d\x33\x7c\xec\x25\xbb\x51\x5f\xab\x54\x9d\x0b\x8e\xc7\x39\x65\x29\x96\x7f\x69\xa0\xc8\x32\x2c\xaf\xe8\xb3\x2e\x96\x39\x84\x1e\x16\x9f\x3a\xe5\x16\xbf\x26\x5b\x57\x2a\x1c\xd0\x6e\x8e\x76\xeb\xab\x8e\x8f\x71\xf8\xaa\x24\xf5\x82\xed\x96\x1f\xd5\x6d\xd2\x6e\x33\x10\x9c\x76\x4e\x3b\xc7\x15\x34\x53\xb1\x69\x4e\x2f\x01\xee\x02\x08\x42\xd4\x4a\x46\x3d\x14\xa9\x89\xf0\xfc\x7a\x6a\x90\xa3\x5b\xac\x24\x74\x88\xbc\xe9\xf5\x69\x7b\x6d\x99\xd6\xa5\x95\x34\x8b\x40\x0a\x64\x24\x21\x22\xcb\x21\xf8\x2b\x64\x63\x3f\x17\x0a\x47\xb3\x13\x99\x58\x88\x24\x6c\xd5\x9c\x1b\x72\x2d\x29\xeb\x9c\x68\xb2\xd5\xe4\xe9\x90\x57\xb7\x24\x61\x02\x16\x7e\x9c\xd2\x3b\x57\xdc\xf9\x5d\x3b\xe0\x39\x45\x39\xdc\xb8\x6d\x8a\xe0\xba\xbd\x50\x10\x0f\xaa\x33\xd0\x52\xfe\xf5\x5a\xef\x52\x5a\xb7\xb6\x6e\xab\xa6\x83\x96\x9e\xbe\x9f\xf8\x65\xbc\xcb\xaf\x41\xdb\x95\x7b\xef\xaf\x80\x0c\x32\xd9\x6b\x6c\xdd\x6e\x5b\xd3\xb1\xec\x65\x4d\x86\xc0\x40\xf5\x7c\x10\xc9\x54\xce\xfc\x60\xb8\x1a\x3a\x71\x04\xca\xce\x99\xfb\x55\x29\xae\xa5\xb1\x7e\x87\x51\x00\x55\xcd\x04\x86\xc6\xd4\x39\xe3\x09\x16\x98\xc8\x89\x86\xe8\x57\x95\x88\x5b\x97\xaa\x49\xe8\xd2\x45\x5d\x09\x45\x25\xb8\xcb\xf4\x13\x19\xc0\x75\xa7\xdb\x29\xe6\x53\x37\x1e\x5a\x1f\x95\x05\x2f\x21\x1b\x4a\x33\x9e\x2d\x5b\x35\xd2\x7a\xe4\xc7\x16\x4b\xed\xba\x65\xcd\x46\x4b\x58\x0e\x2e\x6b\x27\xd4\x94\x5c\xd1\x09\xed\x5c\x08\xe9\xbe\xec\x35\x06\xf0\xca\xc6\xd3\x6e\xeb\x30\x5d\x0c\x43\xb5\xc8\x51\xd3\x4d\x99\xa2\xab\xee\x69\x20\xb3\x2b\x9f\x3a\xe7\x16\xd5\xab\xea\xde\x00\x69\x94\x0d\x5a\x85\x05\x87\xa5\x6e\x68\xae\x86\xeb\x31\xe4\x57\x98\x6e\x69\x6a\xa4\x43\x22\x5b\x9f\x13\xac\xb3\x1b\xbd\xe5\xcc\x21\xd9\x08\x13\x79\x4c\xe8\x2a\xd4\x8a\xaf\x80\x27\xe6\x6a\xfd\x9f\x2a\x0c\x3f\x7b\x2c\x1e\x56\xb7\x62\x6e\xa1\x5b\x43\x0e\xb1\x6b\x37\x65\x86\xe0\xe9\x8e\xcc\x25\x7a\x0b\xe5\x3a\xe1\xb7\xa8\x77\x8a\xbf\x05\xa9\x6d\xc0\x7a\x2c\x1b\xb7\xe0\x55\x8a\x79\x2f\xd5\xae\xbb\xf7\xc1\xa6\xd1\xb5\x13\x36\x5c\x6b\x2f\xca\xe5\x9b\x47\x9c\xba\xca\x2b\xe0\x46\xcd\x6b\x49\x8d\xf4\x22\x81\x5b\xdf\x4b\xd8\xee\x90\xae\x26\xb2\x5e\xa9\x9b\x29\xc8\xec\xe7\x64\xd1\x66\xb7\xee\x2c\x19\xd6\x15\xc4\xc9\x72\xa7\xa6\xd4\x98\xba\xd9\xd6\x88\x6d\x52\x07\x93\xf5\x7f\x16\x91\x99\x7d\x52\x87\x8f\xc9\x67\x56\xa0\x95\x13\xa3\xfa\x9e\x9c\x0c\x28\xda\x4d\x9e\x2c\xeb\x5b\x09\x8b\x57\x9a\xde\xcd\x67\x89\x5d\x69\x82\x00\xfa\x78\xbb\x82\x2a\xa2\xb3\x50\xf5\x55\x59\x70\x26\x30\x0b\xd6\xcd\x72\x94\x54\x49\x31\x70\x84\x35\x30\x2c\xf0\x58\x9c\x54\x58\xda\x31\x35\xde\xb8\x83\xb7\x01\x27\xc0\xf1\xc9\x84\x75\xc3\xa9\x0f\x91\x39\x06\x8d\x8c\xe6\x91\x74\x25\xc5\x18\xd8\xc1\xa7\x28\xc3\xcb\x95\x89\x04\x77\x3a\x22\x58\xda\x41\x48\x5a\x29\x03\x39\x17\xd9\x8c\x2f\x72\x76\x2b\xe8\x7d\x45\x55\xc2\x53\x8e\x57\x04\xd7\xe4\x65\x20\xfa\xbf\x9c\x65\x90\xfc\x62\x63\x2c\xd8\x1c\xef\x80\xa6\x22\xc1\xca\x1e\x26\xa5\x94\x01\x2f\x09\xc1\x9f\x05\xe4\xfd\x34\x93\x45\x13\xc4\x9a\xc3\xee\xc4\x90\xe5\x8e\xd3\x4c\x6a\x2e\x0a\xc4\x12\x00\x21\x58\x08\x04\xa2\x90\x51\x0b\x40\x63\x5e\x94\xea\x4b\x5d\x93\xa9\xdb\x32\xb9\xf2\x98\x54\x3b\xd8\x1a\x82\x11\x88\x08\x5f\x22\x27\x80\x12\x65\x00\x2b\x03\x46\x89\x67\x58\x19\x26\xe5\x94\x8d\x55\x55\xbb\x92\x57\xd4\x2a\x88\x3d\x26\x45\x15\x34\x53\x69\xef\x53\x31\x8e\x28\x65\x73\xb3\xe0\xb1\x49\xa3\x48\x24\x3d\x63\x2b\xb1\x83\x14\x39\x97\x29\x88\x9f\xc7\x31\xec\x95\x08\x0a\xf5\x9e\x07\xce\xcb\x82\x4f\xd5\x0b\x2d\xdc\x0a\xf5\x7c\x24\xc4\x1d\xa8\x43\x75\xcc\xdb\x92\x2a\x34\x88\xaa\xab\x67\x88\x92\xa6\x33\xb9\xcf\xd4\xcb\x99\x74\x2e\xaa\xc0\x61\x12\xa7\xb7\x14\x60\x65\x69\xac\xde\xad\xa1\xb5\x24\x6d\x55\xf5\x9a\x64\x5a\x20\x77\x3c\x90\x05\xd5\x27\xf3\x62\xb1\xc0\x3d\xab\xd9\x22\x8a\x59\x56\x2c\x94\x68\x22\xa0\xc3\x92\xf4\xd6\xbe\x3a\xc3\x95\xb5\xd5\xfa\x15\x97\x81\x91\x8d\x52\x07\x49\x20\xc0\x4f\xa8\xa3\x5a\xfc\x82\x87\x58\x09\x29\x19\xe9\x87\xcb\x43\xad\x82\x41\x58\x20\xbe\x1d\xba\x8d\x72\x61\x94\x9d\xd4\xad\xbb\x4a\x63\x5b\x3e\x0d\xe9\xac\xf3\x64\xe5\x43\x0f\x04\xbb\x4f\x61\x15\xc2\x63\xb5\x18\x7e\xca\xc6\xa7\x4c\x6d\x6d\x30\x3c\x65\xe1\x29\x13\xee\xaa\x42\x3d\x05\xef\xda\xc7\x5e\x3d\xc7\x63\xa1\x59\x29\x78\x0d\x02\xf8\x17\xe9\x9c\xf1\xde\xa8\xee\x6d\x3d\xa9\x43\x5b\x83\xcb\x47\x5d\xd1\x94\xd5\x65\xb9\x1b\x2c\x9b\x0a\x61\x0d\xe4\x16\x95\x79\xed\x5d\x07\xa0\xf3\xe7\x4b\x7a\xdf\xd3\xfd\x02\x84\x00\x7c\x75\x56\x38\x7b\x82\x32\x74\x42\x43\xc4\x5c\xe6\x1e\xda\xf2\x4b\xec\xda\x84\xbd\x87\xea\x9d\x62\x79\x72\xc4\x57\x50\x68\x96\xe3\xf5\x77\xf3\x38\x08\x6b\x1d\xa0\xba\x4c\x4c\x26\xb0\x50\x77\x59\xed\x47\x30\x47\x6c\xe1\xfb\x11\xc5\x55\x9d\x89\x73\x16\x46\x13\xba\x18\x97\xec\xd3\xbb\x0b\xe8\x04\xf3\x80\x77\x05\xb7\xf8\xbc\x61\x5b\x7e\xc7\xdf\x83\xdf\x3f\x66\xe0\xc9\x94\x55\x4c\xc4\xad\x2d\xc3\x7a\x11\x1f\xde\x5d\x78\x55\x32\x52\xae\x26\x55\x86\x05\xf8\x37\x4a\x9b\x80\xa8\x59\x5c\x9e\xa2\xe5\x2a\x5d\x44\x90\x16\xd0\x85\x0f\xe2\x58\x2e\x16\x3c\xc3\xa7\xb5\x35\x77\xf7\xda\xa4\xc0\xbd\xe8\xc1\x76\x8b\x5e\x87\xfe\x0f\xd8\x1e\xba\x22\x54\x74\x86\x6e\x42\x87\xdf\x91\xd0\xf8\x87\x10\xe2\x58\xb6\x5c\x4f\xeb\xe8\xfb\xd1\x3a\xdc\x44\xeb\xf8\xfb\xae\x2b\xf8\xf1\xb4\xf0\x37\xde\x4b\xb9\x69\x3e\xbd\x2f\xcd\x0d\x13\xf4\xbb\x08\x00\x87\x43\x94\x47\xd3\x04\x1d\xfc\xba\x73\xa3\xa1\x0a\x6f\x5e\xd2\x14\x1c\x1d\xd6\x46\x5e\xff\x87\xee\xe1\x5c\xbd\x4d\x35\xa0\xf1\x49\x05\x3b\xf9\x95\xf5\x07\x87\xde\xf6\x93\xae\xd4\xa4\xc3\x41\xdf\x98\xb3\xea\xb0\x56\x80\x9b\xd9\x44\x9d\xe7\x61\xd0\xb7\x00\xeb\x2b\x38\xed\x6d\x29\xb8\xa5\x76\xfa\x0c\xae\x2a\xc7\xf7\xa5\xf6\xeb\x52\x8c\xcc\xf4\x67\xa5\x20\xda\x34\x88\xc0\x36\x85\x4d\x28\x56\xde\xea\x38\x73\xe8\x38\xee\xf6\xae\x0d\xe5\xe5\xbc\x2e\xb5\x50\x0a\x8a\x2c\xef\x95\x0b\xd4\x33\x51\xc2\xb5\x3a\x2d\x47\xd4\xe3\xc9\x9f\x54\xb1\xed\xc1\xcf\xb4\xd0\x3b\xc4\xb5\xda\x19\x1a\xef\x56\x81\xc6\xbd\xae\x8a\x4b\x6e\xcd\x67\xdc\xf3\x25\x5e\x76\x60\xc0\xa1\x2d\x68\xb5\xf6\x88\x94\x13\xfc\x63\x5a\x99\xfb\x51\xab\x0d\xfb\x8c\x60\x7f\xd9\xe0\xb6\x9c\x7c\xb9\x95\xa2\xc3\xec\xaf\x9f\xd4\x8a\x62\x6a\xf0\x8e\xb7\xd0\xf7\xe7\xeb\x60\x13\x5f\x9a\xde\xd6\xb5\xc8\xdf\x79\x7e\x7d\x96\x26\xaf\x2a\x37\xcb\x63\xe7\xf7\x41\xda\x60\xed\x87\xb1\x10\x4f\xe4\xc6\x23\xb8\x46\xa1\x93\x34\x09\x9a\xa9\xf4\x30\x8f\xcd\x01\x25\x28\x3d\xe4\xda\xfb\xec\x33\x56\x62\x29\x1d\x48\x28\x57\xc0\x10\x73\x8b\x6f\x90\xb4\xb9\xda\x14\x79\xae\x99\xba\x45\x28\x8a\x88\x1b\xea\x16\x65\x8f\xad\x93\x16\x7f\xd4\xf1\xb6\x99\x70\xd6\xde\xb9\x03\xb9\xf2\x01\x1b\x48\xd8\xb1\xc4\x46\x7a\xca\xc1\xac\x25\x59\xb9\x9d\xad\x48\x3b\x1d\xd6\x1a\x2e\xbe\x4d\x92\xcd\x32\x87\xa6\x2d\xfe\x9c\x44\x7f\x15\xc2\xac\x4a\x61\x8f\x6f\x68\x69\x41\x7d\xa5\x89\x6d\xd5\x9e\x70\x6c\xdd\x17\x91\xf0\x2b\x07\xa2\xeb\x6d\xbf\xfd\xed\x1e\x2c\x6c\x9b\x69\xfa\x45\x95\xa4\xa7\xb7\x74\x62\x28\x0d\xc7\xaa\x13\xe5\x54\x30\x7b\x01\xcc\xda\x55\x6b\x57\xfa\x8b\xa0\x56\x15\x69\x61\x9f\x48\x3b\x7f\xa5\x23\x89\x49\x71\x93\xd5\xa1\x33\x22\x87\x83\x95\x80\x32\xbd\x0b\x0b\xba\x2e\x68\x5e\xb5\xb6\x4b\x4d\x8b\x75\x59\xef\x4e\xf3\xbd\x2e\xeb\x3b\x2d\x65\x6f\x9d\x63\x26\xa1\x28\x6b\x84\x4d\x0d\xd9\xd3\x32\x4d\xf5\x2a\xde\xfd\x95\x97\xf6\x77\x56\x4a\xec\x6b\x2e\xb0\xdf\x27\x20\xe6\x39\xb7\x39\xd3\xba\x1d\xac\x11\x9c\xf7\x8d\x1c\x5a\xa8\xeb\x1a\xf4\x87\x34\x99\xe2\xb3\xb9\xc7\xbf\x16\xb9\xa8\x1a\xed\x2f\x1d\xd2\xbb\x66\xf5\x30\xb9\xbe\x84\xd3\x26\x34\x07\x4b\x81\xf7\x7a\xc3\x53\xab\xcb\x92\x7a\x39\xae\xca\xd7\x6e\xe6\x88\x09\x6b\x48\x67\x98\xce\xb4\x21\x7b\x0d\x78\xfb\x83\xa1\xcd\xd7\xdf\xd5\x9b\x9a\xde\x9e\xa7\x4d\xd3\x9e\xe6\xb7\xcf\x87\xc2\x66\x5e\x25\xa9\x2e\xb4\x06\x53\xbc\xcc\x36\x4f\x41\xba\x10\x09\xde\x94\x21\x88\x7d\x00\x55\x6f\xc7\xd3\xb9\x72\xf4\x5e\xe1\x50\xf7\x37\x09\x58\x6b\x48\x64\x59\xaf\x7c\x13\x56\xaf\x40\x37\x7b\xff\x09\x00\x00\xff\xff\x4f\xb5\x7b\x9d\xb4\x3a\x00\x00") func resourcesSystemMBytes() ([]byte, error) { return bindataRead( @@ -1261,7 +1261,7 @@ func resourcesSystemM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/system.m", size: 14576, mode: os.FileMode(420), modTime: time.Unix(1539584692, 0)} + info := bindataFileInfo{name: "resources/system.m", size: 15028, mode: os.FileMode(420), modTime: time.Unix(1541060114, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1286,7 +1286,7 @@ func resourcesTimeM() (*asset, error) { return a, nil } -var _resourcesTrigM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x56\x5d\x6f\xea\x46\x10\x7d\xe7\x57\x8c\x78\x88\xc0\xf1\x16\x0c\xcd\x0b\x84\x44\x51\x9b\x4a\x48\x6d\x4a\x3e\xda\x3e\x58\x8e\x59\xec\x2d\x58\x22\x0b\xb5\xd7\x91\xa3\xe6\xfe\xf7\x3b\xeb\xb5\xcd\xae\x6d\x74\xe3\xfb\x92\xbb\x67\xce\xec\x7c\x9d\x59\xf3\x1c\xf1\xd9\x2c\x4d\xe8\x96\xc1\x02\xfa\x6b\x3c\xba\x99\xb7\x86\x28\x01\xb1\x63\x90\x44\x9c\xc1\xe1\x5f\x58\x67\xeb\x9f\xfa\xf3\x9e\xb4\x8e\x3d\x98\x2d\x60\xac\x0e\x24\xf3\xf3\x23\x51\x7e\x0a\x3c\xfa\xab\x7d\x9a\x9c\x70\x72\xf4\x60\x34\x87\xc1\x1f\x54\x04\xbb\x47\xf7\xe8\xba\x8e\xe7\xd9\x40\xd0\xf5\xf3\x13\xd4\x11\xae\x61\x3c\x54\xee\x99\xbf\xe4\x82\x6d\x59\x7c\xfb\xc0\xb6\x54\x44\xef\x4c\xbb\xaa\x8c\xb1\x8a\xf4\x34\x78\xe9\x62\x99\xf8\xd2\xa2\x2a\xbf\xa5\x85\xc7\x9d\x4b\x0b\xef\x01\xb9\x1a\x4d\x86\x25\x99\x38\x25\x3a\xd5\xd0\x0a\x74\x5a\xa9\xce\x68\x7a\x42\x07\xcf\xff\xc5\xc2\x9d\x7a\xc8\x2c\xec\xba\xb9\x32\x56\xb6\x66\x94\x69\x5b\x90\xab\x26\x71\xc9\x43\x26\x58\xfc\x16\x71\x2a\x54\x5f\x0c\x44\x91\xee\xe2\x40\xfe\xc1\xda\x73\x06\xad\xd0\x17\xca\x5d\x8c\xae\x60\x67\x94\x27\x76\x85\x3d\xb9\x13\x22\x8e\x36\xa9\x60\x89\x8b\x4c\x0f\x95\xf0\xff\xef\x51\x22\xe8\x66\xcf\x6c\x78\x48\xdf\x58\x1c\x05\xbf\xa5\x3c\x10\xd1\x81\xdb\xb0\x8a\x0f\x82\x05\x82\x85\xdf\xe6\xbd\xde\x2f\x87\x44\xd7\x0f\x1e\x75\xfd\x04\x87\x9a\x82\xa4\x7d\x5c\x16\x24\x0f\x5a\xcd\xf2\x58\x4d\xf2\xf6\xfe\x9d\xf1\x47\xad\x7a\xd3\xfa\x67\x18\x3e\x5a\x35\x5f\x73\xaa\xe3\x12\x9c\xb6\x81\x4e\x3b\x78\x1a\x9a\x23\xc7\x95\xc3\xe7\xd0\xe6\x05\x6d\x91\x5a\x52\xaa\x54\x89\x07\xa5\x49\x89\x96\xab\xa4\x3a\xa8\xb0\x33\xab\xa0\xe8\x05\x27\xe2\x9c\xc5\x30\x83\xbf\x59\xbc\x41\xca\x9b\x9b\x2f\x9f\xfb\xc4\x8e\x0c\x05\x11\xba\xbe\xb5\xf4\xbc\x53\x38\xb2\xb4\x94\xc7\x68\x04\xbf\xe2\x8c\xd5\xdc\x3d\x95\xd8\x8f\xc4\x25\x49\x28\x23\xf9\x47\x13\x57\x81\x1a\xe2\x9a\xb4\x8a\x0b\x99\x9d\xc4\x85\x57\xea\xe2\x92\x11\x34\x71\x09\xca\xb7\x8c\x0b\x4d\x5d\x39\xc1\xf7\x5e\x71\x94\x43\x55\xb1\xc8\x7b\x29\x71\xea\x5f\xae\x22\x4c\xaf\xc4\x89\x6c\xfc\xc0\x52\x26\x52\x99\x06\xab\x38\xe2\x42\x4e\x85\x48\x16\xf5\x86\x73\x6b\x98\x5f\x50\x94\xa8\x15\xae\x55\x86\x96\x8e\x6b\x23\xcc\xb5\x11\xe6\xda\x34\x6b\xcb\x29\x5a\x6d\xaa\x19\x0a\xaf\xcd\x9e\x38\xa8\x30\x1b\x36\xbe\x5f\xe4\xaa\x4a\x21\x9b\xfa\x34\x44\xb7\x9c\x93\xa0\x83\xda\x50\x68\xe8\x70\x5e\x70\x7a\x22\x49\xd0\xf5\xcd\xd9\xc9\x39\xa8\x00\x54\x36\x65\x53\x6d\xca\x0a\x9f\x1c\xb9\x29\x43\x2b\x66\x89\xc0\x16\x14\x03\x97\x9b\x56\x38\x48\x3e\x10\x70\x14\xa5\x26\xd0\x5d\xa7\x54\x8a\xa7\x56\xff\xe4\x15\x50\x87\xaf\x5e\xe9\x51\x7e\x4c\x8b\x73\x66\x8e\x4b\xa1\x5f\xce\xce\x86\x27\x46\x43\x33\x59\xe3\xb2\x2e\xcb\xd8\x76\x99\x5a\x07\xe2\xa8\x9c\x71\x81\x7e\x9e\x97\x60\xf5\x1b\xa1\x7c\x16\xf2\xb3\x41\xc9\x7c\xfb\x43\x95\xfb\xcf\x2e\xc2\xa1\xf4\x00\xff\x65\x70\x03\x63\x1b\x0a\xca\xc7\x28\xf3\xec\x02\xc7\x46\xc1\xc5\x05\x7c\xc0\xcd\xa2\xc6\x80\x4b\xbc\xb8\x41\xbb\xae\xb3\x88\xc6\x5a\x2c\xaa\xdb\x24\x4d\xee\x7e\xd3\x94\xdf\x40\x4e\xb6\x97\x38\xc5\x16\x99\x4f\x64\x7d\x3e\x5d\x5e\x81\x96\x96\xbe\xc4\xd1\xf6\x3e\x3b\x52\x1e\x4a\x21\xba\x13\xab\x7c\x6b\xf2\x07\xd7\x7b\x9d\xe4\xbf\x81\xe4\x7f\xe6\x75\xae\xc9\x34\xcc\xc5\xc7\xa6\x78\xd8\xfa\x7f\xf1\x24\x3d\x1e\x0f\x31\xc6\x84\x80\xee\xf7\x20\x0e\x70\x62\xf7\x6d\x40\x77\x3a\x34\x1f\xb7\xca\x9c\x57\xd7\xc8\xf9\x89\x85\x69\xc0\xbe\x1a\x48\xb1\xcf\x06\x52\xe6\x46\xa0\xef\x01\x00\x00\xff\xff\x50\x0c\x7d\x34\xa8\x0a\x00\x00") +var _resourcesTrigM = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x56\x51\x8f\xdb\x36\x0c\x7e\xbf\x5f\x41\xdc\x43\x91\xb8\xd6\x1c\x3b\xbd\x97\xa4\x69\x51\x6c\x1d\x10\x60\xeb\x72\xd7\xdb\xf6\x60\xa8\x8e\x62\x6b\x89\x81\x9c\x92\xd9\x72\xe1\xc3\xba\xff\x3e\xca\x92\x6d\xd9\x71\xd6\xf3\xbd\xc4\x24\x3f\x52\x24\xf5\x91\xba\xcf\xa9\x58\x2c\x8a\x9c\xed\x39\xac\xe0\x76\x8b\x62\x58\xd2\x2d\xa4\x39\xc8\x03\x87\x3c\x15\x1c\x4e\x7f\xc1\xb6\xdc\xfe\x70\xbb\xbc\x51\xd6\x19\x85\xc5\x0a\x66\x5a\x20\x65\x54\x89\x44\xfb\x69\xe5\x39\xda\x1c\x8b\xbc\xd5\x93\x33\x05\x6f\x09\x93\x5f\x99\x8c\x0f\xf7\xe1\x39\x0c\x7d\x4a\x5d\x20\xe8\xfa\xed\x1b\x68\x11\xde\xc2\x6c\xaa\xdd\xcb\x68\x2d\x24\xdf\xf3\xec\xfd\x27\xbe\x67\x32\xfd\xca\xad\x50\xf5\x19\x9b\xd4\x4e\x43\xd4\x2e\x4e\x57\xbf\x76\x98\xce\x6f\xed\xa0\x78\x08\x99\xf1\x9e\x90\x3b\x2f\x98\xd6\x60\xe2\xd7\xda\xb9\xa5\x6d\x94\x81\x37\x6f\xa1\x9f\xff\xce\x64\x38\xa7\x5e\x50\x5b\xfd\xc1\x40\xbe\xed\x33\x69\x9c\x4c\x85\x13\xdf\x7b\xd3\x9e\xe3\x55\xe6\x80\x36\xb6\xd6\xb5\x7f\x9a\x3f\x90\x5f\xf0\x3f\xf8\xf9\x50\x72\x77\x97\x41\xd6\x22\xe1\x92\x67\x4f\xa9\x60\x52\x77\xbb\xa3\xd1\xa0\x0f\x59\xac\x7e\xb0\xa3\x15\x82\x35\xda\x47\x26\x42\xcc\x8c\xda\xe5\xdc\x61\x39\x1f\xa4\xcc\xd2\x5d\x21\x79\x1e\x22\x92\x22\xbf\xfe\xf9\x25\xcd\x25\xdb\x1d\xb9\x0b\x9f\x8a\x27\x9e\xa5\xf1\xcf\x85\x88\x65\x7a\x12\x2e\x6c\xb2\x93\xe4\xb1\xe4\xc9\xbf\xcb\x9b\x9b\x1f\x4f\xb9\xcd\x4a\x14\x6d\x56\xc6\xa7\x1e\x2f\x95\x7d\x56\x17\xa4\x04\xab\x66\x25\x36\xfc\x78\xff\xf1\x2b\x17\xf7\x56\xf5\x5d\xeb\x6f\x49\x72\xef\xf4\x7c\xbb\x5c\x99\xd5\xca\xf9\x90\xd2\x1f\x56\xce\xad\xcb\x0e\x8c\xfa\x0a\x05\x8c\x6d\xd8\xe3\x32\x78\x87\x9b\x2d\x74\x28\xb9\x81\x2a\x9a\xf1\x40\x41\x0f\x87\xd2\xd6\x33\xad\x9b\xae\x75\x57\x66\x52\xc3\x0d\x26\x15\x82\x67\xb0\x80\x3f\x78\xb6\x43\xc8\x53\x58\x6d\x81\xf0\x81\x9f\x39\x72\x28\x09\x23\x67\x4d\x69\x7b\x1c\x59\x3b\xda\xc3\xf3\xe0\x27\xa4\x85\xa6\x0a\xd5\x89\x7d\x8f\x8f\x0a\x84\xcc\x53\x3f\x16\x1f\x8d\xb6\xc3\xc7\x60\x90\x8f\x88\x1c\xc5\x47\x0c\x69\xf3\x51\x9d\x60\xf1\x51\x32\xb1\xe7\x42\x5a\x84\xac\x00\x11\xfd\x82\xb7\x3f\xd5\x15\xcb\xaa\x97\x4a\xcf\xa2\xd7\x9b\x14\xd3\xab\xf5\x44\x35\x7e\xe2\x68\x13\x69\x4c\x93\x4d\x96\x0a\xa9\x6e\x85\x28\x14\xa3\xd3\xa5\x33\xad\x02\x98\x12\xad\xc2\xad\xca\xd0\x32\x72\xd2\x64\x77\xd2\x64\x77\xd2\x2e\x6b\xab\x20\x56\x6d\xba\x19\x5a\xdf\xbb\x7b\xe2\x23\xc3\x5c\xd8\x45\x91\xc9\x55\x97\x42\x76\xfd\xdb\x90\xe3\x72\xce\xe3\x11\x6c\x43\xa2\xa1\xc3\x75\xc2\xd9\x89\xe4\xf1\xd8\x35\x75\x50\xf7\xa0\x0f\x60\xaa\x29\xbb\x66\x52\x36\xb8\xa5\xd4\xa4\x4c\x9d\x8c\xe7\x12\x5b\x60\x2e\x5c\x4d\x9a\x71\x50\x78\x20\xe0\x6b\x48\x8f\xa0\x87\x51\xa9\x98\xed\x6c\xbf\xbd\x46\x35\xe2\xf9\xad\x3d\xea\x57\xdd\xc8\xea\x76\xcd\x67\xf3\xfa\x5b\xb9\x6a\xd3\x8b\xb3\x75\xe1\x81\xb3\xa4\x9b\x7c\x27\xd8\x98\xe1\x1c\x0a\xa6\xc7\x83\xf8\xba\x06\x1c\xa8\x37\xcb\x5a\xd9\xa6\x6f\xd6\x44\x25\x77\x20\x65\xe4\x3e\xeb\xf2\xff\x3c\xa4\x78\x49\x37\x80\x7f\x25\xbc\x83\x99\x0b\x06\xf2\xec\x95\xd4\x35\x7a\x6c\x1c\xbc\x7a\x05\xcf\xf0\x6e\xd5\x43\xc0\x6b\x0c\x7c\x01\x7b\xdb\x47\x11\x0b\xb5\x5a\x35\xd1\x14\x4c\xed\x82\x4b\x53\x15\x81\xb4\xb6\xc7\xac\xc0\x16\x75\x57\x66\xff\x7e\xc6\x6c\x85\x81\x96\x3e\x66\xe9\xfe\x63\x79\x66\x22\x51\xc4\x0c\x03\xa7\xde\x3d\xd5\x02\xa6\x5f\x82\xea\x9f\x33\xf5\xb1\xec\x63\xbb\xc8\x8e\xd9\x3c\x3e\x66\xd1\xdd\xfe\x2e\xf2\xe2\x7c\x3e\x65\x78\x26\xc4\xec\x78\x04\x79\x82\x16\x7d\xeb\x02\xba\xb3\x69\x77\xd9\x35\xe6\xaa\xba\x8b\x9c\x1f\x78\x52\xc4\xfc\xa5\x07\x69\xf4\xd5\x83\xb4\xf9\xe2\xa0\xff\x02\x00\x00\xff\xff\x73\xfc\xd3\x5d\x41\x0b\x00\x00") func resourcesTrigMBytes() ([]byte, error) { return bindataRead( @@ -1301,7 +1301,7 @@ func resourcesTrigM() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "resources/trig.m", size: 2728, mode: os.FileMode(420), modTime: time.Unix(1524352562, 0)} + info := bindataFileInfo{name: "resources/trig.m", size: 2881, mode: os.FileMode(420), modTime: time.Unix(1541056950, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/expreduce/resources/arithmetic.m b/expreduce/resources/arithmetic.m index 5c38b59..e0123af 100644 --- a/expreduce/resources/arithmetic.m +++ b/expreduce/resources/arithmetic.m @@ -123,8 +123,8 @@ Times[ComplexInfinity, rest___] := ComplexInfinity; a_Integer?Negative^b_Rational*c_Integer^d_Rational*rest___ := (-1)^b*rest /; (a == -c && b == -d); Verbatim[Times][beg___, a_Integer^m_Rational, a_Integer^n_Rational, end___] := beg*a^(m+n)*end; -Times[c : (Rational[_Integer, d_Integer] | - Complex[_Integer, Rational[_Integer, d_Integer]]), +Times[c : (Rational[_Integer, d_Integer] | + Complex[_Integer, Rational[_Integer, d_Integer]]), Power[a_Integer, Rational[1, r_Integer]], rest___] := Times[c*a, a^(1/r - 1), rest] /; (Mod[d, a] === 0 && a > 1) Sin[x_]*Cos[x_]^(-1)*rest___ := Tan[x]*rest; @@ -237,13 +237,14 @@ Attributes[Abs] = {Listable, NumericFunction, Protected, ReadProtected}; Tests`Abs = { ESimpleExamples[ - ESameTest[5.2, Abs[-5.2]], + ESameTest[5, Abs[-5]], ESameTest[5, Abs[5]], EComment["Absolute values of unspecified inputs will be left unevaluated:"], ESameTest[Abs[a], Abs[a]], EComment["But sometimes simplifications can occur:"], ESameTest[Abs[Sin[x]], Abs[-Sin[x]]] ], ETests[ + ESameTest[True, Abs[-5.2] > 0], ESameTest[0, Abs[0]], ESameTest[Abs[x^a], Abs[-x^a]], ESameTest[Abs[x^(a + b)], Abs[-x^(a + b)]] diff --git a/expreduce/resources/atoms.m b/expreduce/resources/atoms.m index ed532f2..5c78efe 100644 --- a/expreduce/resources/atoms.m +++ b/expreduce/resources/atoms.m @@ -118,3 +118,5 @@ Re[x_Real] := x; Re[x_Rational] := x; Re[Complex[re_,_]] := re; + +ReIm[x_] := {Re[x], Im[x]}; diff --git a/expreduce/resources/plot.m b/expreduce/resources/plot.m index 77ba9a0..f3f8822 100644 --- a/expreduce/resources/plot.m +++ b/expreduce/resources/plot.m @@ -1,36 +1,57 @@ +ColorData[97, i_] := Switch[i, + 1, RGBColor[0.37, 0.5, 0.71], + 2, RGBColor[0.88, 0.6, 0.14], + True, RGBColor[0.55, 0.7, 0.2] +]; + +ExpreduceFilterImaginaryPoints[unfilteredPoints_] := + Select[unfilteredPoints, (Im[#[[2]]] == 0) &]; + Attributes[ExpreducePlotPoints] = {HoldAll}; -ExpreducePlotPoints[fn_, range_List] := +ExpreduceGetPoints[fn_, range_List] := Module[{nPoints, stepSize, replacedFn, unfilteredPoints}, nPoints = 500; stepSize = (range[[3]] - range[[2]])/nPoints // N; replacedFn = fn /. range[[1]] -> varOfIteration; - unfilteredPoints = - Table[{varOfIteration, replacedFn // N}, {varOfIteration, + unfilteredPoints = + Table[{varOfIteration, replacedFn // N}, {varOfIteration, range[[2]], range[[3]], stepSize}]; - Select[unfilteredPoints, (Im[#[[2]]] == 0) &] + ExpreduceFilterImaginaryPoints[unfilteredPoints] + ]; + +Attributes[ExpreduceGetLine] = {HoldAll}; +ExpreduceGetLine[fn_, range_List, + color_] := {Directive[Opacity[1.], color, AbsoluteThickness[1.6]], + Line[ExpreduceGetPoints[fn, range]]}; + +Attributes[ExpreduceGetLines] = {HoldAll}; +ExpreduceGetLines[fn_, range_List] := Module[{fns}, + fns = If[Head[fn] === List, fn, {fn}]; + Table[ExpreduceGetLine[fns[[i]], range, ColorData[97, i]], {i, + Length[fns]}] ]; Plot::usage = "`Plot[fn, {var, min, max}]` plots `fn` over the range specified."; Attributes[Plot] = {HoldAll, Protected, ReadProtected} -Plot[fn_, range_List] := Module[{plotPoints, fullRange, displayOptions}, - plotPoints = ExpreducePlotPoints[fn, range]; - fullRange = {MinMax[Join[plotPoints[[All, 1]], range[[2 ;; 3]]]], - MinMax[plotPoints[[All, 2]]]}; - displayOptions = {DisplayFunction -> Identity, - AspectRatio -> GoldenRatio^(-1), Axes -> {True, True}, - AxesLabel -> {None, None}, AxesOrigin -> {0, 0}, - DisplayFunction :> Identity, - Frame -> {{False, False}, {False, False}}, - FrameLabel -> {{None, None}, {None, None}}, - FrameTicks -> {{Automatic, Automatic}, {Automatic, Automatic}}, - GridLines -> {None, None}, - GridLinesStyle -> Directive[GrayLevel[0.5, 0.4]], - Method -> {"DefaultBoundaryStyle" -> Automatic, - "DefaultMeshStyle" -> AbsolutePointSize[6], - "ScalingFunctions" -> None}, PlotRange -> fullRange, - PlotRangeClipping -> True, - PlotRangePadding -> {{Scaled[0.02], Scaled[0.02]}, {Scaled[0.05], - Scaled[0.05]}}, Ticks -> {Automatic, Automatic}}; - Graphics[{{{}, {}, {Directive[Opacity[1.], - RGBColor[0.37, 0.5, 0.71], AbsoluteThickness[1.6]], - Line[plotPoints]}}}, displayOptions]]; +Plot[fn_, range_List] := + Module[{lines, plotPoints, fullRange, displayOptions}, + lines = ExpreduceGetLines[fn, range]; + plotPoints = Join @@ Map[(#[[2]][[1]]) &, lines]; + fullRange = {MinMax[Join[plotPoints[[All, 1]], range[[2 ;; 3]]]], + MinMax[plotPoints[[All, 2]]]}; + displayOptions = {DisplayFunction -> Identity, + AspectRatio -> GoldenRatio^(-1), Axes -> {True, True}, + AxesLabel -> {None, None}, AxesOrigin -> {0, 0}, + DisplayFunction :> Identity, + Frame -> {{False, False}, {False, False}}, + FrameLabel -> {{None, None}, {None, None}}, + FrameTicks -> {{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines -> {None, None}, + GridLinesStyle -> Directive[GrayLevel[0.5, 0.4]], + Method -> {"DefaultBoundaryStyle" -> Automatic, + "DefaultMeshStyle" -> AbsolutePointSize[6], + "ScalingFunctions" -> None}, PlotRange -> fullRange, + PlotRangeClipping -> True, + PlotRangePadding -> {{Scaled[0.02], Scaled[0.02]}, {Scaled[0.05], + Scaled[0.05]}}, Ticks -> {Automatic, Automatic}}; + Graphics[lines, displayOptions]]; diff --git a/expreduce/resources/power.m b/expreduce/resources/power.m index 757a908..5386436 100644 --- a/expreduce/resources/power.m +++ b/expreduce/resources/power.m @@ -274,16 +274,16 @@ ] }; -possibleExponents[n_Integer, m_Integer] := - Flatten[Permutations /@ ((PadRight[#, m]) & /@ +possibleExponents[n_Integer, m_Integer] := + Flatten[Permutations /@ ((PadRight[#, m]) & /@ IntegerPartitions[n, m]), 1]; genVars[addends_List, exponents_List] := Times@@(addends ^ exponents); -genExpand[addends_List, exponents_List] := +genExpand[addends_List, exponents_List] := Plus@@Table[(Multinomial @@ exponents[[ExpandUnique`i]])* - genVars[addends, exponents[[ExpandUnique`i]]], {ExpandUnique`i, 1, + genVars[addends, exponents[[ExpandUnique`i]]], {ExpandUnique`i, 1, Length[exponents]}]; expandRules := { - s_Plus^n_Integer?Positive :> + s_Plus^n_Integer?Positive :> genExpand[List @@ s, possibleExponents[n, Length[s]]], c_*s_Plus :> ((c*#) &) /@ s }; @@ -443,7 +443,7 @@ If[MatchQ[toMatch, pat], toMatch, 0]] ]; Coefficient::usage = "`Coefficient[p, form]` returns the coefficient of form `form` in polynomial `p`."; -Coefficient[p_, var_, exp_] := +Coefficient[p_, var_, exp_] := If[exp === 0, ExpreduceNonProp[p, var], Coefficient[p, var^exp] @@ -563,7 +563,7 @@ Return[ExpreduceConstantTerm[toFactor]] ]; (* Parens are necessary due to precedence issue. *) - cTerms = ((ExpreduceConstantTerm /@ (List @@ toFactor)) // + cTerms = ((ExpreduceConstantTerm /@ (List @@ toFactor)) // Transpose)[[1]]; c = GCD @@ cTerms; If[Last[cTerms] < 0, c = -c]; @@ -629,14 +629,14 @@ Variables[s_Symbol] := {s}; Variables[s_^p_Integer] := Variables[s]; Variables[s_^p_Rational] := Variables[s]; -Variables[s_^p_Plus] := +Variables[s_^p_Plus] := If[NumericQ[s], {}, (((s^#) &) /@ p) // Variables]; Variables[s_^p_] := If[NumericQ[s], {}, {s^p}]; -Variables[s_^p_Times] := +Variables[s_^p_Times] := If[NumericQ[s], {}, {s^DeleteCases[p, _Integer]}]; Variables[e_] := ( If[NumericQ[e] || Length[e] === 0, Return[{}]]; - If[MemberQ[{Plus, Times, List}, Head[e]], + If[MemberQ[{Plus, Times, List}, Head[e]], Return[Union @@ Variables /@ (List @@ e)]]; If[Length[e] > 0, Return[{e}]]; Unknown @@ -703,7 +703,7 @@ }; PolynomialGCD::usage = "`PolynomialGCD[a, b]` calculates the polynomial GCD of `a` and `b`."; -PolySubresultantGCD[inA_, inB_, inX_] := +PolySubresultantGCD[inA_, inB_, inX_] := Module[{u = inA, v = inB, x = inX, h, delta, beta, newU, newV, i}, h = 1; i = 1; @@ -723,7 +723,7 @@ ]; (* doesn't work with rational functions yet. *) (* Looks like prefactored inputs remain factored. *) -PolynomialGCD[inA_, inB_] := +PolynomialGCD[inA_, inB_] := FactorTermsList[ PolySubresultantGCD[inA, inB, Variables[inA][[1]]]][[2]]; Attributes[PolynomialGCD] = {Listable, Protected}; @@ -755,8 +755,8 @@ }; PSimplify[expr_] := expr; -PSimplify[p_?PolynomialQ/q_?PolynomialQ] := - If[Length[Variables[p]] === 1 && Variables[p] === Variables[q], +PSimplify[p_?PolynomialQ/q_?PolynomialQ] := + If[Length[Variables[p]] === 1 && Variables[p] === Variables[q], PolynomialQuotient[p, q, Variables[p][[1]]], p/q]; Tests`PSimplify = { ESimpleExamples[ @@ -844,12 +844,14 @@ ComplexExpand::usage = "`ComplexExpand[e]` returns a complex expansion of `e`."; Attributes[ComplexExpand] = {Protected}; complexExpandInner[e_] := e; -complexExpandInner[(a_Integer?Negative)^b_Rational] := +complexExpandInner[(a_Integer?Negative)^b_Rational] := Module[{coeff, inner}, coeff = ((a^2)^(b/2)); inner = b*Arg[a]; coeff*Cos[inner] + I*coeff*Sin[inner]]; -ComplexExpand[exp_] := +complexExpandInner[E^((a_ + I*b_)*c_)] := E^(a c) Cos[b c]+I E^(a c) Sin[b c]; +complexExpandInner[E^(Complex[a_, b_]*c_)] := E^(a c) Cos[b c]+I E^(a c) Sin[b c]; +ComplexExpand[exp_] := Map[complexExpandInner, exp, {0, Infinity}] // Expand; Tests`ComplexExpand = { ESimpleExamples[ @@ -860,6 +862,8 @@ ESameTest[-(1/2)-(I Sqrt[3])/2, ComplexExpand[(-1)^(4/3)]], ESameTest[2 2^(1/3), ComplexExpand[(2)^(4/3)]], ESameTest[-1+I Sqrt[3], ComplexExpand[(-1)^(1/3) (1+I Sqrt[3])]], + ESameTest[d E^(a c) Cos[b c]+d I E^(a c) Sin[b c], ComplexExpand[d*E^((a+I*b)*c)]], + ESameTest[(1/2 + I/2)/Sqrt[2], ComplexExpand[1/2 E^(\[ImaginaryJ]*\[Pi]/4)]], ], EKnownFailures[ ESameTest[-2^(1/3)-I 2^(1/3) Sqrt[3], ComplexExpand[(-2)^(4/3)]], ] diff --git a/expreduce/resources/system.m b/expreduce/resources/system.m index 93393dd..fefc907 100644 --- a/expreduce/resources/system.m +++ b/expreduce/resources/system.m @@ -62,6 +62,12 @@ ] }; +Print::usage = "`Print[expr1, expr2, ...]` prints the string representation of the expressions to the console and returns `Null`."; +Print[expressions___] := + WriteString[OutputStream["stdout", 1], + StringJoin[ToString /@ {expressions}] <> "\n"]; +Attributes[Print] = {Protected}; + MessageName::usage = "`sym::msg` references a particular message for `sym`."; Attributes[MessageName] = {HoldFirst, ReadProtected, Protected}; Tests`MessageName = { @@ -339,4 +345,11 @@ Attributes[OutputStream] = {Protected, ReadProtected}; Attributes[WriteString] = {Protected}; -WriteString[OutputStream["stdout", 1], str_String] := Print[str]; + +Streams::usage = "`Streams[]` gets a list of all open streams."; +Attributes[Streams] = {Protected}; +Tests`Streams = { + ESimpleExamples[ + ESameTest[{OutputStream["stdout", 1], OutputStream["stderr", 2]}, Streams[]], + ] +}; diff --git a/expreduce/resources/trig.m b/expreduce/resources/trig.m index 278bd7d..8d53e8b 100644 --- a/expreduce/resources/trig.m +++ b/expreduce/resources/trig.m @@ -8,10 +8,13 @@ Sin[I*a_] := I*Sinh[a]; Sin[(-5/2)*Pi] := -1; Sin[(-3/2)*Pi] := 1; +Sin[(-2/3)*Pi] := -Sqrt[3]/2; Sin[(-1/2)*Pi] := -1; Sin[(-1/3)*Pi] := -(Sqrt[3]/2); +Sin[(1/4)*Pi] := 1/Sqrt[2]; Sin[(1/3)*Pi] := Sqrt[3]/2; Sin[(1/2)*Pi] := 1; +Sin[(2/3)*Pi] := Sqrt[3]/2; Sin[(3/2)*Pi] := -1; Sin[(5/2)*Pi] := 1; Sin[Indeterminate] := Indeterminate; @@ -28,8 +31,10 @@ Cos[(-3/2)*Pi] := 0; Cos[(-1/2)*Pi] := 0; Cos[(-1/3)*Pi] := 1/2; +Cos[(1/4)*Pi] := 1/Sqrt[2]; Cos[(1/3)*Pi] := 1/2; Cos[(1/2)*Pi] := 0; +Cos[(2/3)*Pi] := -1/2; Cos[(3/2)*Pi] := 0; Cos[(5/2)*Pi] := 0; Cos[I*a_] := Cosh[a]; @@ -61,6 +66,7 @@ ArcSin[p_Plus] := -ArcSin[-p] /; (MatchQ[p[[1]], -_] || p[[1]] < 0); ArcSin[-x_] := -ArcSin[x]; +ArcSin[0] := 0; Attributes[ArcSin] = {Listable, NumericFunction, Protected, ReadProtected}; Attributes[ArcCos] = {Listable, NumericFunction, Protected, ReadProtected}; diff --git a/expreduce/sameq.go b/expreduce/sameq.go deleted file mode 100644 index e7d7d4f..0000000 --- a/expreduce/sameq.go +++ /dev/null @@ -1,48 +0,0 @@ -package expreduce - -import "math" - -func IsSameQ(a Ex, b Ex, cl *CASLogger) bool { - aFlt, aIsFlt := a.(*Flt) - bFlt, bIsFlt := b.(*Flt) - _, aIsInteger := a.(*Integer) - _, bIsInteger := b.(*Integer) - _, aIsString := a.(*String) - _, bIsString := b.(*String) - _, aIsSymbol := a.(*Symbol) - _, bIsSymbol := b.(*Symbol) - _, aIsRational := a.(*Rational) - _, bIsRational := b.(*Rational) - _, aIsComplex := a.(*Complex) - _, bIsComplex := b.(*Complex) - _, aIsExpression := a.(*Expression) - _, bIsExpression := b.(*Expression) - - if (aIsFlt && bIsFlt) || (aIsString && bIsString) || (aIsInteger && bIsInteger) || (aIsSymbol && bIsSymbol) || (aIsRational && bIsRational) || (aIsComplex && bIsComplex) { - // a and b are identical raw types - if aIsFlt && bIsFlt { - // This is important, without it e.g. NestWhileList[(# + 3/#)/2 &, 1.0, UnsameQ, 2] never converges - // https://stackoverflow.com/questions/46136886/comparing-floats-by-ignoring-last-bit-in-golang - aVal, _ := aFlt.Val.Float64() - bVal, _ := bFlt.Val.Float64() - - if math.IsInf(aVal, 0) || math.IsInf(bVal, 0) { - return a.IsEqual(b, cl) == "EQUAL_TRUE" - } else { - return almostEqual(aVal, bVal) - } - } else { - return a.IsEqual(b, cl) == "EQUAL_TRUE" - } - } else if aIsExpression && bIsExpression { - return a.Hash() == b.Hash() - } - - // This should never happen - return false -} - -func almostEqual(a, b float64) bool { - ai, bi := int64(math.Float64bits(a)), int64(math.Float64bits(b)) - return a == b || -1 <= ai-bi && ai-bi <= 1 -} diff --git a/expreduce/streammanager/streammanager.go b/expreduce/streammanager/streammanager.go new file mode 100644 index 0000000..f80f2da --- /dev/null +++ b/expreduce/streammanager/streammanager.go @@ -0,0 +1,63 @@ +// Package streammanager keeps track of open streams and allows for reading/writing to them. +package streammanager + +import ( + "io" + "os" + "sort" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) + +type streamKey struct { + id int64 + name string +} +type streamMap map[streamKey]io.Writer + +type streamManagerImpl struct { + openStreams streamMap +} + +// NewStreamManager returns an object that can keep track of open streams. +func NewStreamManager() expreduceapi.StreamManager { + sm := streamManagerImpl{} + sm.openStreams = make(streamMap) + sm.openStreams[streamKey{id: 1, name: "stdout"}] = os.Stdout + sm.openStreams[streamKey{id: 2, name: "stderr"}] = os.Stderr + return &sm +} + +// WriteString writes the toWrite string into the stream defined by streamName and streamIndex. +func (sm streamManagerImpl) WriteString(streamName string, streamIndex int64, toWrite string) bool { + key := streamKey{id: streamIndex, name: streamName} + writer, hasWriter := sm.openStreams[key] + if !hasWriter { + return false + } + writer.Write([]byte(toWrite)) + return true +} + +func (sm streamManagerImpl) AsExpr() expreduceapi.Ex { + res := atoms.E(atoms.S("List")) + + keys := make([]streamKey, 0) + for k := range sm.openStreams { + keys = append(keys, k) + } + sort.Slice(keys, func(i, j int) bool { + return keys[i].id < keys[j].id + }) + + for _, k := range keys { + res.AppendEx(atoms.E( + atoms.S("OutputStream"), + atoms.NewString(k.name), + atoms.NewInt(k.id), + )) + } + + return res +} diff --git a/expreduce/string.go b/expreduce/string.go index 0d3f85f..2fb0cf6 100644 --- a/expreduce/string.go +++ b/expreduce/string.go @@ -1,53 +1,31 @@ package expreduce -import "bytes" -import "github.com/cznic/wl" +import ( + "bytes" -type ToStringParams struct { - form string - context *String - contextPath *Expression - previousHead string - // Used by Definition[] - es *EvalState -} + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/parser/parens" + "github.com/corywalker/expreduce/pkg/expreduceapi" +) -func needsParens(thisHead string, previousHead string) bool { - if previousHead == "" { - return false - } - prevToken, prevTokenOk := headsToTokens[previousHead] - thisToken, thisTokenOk := headsToTokens[thisHead] - if prevTokenOk && thisTokenOk { - prevPrec, prevPrecOk := wl.Precedence[prevToken] - thisPrec, thisPrecOk := wl.Precedence[thisToken] - if prevPrecOk && thisPrecOk { - if prevPrec < thisPrec { - return false - } - } - } - return true -} - -func ToStringInfix(parts []Ex, delim string, thisHead string, p ToStringParams) (bool, string) { - if p.form != "InputForm" && p.form != "OutputForm" && p.form != "TeXForm" { +func toStringInfix(parts []expreduceapi.Ex, delim string, thisHead string, p expreduceapi.ToStringParams) (bool, string) { + if p.Form != "InputForm" && p.Form != "OutputForm" && p.Form != "TeXForm" { return false, "" } if len(parts) < 2 { return false, "" } - addParens := needsParens(thisHead, p.previousHead) + addParens := parens.NeedsParens(thisHead, p.PreviousHead) var buffer bytes.Buffer if addParens { - if p.form == "TeXForm" { + if p.Form == "TeXForm" { buffer.WriteString("{\\left(") } else { buffer.WriteString("(") } } nextParams := p - nextParams.previousHead = thisHead + nextParams.PreviousHead = thisHead for i := 0; i < len(parts); i++ { buffer.WriteString(parts[i].StringForm(nextParams)) if i != len(parts)-1 { @@ -55,7 +33,7 @@ func ToStringInfix(parts []Ex, delim string, thisHead string, p ToStringParams) } } if addParens { - if p.form == "TeXForm" { + if p.Form == "TeXForm" { buffer.WriteString("\\right)}") } else { buffer.WriteString(")") @@ -64,30 +42,30 @@ func ToStringInfix(parts []Ex, delim string, thisHead string, p ToStringParams) return true, buffer.String() } -func (this *Expression) ToStringInfix(p ToStringParams) (bool, string) { - if len(this.Parts) != 3 { +func toStringInfixFn(this expreduceapi.ExpressionInterface, p expreduceapi.ToStringParams) (bool, string) { + if len(this.GetParts()) != 3 { return false, "" } - expr, isExpr := this.Parts[1].(*Expression) - delim, delimIsStr := this.Parts[2].(*String) + expr, isExpr := this.GetParts()[1].(expreduceapi.ExpressionInterface) + delim, delimIsStr := this.GetParts()[2].(*atoms.String) if !isExpr || !delimIsStr { return false, "" } - return ToStringInfix(expr.Parts[1:], delim.Val, "", p) + return toStringInfix(expr.GetParts()[1:], delim.Val, "", p) } // TODO(corywalker): Remove start, end. No users of these values. -func ToStringInfixAdvanced(parts []Ex, delim string, thisHead string, surroundEachArg bool, start string, end string, params ToStringParams) (bool, string) { - if params.form != "InputForm" && params.form != "OutputForm" && params.form != "TeXForm" { +func toStringInfixAdvanced(parts []expreduceapi.Ex, delim string, thisHead string, surroundEachArg bool, start string, end string, params expreduceapi.ToStringParams) (bool, string) { + if params.Form != "InputForm" && params.Form != "OutputForm" && params.Form != "TeXForm" { return false, "" } if len(parts) < 2 { return false, "" } var buffer bytes.Buffer - addParens := needsParens(thisHead, params.previousHead) + addParens := parens.NeedsParens(thisHead, params.PreviousHead) if addParens { - if params.form == "TeXForm" { + if params.Form == "TeXForm" { buffer.WriteString("{\\left(") } else { buffer.WriteString("(") @@ -97,7 +75,7 @@ func ToStringInfixAdvanced(parts []Ex, delim string, thisHead string, surroundEa buffer.WriteString(start) } nextParams := params - nextParams.previousHead = thisHead + nextParams.PreviousHead = thisHead for i := 0; i < len(parts); i++ { if surroundEachArg { buffer.WriteString("(") @@ -114,7 +92,7 @@ func ToStringInfixAdvanced(parts []Ex, delim string, thisHead string, surroundEa buffer.WriteString(end) } if addParens { - if params.form == "TeXForm" { + if params.Form == "TeXForm" { buffer.WriteString("\\right)}") } else { buffer.WriteString(")") @@ -123,48 +101,42 @@ func ToStringInfixAdvanced(parts []Ex, delim string, thisHead string, surroundEa return true, buffer.String() } -func DefaultStringFormArgs() (*String, *Expression) { - return NewString("Global`"), NewExpression([]Ex{ - NewSymbol("System`List"), - NewString("System`"), - }) -} - -func DefinitionComplexityStringFormArgs() (*String, *Expression) { +func definitionComplexityStringFormArgs() (*atoms.String, expreduceapi.ExpressionInterface) { // This was created because the "Private`" names in the blanks were // indicating greater complexity than they deserved. - return NewString("Global`"), NewExpression([]Ex{ - NewSymbol("System`List"), - NewString("System`"), - NewString("Private`"), + return atoms.NewString("Global`"), atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`List"), + atoms.NewString("System`"), + atoms.NewString("Private`"), }) + } -func ActualStringFormArgs(es *EvalState) (*String, *Expression) { - return NewString(es.GetStringDef("System`$Context", "Global`")), es.GetListDef("System`$ContextPath") +func actualStringFormArgs(es expreduceapi.EvalStateInterface) (*atoms.String, expreduceapi.ExpressionInterface) { + return atoms.NewString(es.GetStringDef("System`$Context", "Global`")), es.GetListDef("System`$ContextPath") } -func ActualStringFormArgsFull(form string, es *EvalState) ToStringParams { - return ToStringParams{ - form: form, - context: NewString(es.GetStringDef("System`$Context", "Global`")), - contextPath: es.GetListDef("System`$ContextPath"), - previousHead: "", - es: es, +func ActualStringFormArgsFull(form string, es expreduceapi.EvalStateInterface) expreduceapi.ToStringParams { + return expreduceapi.ToStringParams{ + Form: form, + Context: atoms.NewString(es.GetStringDef("System`$Context", "Global`")), + ContextPath: es.GetListDef("System`$ContextPath"), + PreviousHead: "", + Esi: es, } } -func simpleTeXToString(fnName string) func(*Expression, ToStringParams) (bool, string) { - return (func(this *Expression, params ToStringParams) (bool, string) { - if params.form != "TeXForm" { +func simpleTeXToString(fnName string) func(expreduceapi.ExpressionInterface, expreduceapi.ToStringParams) (bool, string) { + return (func(this expreduceapi.ExpressionInterface, params expreduceapi.ToStringParams) (bool, string) { + if params.Form != "TeXForm" { return false, "" } var buffer bytes.Buffer buffer.WriteString("\\" + fnName + " \\left(") - for i := 1; i < len(this.Parts); i++ { - buffer.WriteString(this.Parts[i].StringForm(params)) - if i != len(this.Parts)-1 { + for i := 1; i < len(this.GetParts()); i++ { + buffer.WriteString(this.GetParts()[i].StringForm(params)) + if i != len(this.GetParts())-1 { buffer.WriteString(",") } } diff --git a/expreduce/testing.go b/expreduce/testing.go index 3162a68..84bba20 100644 --- a/expreduce/testing.go +++ b/expreduce/testing.go @@ -2,18 +2,22 @@ package expreduce import ( "bytes" - "github.com/stretchr/testify/assert" "testing" + + "github.com/corywalker/expreduce/expreduce/atoms" + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/corywalker/expreduce/pkg/expreduceapi" + "github.com/stretchr/testify/assert" ) -type TestDesc struct { +type testDesc struct { module string def Definition desc string } type TestInstruction interface { - Run(t *testing.T, es *EvalState, td TestDesc) bool + run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool } type SameTest struct { @@ -21,8 +25,8 @@ type SameTest struct { In string } -func (this *SameTest) Run(t *testing.T, es *EvalState, td TestDesc) bool { - return CasAssertDescSame(t, es, this.Out, this.In, td.desc) +func (test *SameTest) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { + return casAssertDescSame(t, es, test.Out, test.In, td.desc) } type StringTest struct { @@ -30,8 +34,8 @@ type StringTest struct { In string } -func (this *StringTest) Run(t *testing.T, es *EvalState, td TestDesc) bool { - return assert.Equal(t, this.Out, EasyRun(this.In, es), td.desc) +func (test *StringTest) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { + return assert.Equal(t, test.Out, EasyRun(test.In, es), td.desc) } type ExampleOnlyInstruction struct { @@ -39,13 +43,13 @@ type ExampleOnlyInstruction struct { In string } -func (this *ExampleOnlyInstruction) Run(t *testing.T, es *EvalState, td TestDesc) bool { +func (test *ExampleOnlyInstruction) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { return true } type ResetState struct{} -func (this *ResetState) Run(t *testing.T, es *EvalState, td TestDesc) bool { +func (test *ResetState) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { es.ClearAll() return true } @@ -54,40 +58,41 @@ type TestComment struct { Comment string } -func (this *TestComment) Run(t *testing.T, es *EvalState, td TestDesc) bool { +func (test *TestComment) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { return true } type SameTestEx struct { - Out Ex - In Ex + Out expreduceapi.Ex + In expreduceapi.Ex } -func (this *SameTestEx) Run(t *testing.T, es *EvalState, td TestDesc) bool { - succ, s := CasTestInner(es, this.In.Eval(es), this.Out.Eval(es), this.In.String(es), true, td.desc) +func (test *SameTestEx) run(t *testing.T, es expreduceapi.EvalStateInterface, td testDesc) bool { + stringParams := ActualStringFormArgsFull("InputForm", es) + succ, s := casTestInner(es, es.Eval(test.In), es.Eval(test.Out), test.In.StringForm(stringParams), true, td.desc) assert.True(t, succ, s) return succ } -func CasTestInner(es *EvalState, inTree Ex, outTree Ex, inStr string, test bool, desc string) (succ bool, s string) { - theTestTree := NewExpression([]Ex{ - NewSymbol("System`SameQ"), - NewExpression([]Ex{NewSymbol("System`Hold"), inTree}), - NewExpression([]Ex{NewSymbol("System`Hold"), outTree}), +func casTestInner(es expreduceapi.EvalStateInterface, inTree expreduceapi.Ex, outTree expreduceapi.Ex, inStr string, test bool, desc string) (succ bool, s string) { + theTestTree := atoms.NewExpression([]expreduceapi.Ex{ + atoms.NewSymbol("System`SameQ"), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Hold"), inTree}), + atoms.NewExpression([]expreduceapi.Ex{atoms.NewSymbol("System`Hold"), outTree}), }) - theTest := theTestTree.Eval(es) + theTest := es.Eval(theTestTree) - context, contextPath := DefinitionComplexityStringFormArgs() + context, contextPath := definitionComplexityStringFormArgs() var buffer bytes.Buffer buffer.WriteString("(") - buffer.WriteString(inTree.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es})) + buffer.WriteString(inTree.StringForm(expreduceapi.ToStringParams{Form: "InputForm", Context: context, ContextPath: contextPath, Esi: es})) if test { buffer.WriteString(") != (") } else { buffer.WriteString(") == (") } - buffer.WriteString(outTree.StringForm(ToStringParams{form: "InputForm", context: context, contextPath: contextPath, es: es})) + buffer.WriteString(outTree.StringForm(expreduceapi.ToStringParams{Form: "InputForm", Context: context, ContextPath: contextPath, Esi: es})) buffer.WriteString(")") buffer.WriteString("\n\tInput was: ") buffer.WriteString(inStr) @@ -96,7 +101,7 @@ func CasTestInner(es *EvalState, inTree Ex, outTree Ex, inStr string, test bool, buffer.WriteString(desc) } - resSym, resIsSym := theTest.(*Symbol) + resSym, resIsSym := theTest.(*atoms.Symbol) if !resIsSym { return false, buffer.String() } @@ -106,26 +111,20 @@ func CasTestInner(es *EvalState, inTree Ex, outTree Ex, inStr string, test bool, return resSym.Name == "System`False", buffer.String() } -func CasAssertSame(t *testing.T, es *EvalState, out string, in string) bool { - succ, s := CasTestInner(es, Interp(in, es).Eval(es), Interp(out, es).Eval(es), in, true, "") - assert.True(t, succ, s) - return succ -} - -func CasAssertDiff(t *testing.T, es *EvalState, out string, in string) bool { - succ, s := CasTestInner(es, Interp(in, es).Eval(es), Interp(out, es).Eval(es), in, false, "") +func casAssertSame(t *testing.T, es expreduceapi.EvalStateInterface, out string, in string) bool { + succ, s := casTestInner(es, es.Eval(parser.Interp(in, es)), es.Eval(parser.Interp(out, es)), in, true, "") assert.True(t, succ, s) return succ } -func CasAssertDescSame(t *testing.T, es *EvalState, out string, in string, desc string) bool { - succ, s := CasTestInner(es, Interp(in, es).Eval(es), Interp(out, es).Eval(es), in, true, desc) +func casAssertDiff(t *testing.T, es expreduceapi.EvalStateInterface, out string, in string) bool { + succ, s := casTestInner(es, es.Eval(parser.Interp(in, es)), es.Eval(parser.Interp(out, es)), in, false, "") assert.True(t, succ, s) return succ } -func CasAssertDescDiff(t *testing.T, es *EvalState, out string, in string, desc string) bool { - succ, s := CasTestInner(es, Interp(in, es).Eval(es), Interp(out, es).Eval(es), in, false, desc) +func casAssertDescSame(t *testing.T, es expreduceapi.EvalStateInterface, out string, in string, desc string) bool { + succ, s := casTestInner(es, es.Eval(parser.Interp(in, es)), es.Eval(parser.Interp(out, es)), in, true, desc) assert.True(t, succ, s) return succ } diff --git a/expreduce/testing_test.go b/expreduce/testing_test.go index b2d3c09..7d74a71 100644 --- a/expreduce/testing_test.go +++ b/expreduce/testing_test.go @@ -2,8 +2,10 @@ package expreduce import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/corywalker/expreduce/expreduce/parser" + "github.com/stretchr/testify/assert" ) func TestTesting(t *testing.T) { @@ -11,11 +13,11 @@ func TestTesting(t *testing.T) { es := NewEvalState() - CasAssertSame(t, es, " 1 ", " 1") - succ, s := CasTestInner(es, Interp(" 1. ", es).Eval(es), Interp("1 ", es).Eval(es), " 1. ", true, "") + casAssertSame(t, es, " 1 ", " 1") + succ, s := casTestInner(es, es.Eval(parser.Interp(" 1. ", es)), es.Eval(parser.Interp("1 ", es)), " 1. ", true, "") assert.False(t, succ, s) - CasAssertSame(t, es, "5.5", "1+1.5+3") - CasAssertDiff(t, es, "5.6", "1+1.5+3") - CasAssertSame(t, es, "9", "If[True, 9, 10]") - CasAssertDiff(t, es, " 1. ", " 1") + casAssertSame(t, es, "5.5", "1+1.5+3") + casAssertDiff(t, es, "5.6", "1+1.5+3") + casAssertSame(t, es, "9", "If[True, 9, 10]") + casAssertDiff(t, es, " 1. ", " 1") } diff --git a/expreduce/time_counter.go b/expreduce/time_counter.go deleted file mode 100644 index 2b7a3bc..0000000 --- a/expreduce/time_counter.go +++ /dev/null @@ -1,113 +0,0 @@ -package expreduce - -import ( - "bytes" - "fmt" - "sort" -) - -type TimeMap map[string]float64 -type CountMap map[string]int64 - -type TimeCounter struct { - times TimeMap - counts CountMap -} - -func (tc *TimeCounter) Init() { - tc.times = make(TimeMap) - tc.counts = make(CountMap) -} - -func (tc *TimeCounter) AddTime(key string, elapsed float64) { - tc.times[key] += elapsed - tc.counts[key] += 1 -} - -func (tc *TimeCounter) Update(other *TimeCounter) { - for k, v := range other.times { - tc.AddTime(k, v) - } -} - -func (tc *TimeCounter) TruncatedString(numToPrint int) string { - var buffer bytes.Buffer - n := map[float64][]string{} - var a []float64 - for k, v := range tc.times { - n[v] = append(n[v], k) - } - for k := range n { - a = append(a, k) - } - sort.Sort(sort.Reverse(sort.Float64Slice(a))) - numPrinted := 0 - for _, k := range a { - if numPrinted >= numToPrint { - break - } - for _, s := range n[k] { - count := tc.counts[s] - buffer.WriteString(fmt.Sprintf("%v, %v, %v\n", k, count, s)) - numPrinted++ - } - } - return buffer.String() -} - -func (tc *TimeCounter) String() string { - return tc.TruncatedString(25) -} - -// TimeCounterGroup - -type CounterGroupType uint8 - -const ( - CounterGroupDefTime CounterGroupType = iota + 1 - CounterGroupLhsDefTime - CounterGroupEvalTime - CounterGroupHeadEvalTime -) - -type TimeCounterGroup struct { - defTimeCounter TimeCounter - lhsDefTimeCounter TimeCounter - evalTimeCounter TimeCounter - headEvalTimeCounter TimeCounter -} - -func (tcg *TimeCounterGroup) Init() { - tcg.defTimeCounter.Init() - tcg.lhsDefTimeCounter.Init() - tcg.evalTimeCounter.Init() - tcg.headEvalTimeCounter.Init() -} - -func (tcg *TimeCounterGroup) AddTime(counter CounterGroupType, key string, elapsed float64) { - if counter == CounterGroupDefTime { - tcg.defTimeCounter.AddTime(key, elapsed) - } else if counter == CounterGroupLhsDefTime { - tcg.lhsDefTimeCounter.AddTime(key, elapsed) - } else if counter == CounterGroupEvalTime { - tcg.evalTimeCounter.AddTime(key, elapsed) - } else if counter == CounterGroupHeadEvalTime { - tcg.headEvalTimeCounter.AddTime(key, elapsed) - } -} - -func (tcg *TimeCounterGroup) Update(other *TimeCounterGroup) { - tcg.defTimeCounter.Update(&other.defTimeCounter) - tcg.lhsDefTimeCounter.Update(&other.lhsDefTimeCounter) - tcg.evalTimeCounter.Update(&other.evalTimeCounter) - tcg.headEvalTimeCounter.Update(&other.headEvalTimeCounter) -} - -func (tcg *TimeCounterGroup) String() string { - var buffer bytes.Buffer - buffer.WriteString(tcg.defTimeCounter.String() + "\n") - buffer.WriteString(tcg.lhsDefTimeCounter.String() + "\n") - buffer.WriteString(tcg.evalTimeCounter.String() + "\n") - buffer.WriteString(tcg.headEvalTimeCounter.String() + "\n") - return buffer.String() -} diff --git a/expreduce/timecounter/timecounter.go b/expreduce/timecounter/timecounter.go new file mode 100644 index 0000000..3fad4d8 --- /dev/null +++ b/expreduce/timecounter/timecounter.go @@ -0,0 +1,125 @@ +// Package timecounter provides functionality for aggregating times based on a +// string key. +package timecounter + +import ( + "bytes" + "fmt" + "sort" +) + +type timeMap map[string]float64 +type countMap map[string]int64 + +type timeCounter struct { + times timeMap + counts countMap +} + +func (tc *timeCounter) init() { + tc.times = make(timeMap) + tc.counts = make(countMap) +} + +func (tc *timeCounter) addTime(key string, elapsed float64) { + tc.times[key] += elapsed + tc.counts[key]++ +} + +func (tc *timeCounter) update(other *timeCounter) { + for k, v := range other.times { + tc.addTime(k, v) + } +} + +func (tc *timeCounter) truncatedString(numToPrint int) string { + var buffer bytes.Buffer + n := map[float64][]string{} + var a []float64 + for k, v := range tc.times { + n[v] = append(n[v], k) + } + for k := range n { + a = append(a, k) + } + sort.Sort(sort.Reverse(sort.Float64Slice(a))) + numPrinted := 0 + for _, k := range a { + if numPrinted >= numToPrint { + break + } + for _, s := range n[k] { + count := tc.counts[s] + buffer.WriteString(fmt.Sprintf("%v, %v, %v\n", k, count, s)) + numPrinted++ + } + } + return buffer.String() +} + +func (tc *timeCounter) string() string { + return tc.truncatedString(25) +} + +// Group + +type counterGroupType uint8 + +const ( + // CounterGroupDefTime is the counter for definition times. + CounterGroupDefTime counterGroupType = iota + 1 + // CounterGroupLHSDefTime is the counter for LHS definition times. + CounterGroupLHSDefTime + // CounterGroupEvalTime is the counter for eval times. + CounterGroupEvalTime + // CounterGroupHeadEvalTime is the counter for head eval times. + CounterGroupHeadEvalTime +) + +// Group collects eval-related timeCounters. +type Group struct { + defTimeCounter timeCounter + lhsDefTimeCounter timeCounter + evalTimeCounter timeCounter + headEvalTimeCounter timeCounter +} + +// Init initializes the Group with empty maps. +func (tcg *Group) Init() { + tcg.defTimeCounter.init() + tcg.lhsDefTimeCounter.init() + tcg.evalTimeCounter.init() + tcg.headEvalTimeCounter.init() +} + +// AddTime adds a floating-point time to a particular timeCounter, selected with +// a counterGroupType. +func (tcg *Group) AddTime(counter counterGroupType, key string, elapsed float64) { + if counter == CounterGroupDefTime { + tcg.defTimeCounter.addTime(key, elapsed) + } else if counter == CounterGroupLHSDefTime { + tcg.lhsDefTimeCounter.addTime(key, elapsed) + } else if counter == CounterGroupEvalTime { + tcg.evalTimeCounter.addTime(key, elapsed) + } else if counter == CounterGroupHeadEvalTime { + tcg.headEvalTimeCounter.addTime(key, elapsed) + } +} + +// Update adds another Group to this one. +func (tcg *Group) Update(other *Group) { + tcg.defTimeCounter.update(&other.defTimeCounter) + tcg.lhsDefTimeCounter.update(&other.lhsDefTimeCounter) + tcg.evalTimeCounter.update(&other.evalTimeCounter) + tcg.headEvalTimeCounter.update(&other.headEvalTimeCounter) +} + +// Prints the counter group as a formatted string. +func (tcg *Group) String() string { + var buffer bytes.Buffer + buffer.WriteString(tcg.defTimeCounter.string() + "\n") + buffer.WriteString(tcg.lhsDefTimeCounter.string() + "\n") + buffer.WriteString(tcg.evalTimeCounter.string() + "\n") + buffer.WriteString(tcg.headEvalTimeCounter.string() + "\n") + return buffer.String() +} diff --git a/expreduce/utils.go b/expreduce/utils.go index b24ba93..6dda500 100644 --- a/expreduce/utils.go +++ b/expreduce/utils.go @@ -1,51 +1,13 @@ package expreduce -import ( - "bytes" -) - -func ExArrayToString(exArray []Ex, es *EvalState) string { - var buffer bytes.Buffer - buffer.WriteString("{") - for i, e := range exArray { - buffer.WriteString(e.String(es)) - if i != len(exArray)-1 { - buffer.WriteString(", ") - } - } - buffer.WriteString("}") - return buffer.String() -} - -func PFArrayToString(pfArray []parsedForm, es *EvalState) string { - var buffer bytes.Buffer - buffer.WriteString("{") - for i, e := range pfArray { - buffer.WriteString(e.origForm.String(es)) - if i != len(pfArray)-1 { - buffer.WriteString(", ") - } - } - buffer.WriteString("}") - return buffer.String() -} - -func ExArrayDeepCopy(exArray []Ex) []Ex { - res := make([]Ex, len(exArray)) - for i, e := range exArray { - res[i] = e.DeepCopy() - } - return res -} - -func Max(x, y int) int { +func max(x, y int) int { if x > y { return x } return y } -func Min(x, y int) int { +func min(x, y int) int { if x < y { return x } diff --git a/pkg/expreduceapi/cas.go b/pkg/expreduceapi/cas.go new file mode 100644 index 0000000..3b54ad7 --- /dev/null +++ b/pkg/expreduceapi/cas.go @@ -0,0 +1,154 @@ +package expreduceapi + +import ( + "github.com/corywalker/expreduce/expreduce/timecounter" + gologging "github.com/op/go-logging" +) + +type evalStateForStringer interface { + GetStringFn(headStr string) (ToStringFnType, bool) + // Used by Definition[] + GetDefined(name string) (Def, bool) +} + +type ToStringFnType (func(ExpressionInterface, ToStringParams) (bool, string)) +type ToStringParams struct { + Form string + Context StringInterface + ContextPath ExpressionInterface + PreviousHead string + Esi evalStateForStringer +} + +// Ex is the interface that fundamental types must implement. +type Ex interface { + StringForm(params ToStringParams) string + IsEqual(b Ex) string + DeepCopy() Ex + Copy() Ex + NeedsEval() bool + Hash() uint64 +} + +type LoggingInterface interface { + Debugf(fmt string, args ...interface{}) + Infof(fmt string, args ...interface{}) + Errorf(fmt string, args ...interface{}) + DebugOn(level gologging.Level) + DebugOff() + SetDebugState(newState bool) + IsProfiling() bool + SetProfiling(profiling bool) + SetUpLogging() +} + +type EvalStateInterface interface { + LoggingInterface + + Eval(expr Ex) Ex + + GetDefined(name string) (Def, bool) + GetStringFn(headStr string) (ToStringFnType, bool) + Init(loadAllDefs bool) + IsDef(name string) bool + GetDef(name string, lhs Ex) (Ex, bool, ExpressionInterface) + GetSymDef(name string) (Ex, bool) + MarkSeen(name string) + Define(lhs Ex, rhs Ex) + ClearAll() + Clear(name string) + GetDefinedSnapshot() DefinitionMap + IsFrozen() bool + SetFrozen(frozen bool) + IsInterrupted() bool + GetStringDef(name string, defaultVal string) string + GetListDef(name string) ExpressionInterface + Throw(e ExpressionInterface) + HasThrown() bool + Thrown() ExpressionInterface + ProcessTopLevelResult(in Ex, out Ex) Ex + + GetLogger() LoggingInterface + GetTrace() ExpressionInterface + SetTrace(newTrace ExpressionInterface) + GetDefinedMap() DefinitionMap + GetReapSown() ExpressionInterface + SetReapSown(ex ExpressionInterface) + + GetTimeCounter() *timecounter.Group + GetStreamManager() StreamManager +} + +type ExpressionInterface interface { + Ex + + GetParts() []Ex + GetPart(i int) Ex + SetParts(newParts []Ex) + ClearHashes() + + Len() int + Less(i, j int) bool + Swap(i, j int) + AppendEx(e Ex) + AppendExArray(e []Ex) + HeadStr() string +} + +type StringInterface interface { + Ex + + GetValue() string +} + +type DefinitionMap interface { + Set(key string, value Def) + Get(key string) (Def, bool) + GetDef(key string) Def + LockKey(key string) + UnlockKey(key string) + CopyDefs() DefinitionMap +} + +type StreamManager interface { + WriteString(streamName string, streamIndex int64, toWrite string) bool + AsExpr() Ex +} + +type DownValue struct { + Rule ExpressionInterface + Specificity int +} + +type EvalFnType (func(ExpressionInterface, EvalStateInterface) Ex) +type Def struct { + Downvalues []DownValue + Attributes Attributes + DefaultExpr Ex + + // A function defined here will override downvalues. + LegacyEvalFn EvalFnType +} + +// Functions for working with the attributes of symbols: +type Attributes struct { + Orderless bool + Flat bool + OneIdentity bool + Listable bool + Constant bool + NumericFunction bool + Protected bool + Locked bool + ReadProtected bool + HoldFirst bool + HoldRest bool + HoldAll bool + HoldAllComplete bool + NHoldFirst bool + NHoldRest bool + NHoldAll bool + SequenceHold bool + Temporary bool + Stub bool +}