Skip to content

Commit

Permalink
patterns: mix test working, readme docs; better SetTensor, Set functi…
Browse files Browse the repository at this point in the history
…ons.
  • Loading branch information
rcoreilly committed Dec 30, 2024
1 parent bcecd20 commit 3a09324
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 14 deletions.
274 changes: 274 additions & 0 deletions patterns/patterns_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
package patterns

import (
"testing"

"cogentcore.org/lab/tensorfs"
"github.com/stretchr/testify/assert"
)

func TestABAC(t *testing.T) {
NewRand(10)
dir, _ := tensorfs.NewDir("test")
empty := dir.Float32("empty", 6, 3, 3)
a := dir.Float32("A", 6, 3, 3)
b := dir.Float32("B", 6, 3, 3)
nOn := NFromPct(0.3, 9)
nDiff := NFromPct(0.4, nOn)
// AddVocabPermutedBinary(m, "A", 6, 3, 3, 0.3, 0.4)
PermutedBinaryMinDiff(a, nOn, 1, 0, nDiff)
// fmt.Println(a)
// AddVocabDrift(m, "B", 6, 0.2, "A", 0) // nOn=4*(3*3*0.3); nDrift=nOn*0.5
PermutedBinaryMinDiff(b, nOn, 1, 0, nDiff)
// fmt.Println(b)
ctx1 := dir.Float32("ctxt1")
// AddVocabRepeat(m, "ctxt1", 6, "A", 0)
ReplicateRows(ctx1, a.SubSpace(0), 6)
// fmt.Println(ctx1)
// VocabConcat(m, "AB-C", []string{"A", "B"})
ab := dir.Float32("ab", 0, 3, 3)
ab.AppendFrom(a)
ab.AppendFrom(b)
// fmt.Println(ab)
// VocabSlice(m, "AB-C", []string{"A'", "B'"}, []int{0, 6, 12}) // 3 cutoffs for 2 vocabs
SplitRows(dir, ab, []string{"asp", "bsp"}, 6)
// fmt.Println(dir.Float32("asp"), dir.Float32("bsp"))
// VocabShuffle(m, []string{"B'"})
bshuf := Shuffle(b)
dir.Set("bshuf", bshuf)
// fmt.Println(bshuf)
// AddVocabClone(m, "B''", "B'")

exempty := `empty [6 3 3]
[r r c] [0] [1] [2]
[0 0] 0 0 0
[0 1] 0 0 0
[0 2] 0 0 0
[1 0] 0 0 0
[1 1] 0 0 0
[1 2] 0 0 0
[2 0] 0 0 0
[2 1] 0 0 0
[2 2] 0 0 0
[3 0] 0 0 0
[3 1] 0 0 0
[3 2] 0 0 0
[4 0] 0 0 0
[4 1] 0 0 0
[4 2] 0 0 0
[5 0] 0 0 0
[5 1] 0 0 0
[5 2] 0 0 0
`
assert.Equal(t, exempty, empty.String())

exa := `A [6 3 3]
[r r c] [0] [1] [2]
[0 0] 0 1 0
[0 1] 1 0 1
[0 2] 0 0 0
[1 0] 1 0 1
[1 1] 1 0 0
[1 2] 0 0 0
[2 0] 0 0 0
[2 1] 1 0 0
[2 2] 1 1 0
[3 0] 0 1 0
[3 1] 0 0 0
[3 2] 1 0 1
[4 0] 1 0 1
[4 1] 0 1 0
[4 2] 0 0 0
[5 0] 1 0 0
[5 1] 0 0 1
[5 2] 1 0 0
`

assert.Equal(t, exa, a.String())

exb := `B [6 3 3]
[r r c] [0] [1] [2]
[0 0] 1 0 0
[0 1] 0 1 0
[0 2] 1 0 0
[1 0] 1 0 0
[1 1] 1 1 0
[1 2] 0 0 0
[2 0] 0 0 0
[2 1] 0 1 1
[2 2] 0 0 1
[3 0] 1 1 0
[3 1] 0 0 0
[3 2] 0 1 0
[4 0] 0 0 0
[4 1] 1 1 0
[4 2] 1 0 0
[5 0] 0 0 0
[5 1] 0 0 1
[5 2] 1 1 0
`

// drift version:
// `B [6 3 3]
// [r r c] [0] [1] [2]
// [0 0] 0 1 0
// [0 1] 1 0 1
// [0 2] 0 0 0
// [1 0] 0 1 0
// [1 1] 1 0 1
// [1 2] 0 0 0
// [2 0] 0 1 0
// [2 1] 1 0 1
// [2 2] 0 0 0
// [3 0] 0 1 1
// [3 1] 1 0 0
// [3 2] 0 0 0
// [4 0] 0 1 1
// [4 1] 1 0 0
// [4 2] 0 0 0
// [5 0] 0 1 1
// [5 1] 1 0 0
// [5 2] 0 0 0
// `

assert.Equal(t, exb, b.String())

exctxt := `ctxt1 [6 3 3]
[r r c] [0] [1] [2]
[0 0] 0 1 0
[0 1] 1 0 1
[0 2] 0 0 0
[1 0] 0 1 0
[1 1] 1 0 1
[1 2] 0 0 0
[2 0] 0 1 0
[2 1] 1 0 1
[2 2] 0 0 0
[3 0] 0 1 0
[3 1] 1 0 1
[3 2] 0 0 0
[4 0] 0 1 0
[4 1] 1 0 1
[4 2] 0 0 0
[5 0] 0 1 0
[5 1] 1 0 1
[5 2] 0 0 0
`

assert.Equal(t, exctxt, ctx1.String())

exabc := `ab [12 3 3]
[r r c] [0] [1] [2]
[0 0] 0 1 0
[0 1] 1 0 1
[0 2] 0 0 0
[1 0] 1 0 1
[1 1] 1 0 0
[1 2] 0 0 0
[2 0] 0 0 0
[2 1] 1 0 0
[2 2] 1 1 0
[3 0] 0 1 0
[3 1] 0 0 0
[3 2] 1 0 1
[4 0] 1 0 1
[4 1] 0 1 0
[4 2] 0 0 0
[5 0] 1 0 0
[5 1] 0 0 1
[5 2] 1 0 0
[6 0] 1 0 0
[6 1] 0 1 0
[6 2] 1 0 0
[7 0] 1 0 0
[7 1] 1 1 0
[7 2] 0 0 0
[8 0] 0 0 0
[8 1] 0 1 1
[8 2] 0 0 1
[9 0] 1 1 0
[9 1] 0 0 0
[9 2] 0 1 0
[10 0] 0 0 0
[10 1] 1 1 0
[10 2] 1 0 0
[11 0] 0 0 0
[11 1] 0 0 1
[11 2] 1 1 0
`

// fmt.Println(ab)
assert.Equal(t, exabc, ab.String())

//////// Mix

mix := dir.Float32("mix")
Mix(mix, 12, a, b, ctx1, ctx1, empty, b)
mix.SetShapeSizes(6, 3, 2, 3, 3)
// InitPats(dt, "TrainAB", "describe", "Input", "ECout", 6, 3, 2, 3, 3)
// MixPats(dt, m, "Input", []string{"A", "B", "ctxt1", "ctxt1", "empty", "B'"})

// try shuffle
// Shuffle(dt, []int{0, 1, 2, 3, 4, 5}, []string{"Input", "ECout"}, false)

exmix := `mix [6 3 2 3 3]
[r r c r c] [0 0] [0 1] [0 2] [1 0] [1 1] [1 2]
[0 0 0] 0 1 0 1 0 0
[0 0 1] 1 0 1 0 1 0
[0 0 2] 0 0 0 1 0 0
[0 1 0] 0 1 0 0 1 0
[0 1 1] 1 0 1 1 0 1
[0 1 2] 0 0 0 0 0 0
[0 2 0] 0 0 0 1 0 0
[0 2 1] 0 0 0 0 1 0
[0 2 2] 0 0 0 1 0 0
[1 0 0] 1 0 1 1 0 0
[1 0 1] 1 0 0 1 1 0
[1 0 2] 0 0 0 0 0 0
[1 1 0] 0 1 0 0 1 0
[1 1 1] 1 0 1 1 0 1
[1 1 2] 0 0 0 0 0 0
[1 2 0] 0 0 0 1 0 0
[1 2 1] 0 0 0 1 1 0
[1 2 2] 0 0 0 0 0 0
[2 0 0] 0 0 0 0 0 0
[2 0 1] 1 0 0 0 1 1
[2 0 2] 1 1 0 0 0 1
[2 1 0] 0 1 0 0 1 0
[2 1 1] 1 0 1 1 0 1
[2 1 2] 0 0 0 0 0 0
[2 2 0] 0 0 0 0 0 0
[2 2 1] 0 0 0 0 1 1
[2 2 2] 0 0 0 0 0 1
[3 0 0] 0 1 0 1 1 0
[3 0 1] 0 0 0 0 0 0
[3 0 2] 1 0 1 0 1 0
[3 1 0] 0 1 0 0 1 0
[3 1 1] 1 0 1 1 0 1
[3 1 2] 0 0 0 0 0 0
[3 2 0] 0 0 0 1 1 0
[3 2 1] 0 0 0 0 0 0
[3 2 2] 0 0 0 0 1 0
[4 0 0] 1 0 1 0 0 0
[4 0 1] 0 1 0 1 1 0
[4 0 2] 0 0 0 1 0 0
[4 1 0] 0 1 0 0 1 0
[4 1 1] 1 0 1 1 0 1
[4 1 2] 0 0 0 0 0 0
[4 2 0] 0 0 0 0 0 0
[4 2 1] 0 0 0 1 1 0
[4 2 2] 0 0 0 1 0 0
[5 0 0] 1 0 0 0 0 0
[5 0 1] 0 0 1 0 0 1
[5 0 2] 1 0 0 1 1 0
[5 1 0] 0 1 0 0 1 0
[5 1 1] 1 0 1 1 0 1
[5 1 2] 0 0 0 0 0 0
[5 2 0] 0 0 0 0 0 0
[5 2 1] 0 0 0 0 0 1
[5 2 2] 0 0 0 1 1 0
`

// fmt.Println(mix)
assert.Equal(t, exmix, mix.String())
}
4 changes: 2 additions & 2 deletions tensorfs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The hierarchical structure of a filesystem naturally supports various kinds of f

# Usage

There are two main APIs, one for direct usage within Go, and another that is used by the `goal` framework for interactive shell-based access, which always operates relative to a current working directory.
There are two main APIs, one for direct usage within Go, and another that is used by the [goal](../goal) framework for interactive shell-based access, which always operates relative to a current working directory.

## Go API

Expand All @@ -40,7 +40,7 @@ There are also a few other variants of the `Value` functionality:
* `Scalar` calls `Value` with a size of 1.
* `Values` makes multiple tensor values of the same shape, with a final variadic list of names.
* `ValueType` takes a `reflect.Kind` arg for the data type, which can then be a variable.
* `NewForTensor` creates a node for an existing tensor.
* `SetTensor` sets a tensor to a node of given name, creating the node if needed. This is also available as the `Set` method on a directory node.

`DirTable` returns a `table.Table` with all the tensors under a given directory node, which can then be used for making plots or doing other forms of data analysis. This works best when each tensor has the same outer-most row dimension. The table is persistent and very efficient, using direct pointers to the underlying tensor values.

Expand Down
12 changes: 7 additions & 5 deletions tensorfs/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ func init() {
}

// Record saves given tensor to current directory with given name.
func Record(tsr tensor.Tensor, name string) error {
_, err := NewForTensor(CurDir, tsr, name)
return err // todo: could prompt about conficts, or always overwrite existing?
func Record(tsr tensor.Tensor, name string) {
if CurDir == nil {
CurDir = CurRoot
}
SetTensor(CurDir, tsr, name)
}

// Chdir changes the current working tensorfs directory to the named directory.
Expand Down Expand Up @@ -151,6 +153,6 @@ func Set(name string, tsr tensor.Tensor) error {
}
cd = d
}
_, err = NewForTensor(cd, tsr, name)
return errors.Log(err)
SetTensor(cd, tsr, name)
return nil
}
21 changes: 14 additions & 7 deletions tensorfs/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,22 @@ func ValueType(dir *Node, name string, typ reflect.Kind, sizes ...int) tensor.Va
return tsr
}

// NewForTensor creates a new Node node for given existing tensor with given name.
// If the name already exists, that Node is returned with [fs.ErrExists] error.
func NewForTensor(dir *Node, tsr tensor.Tensor, name string) (*Node, error) {
nd, err := newNode(dir, name)
if err != nil {
return nd, err
// SetTensor creates / recycles a node and sets to given existing tensor with given name.
func SetTensor(dir *Node, tsr tensor.Tensor, name string) *Node {
nd := dir.Node(name)
if nd != nil {
nd.Tensor = tsr
} else {
nd, _ = newNode(dir, name)
}
nd.Tensor = tsr
return nd, nil
return nd
}

// Set creates / returns a Node with given name setting value to given Tensor,
// in given directory [Node]. Calls [SetTensor].
func (dir *Node) Set(name string, tsr tensor.Tensor) *Node {
return SetTensor(dir, tsr, name)
}

// DirTable returns a [table.Table] with all of the tensor values under
Expand Down

0 comments on commit 3a09324

Please sign in to comment.