Skip to content

Commit

Permalink
Merge pull request #189 from corywalker/corywalker
Browse files Browse the repository at this point in the history
Corywalker
  • Loading branch information
corywalker committed Nov 9, 2018
2 parents b980d9d + 668a657 commit a2d2b6e
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 14 deletions.
9 changes: 9 additions & 0 deletions expreduce/atoms/ex_expression.go
Expand Up @@ -274,6 +274,15 @@ func newEmptyExpressionOfLength(n int) *Expression {
}
}

// NewStringList transforms a list of strings in Go format into Expreduce format.
func NewStringList(items []string) *Expression {
list := NewHead("System`List")
for _, item := range items {
list.AppendEx(NewString(item))
}
return list
}

func (thisExpr *Expression) GetParts() []expreduceapi.Ex {
return thisExpr.Parts
}
Expand Down
14 changes: 14 additions & 0 deletions expreduce/atoms/gob.go
@@ -0,0 +1,14 @@
package atoms

import "encoding/gob"

// RegisterGobAtoms performs gob registration for the atoms package.
func RegisterGobAtoms() {
gob.RegisterName("E", &Expression{})
gob.RegisterName("S", &Symbol{})
gob.RegisterName("C", &Complex{})
gob.RegisterName("I", &Integer{})
gob.RegisterName("R", &Rational{})
gob.RegisterName("F", &Flt{})
gob.RegisterName("T", &String{})
}
8 changes: 8 additions & 0 deletions expreduce/builtin_rubi.go
Expand Up @@ -5,5 +5,13 @@ func getRubiDefinitions() (defs []Definition) {
Name: "LoadRubi",
expreduceSpecific: true,
})
defs = append(defs, Definition{
Name: "LoadRubiSnapshot",
expreduceSpecific: true,
})
defs = append(defs, Definition{
Name: "SaveRubiSnapshot",
expreduceSpecific: true,
})
return
}
129 changes: 119 additions & 10 deletions expreduce/builtin_system.go
@@ -1,13 +1,17 @@
package expreduce

import (
"bytes"
"encoding/gob"
"flag"
"fmt"
"io/ioutil"
"log"
"math/big"
"os"
"regexp"
"runtime/pprof"
"sort"
"strings"
"time"

Expand All @@ -19,6 +23,13 @@ import (

var mymemprofile = flag.String("mymemprofile", "", "write memory profile to this file")

var exprFileHeader = []byte{26, 166, 245, 29, 69, 251, 144, 0}

type encodedDef struct {
Name string
Def expreduceapi.Def
}

func hashEx(e expreduceapi.Ex) uint64 {
return e.Hash()
}
Expand Down Expand Up @@ -69,19 +80,19 @@ func exprToN(es expreduceapi.EvalStateInterface, e expreduceapi.Ex) expreduceapi
return e.DeepCopy()
}

func tryReadFile(fn expreduceapi.Ex, es expreduceapi.EvalStateInterface) (string, string, bool) {
func tryReadFile(fn expreduceapi.Ex, es expreduceapi.EvalStateInterface) ([]byte, string, bool) {
pathSym := atoms.NewSymbol("System`$Path")
path, isDef, _ := es.GetDef("System`$Path", pathSym)
if !isDef {
return "", "", false
return []byte{}, "", false
}
pathL, pathIsList := atoms.HeadAssertion(path, "System`List")
if !pathIsList {
return "", "", false
return []byte{}, "", false
}
filenameString, fnIsStr := fn.(*atoms.String)
if !fnIsStr {
return "", "", false
return []byte{}, "", false
}
rawFn := filenameString.Val

Expand All @@ -90,7 +101,7 @@ func tryReadFile(fn expreduceapi.Ex, es expreduceapi.EvalStateInterface) (string

fileData, err := Asset("resources/" + rawFn[8:])
if err == nil {
return string(fileData), rawFn, true
return fileData, rawFn, true
}
}

Expand All @@ -111,10 +122,9 @@ func tryReadFile(fn expreduceapi.Ex, es expreduceapi.EvalStateInterface) (string
if err != nil {
continue
}
fileData := string(dat)
return fileData, rawPath, true
return dat, rawPath, true
}
return "", "", false
return []byte{}, "", false
}

func snagUnique(context string, prefix string, es expreduceapi.EvalStateInterface) (string, bool) {
Expand Down Expand Up @@ -640,7 +650,77 @@ func getSystemDefinitions() (defs []Definition) {
if !ok {
return atoms.NewSymbol("System`$Failed")
}
return EvalInterpMany(fileData, rawPath, es)
if len(fileData) >= len(exprFileHeader) && bytes.Equal(fileData[:len(exprFileHeader)], exprFileHeader) {

// TODO: Read as a stream and not a byte string.
r := bytes.NewReader(fileData[len(exprFileHeader):])
atoms.RegisterGobAtoms()
decoder := gob.NewDecoder(r)
definitions := []encodedDef{}
if err := decoder.Decode(&definitions); err != nil {
panic(err)
}

for _, def := range definitions {
es.SetDefined(def.Name, def.Def)
}

return atoms.NewSymbol("System`Null")
}
return EvalInterpMany(string(fileData), rawPath, es)
},
})
defs = append(defs, Definition{
Name: "Save",
legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex {
if this.Len() != 2 {
return this
}

filenameStr, ok := this.GetPart(1).(*atoms.String)
if !ok {
return this
}
filename := filenameStr.GetValue()

definitions := []encodedDef{}
symList, ok := atoms.HeadAssertion(this.GetPart(2), "System`List")
if !ok {
return this
}
for _, symEx := range symList.GetParts()[1:] {
symStr, symIsStr := symEx.(*atoms.String)
if !symIsStr {
return this
}
symName := symStr.GetValue()
def, ok := es.GetDefined(symName)
if !ok {
return this
}
definitions = append(definitions, encodedDef{
Name: symName,
Def: def,
})
}
if len(definitions) == 0 {
return this
}

atoms.RegisterGobAtoms()

file, err := os.Create(filename)
if err == nil {
// Write the header.
file.Write(exprFileHeader)
encoder := gob.NewEncoder(file)
if err := encoder.Encode(definitions); err != nil {
panic(err)
}
}
file.Close()

return atoms.NewSymbol("System`Null")
},
})
defs = append(defs, Definition{
Expand Down Expand Up @@ -692,7 +772,7 @@ func getSystemDefinitions() (defs []Definition) {
if !ok {
return atoms.NewSymbol("System`$Failed")
}
return ReadList(fileData, rawPath, es)
return ReadList(string(fileData), rawPath, es)
},
})
defs = append(defs, Definition{Name: "BeginPackage"})
Expand Down Expand Up @@ -841,5 +921,34 @@ func getSystemDefinitions() (defs []Definition) {
return es.GetStreamManager().AsExpr()
},
})
defs = append(defs, Definition{
Name: "Names",
legacyEvalFn: func(this expreduceapi.ExpressionInterface, es expreduceapi.EvalStateInterface) expreduceapi.Ex {
regex := ""
if this.Len() == 0 {
regex = ".*"
}
if this.Len() == 1 {
filter, filterIsString := this.GetPart(1).(*atoms.String)
if filterIsString {
replacedVal := strings.Replace(filter.GetValue(), "*", ".*", -1)
regex = "^" + replacedVal + "$"
}
}
if regex == "" {
fmt.Println("Unsupported call to Names.")
return this
}
var namesRegex = regexp.MustCompile(regex)
names := []string{}
for _, name := range es.GetDefinedMap().Keys() {
if namesRegex.MatchString(name) {
names = append(names, name)
}
}
sort.Strings(names)
return atoms.NewStringList(names)
},
})
return
}
4 changes: 4 additions & 0 deletions expreduce/definition_map.go
Expand Up @@ -45,6 +45,10 @@ func (dm threadSafeDefinitionMap) UnlockKey(key string) {
shard.Unlock()
}

func (dm threadSafeDefinitionMap) Keys() []string {
return dm.internalMap.Keys()
}

func (dm threadSafeDefinitionMap) CopyDefs() expreduceapi.DefinitionMap {
out := newDefinitionMap()
for mapTuple := range dm.internalMap.IterBuffered() {
Expand Down
4 changes: 4 additions & 0 deletions expreduce/evalstate.go
Expand Up @@ -39,6 +39,10 @@ func (es *EvalState) GetDefined(name string) (expreduceapi.Def, bool) {
return es.GetDefinedMap().Get(name)
}

func (es *EvalState) SetDefined(name string, def expreduceapi.Def) {
es.GetDefinedMap().Set(name, def)
}

func (es *EvalState) GetStringFn(headStr string) (expreduceapi.ToStringFnType, bool) {
fn, ok := es.toStringFns[headStr]
return fn, ok
Expand Down
8 changes: 4 additions & 4 deletions expreduce/resources.go

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions expreduce/resources/rubi.m
Expand Up @@ -20,3 +20,10 @@
ESameTest[-(3/8) ArcTanh[Cos[a+x]]-3/8 Cot[a+x] Csc[a+x]-1/4 Cot[a+x] Csc[a+x]^3, Rubi`Int[csc[a+x]^5,x]],
]
};

expreduceRubiSnapshotLoc = "/tmp/rubi.expred";
LoadRubiSnapshot[] := (
Get[expreduceRubiSnapshotLoc];
$ContextPath = Prepend[$ContextPath, "Rubi`"];
);
SaveRubiSnapshot[] := Save[expreduceRubiSnapshotLoc, "Rubi`*"];
14 changes: 14 additions & 0 deletions expreduce/resources/system.m
Expand Up @@ -127,6 +127,10 @@
Get::usage = "`Get[file]` loads `file` and returns the last expression.";
Attributes[Get] = {Protected};

Save::usage = "`Save[filename, {sym1, sym2, ...}]` saves a list of symbols into a file."
Save[fn_String, pattern_String] := Save[fn, syms] /. syms -> Names[pattern];
Attributes[Save] = {HoldRest, Protected};

Module::usage = "`Module[{locals}, expr]` evaluates `expr` with the local variables `locals`.";
Attributes[Module] = {HoldAll, Protected};
Tests`Module = {
Expand Down Expand Up @@ -353,3 +357,13 @@
ESameTest[{OutputStream["stdout", 1], OutputStream["stderr", 2]}, Streams[]],
]
};

Names::usage = "`Names[]` returns a list of all defined symbols.
`Names[\"pattern\"]` returns a list of all defined symbols matching the regex pattern.";
Attributes[Names] = {Protected};
Tests`Names = {
ETests[
ESameTest[True, Length[Names[]] > 1],
]
};
2 changes: 2 additions & 0 deletions pkg/expreduceapi/cas.go
Expand Up @@ -48,6 +48,7 @@ type EvalStateInterface interface {
Eval(expr Ex) Ex

GetDefined(name string) (Def, bool)
SetDefined(name string, def Def)
GetStringFn(headStr string) (ToStringFnType, bool)
Init(loadAllDefs bool)
IsDef(name string) bool
Expand Down Expand Up @@ -107,6 +108,7 @@ type DefinitionMap interface {
GetDef(key string) Def
LockKey(key string)
UnlockKey(key string)
Keys() []string
CopyDefs() DefinitionMap
}

Expand Down

0 comments on commit a2d2b6e

Please sign in to comment.