Skip to content

Commit 5f7609e

Browse files
committed
brain/*: remove forgetting by tuples
It was complex to implement and not really the right thing. Now that we record traces of generated messages, we don't need it. Resolves #44.
1 parent cc976d0 commit 5f7609e

File tree

8 files changed

+0
-1037
lines changed

8 files changed

+0
-1037
lines changed

brain/braintest/braintest.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
// If a brain cannot be created without error, new should call t.Fatal.
1919
func Test(ctx context.Context, t *testing.T, new func(context.Context) brain.Brain) {
2020
t.Run("speak", testSpeak(ctx, new(ctx)))
21-
t.Run("forget", testForget(ctx, new(ctx)))
2221
t.Run("forgetMessage", testForgetMessage(ctx, new(ctx)))
2322
t.Run("forgetDuring", testForgetDuring(ctx, new(ctx)))
2423
t.Run("combinatoric", testCombinatoric(ctx, new(ctx)))
@@ -183,38 +182,6 @@ func testSpeak(ctx context.Context, br brain.Brain) func(t *testing.T) {
183182
}
184183
}
185184

186-
// testForget tests that a brain forgets what it forgets.
187-
func testForget(ctx context.Context, br brain.Brain) func(t *testing.T) {
188-
return func(t *testing.T) {
189-
learn(ctx, t, br)
190-
if err := brain.Forget(ctx, br, "kessoku", messages[0].Tokens()); err != nil {
191-
t.Errorf("couldn't forget: %v", err)
192-
}
193-
for range 100 {
194-
s, trace, err := brain.Speak(ctx, br, "kessoku", "")
195-
if err != nil {
196-
t.Errorf("couldn't speak: %v", err)
197-
}
198-
if strings.Contains(s, "bocchi") {
199-
t.Errorf("remembered that which must be forgotten: %q", s)
200-
}
201-
if trace[len(trace)-1] == messages[0].ID {
202-
t.Errorf("id %q should have been forgotten but was used in %q", messages[0].ID, trace)
203-
}
204-
}
205-
for range 10000 {
206-
s, _, err := brain.Speak(ctx, br, "sickhack", "")
207-
if err != nil {
208-
t.Errorf("couldn't speak: %v", err)
209-
}
210-
if strings.Contains(s, "bocchi") {
211-
return
212-
}
213-
}
214-
t.Error("didn't see bocchi in many attempts; deleted from wrong tag?")
215-
}
216-
}
217-
218185
// testForgetMessage tests that a brain can forget messages by ID.
219186
func testForgetMessage(ctx context.Context, br brain.Brain) func(t *testing.T) {
220187
return func(t *testing.T) {

brain/kvbrain/forget.go

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,11 @@ package kvbrain
33
import (
44
"bytes"
55
"context"
6-
"errors"
76
"fmt"
87
"slices"
9-
"strings"
108
"sync"
119
"time"
1210

13-
"github.com/dgraph-io/badger/v4"
14-
15-
"github.com/zephyrtronium/robot/brain"
1611
"github.com/zephyrtronium/robot/userhash"
1712
)
1813

@@ -94,58 +89,6 @@ func (p *past) findUser(user userhash.Hash) [][]byte {
9489
return r
9590
}
9691

97-
// Forget removes a set of recorded tuples. The tuples provided are as for
98-
// Learn. If a tuple has been recorded multiple times, only the first
99-
// should be deleted. If a tuple has not been recorded, it should be
100-
// ignored.
101-
func (br *Brain) Forget(ctx context.Context, tag string, tuples []brain.Tuple) error {
102-
// Sort tuples so that we always seek forward.
103-
slices.SortFunc(tuples, func(a, b brain.Tuple) int {
104-
p := slices.Compare(a.Prefix, b.Prefix)
105-
if p == 0 {
106-
p = strings.Compare(a.Suffix, b.Suffix)
107-
}
108-
return p
109-
})
110-
err := br.knowledge.Update(func(txn *badger.Txn) error {
111-
var errs error
112-
opts := badger.DefaultIteratorOptions
113-
it := txn.NewIterator(opts)
114-
defer it.Close()
115-
b := hashTag(nil, tag)
116-
for _, t := range tuples {
117-
b = append(appendPrefix(b[:tagHashLen], t.Prefix), '\xff') // terminate the prefix
118-
it.Seek(b)
119-
for it.ValidForPrefix(b) {
120-
v := it.Item()
121-
it.Next()
122-
if v.IsDeletedOrExpired() {
123-
continue
124-
}
125-
u, err := v.ValueCopy(nil)
126-
if err != nil {
127-
errs = errors.Join(errs, err)
128-
continue
129-
}
130-
if string(u) != t.Suffix {
131-
continue
132-
}
133-
if err := txn.Delete(v.KeyCopy(nil)); err != nil {
134-
errs = errors.Join(errs, err)
135-
continue
136-
}
137-
// Only delete a single instance of each tuple.
138-
break
139-
}
140-
}
141-
return errs
142-
})
143-
if err != nil {
144-
return fmt.Errorf("couldn't forget: %w", err)
145-
}
146-
return nil
147-
}
148-
14992
// ForgetMessage forgets everything learned from a single given message.
15093
// If nothing has been learned from the message, it should be ignored.
15194
func (br *Brain) ForgetMessage(ctx context.Context, tag, id string) error {

brain/kvbrain/forget_test.go

Lines changed: 0 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -209,210 +209,6 @@ func BenchmarkPastFindUser(b *testing.B) {
209209
//go:noinline
210210
func use(x [][]byte) {}
211211

212-
func TestForget(t *testing.T) {
213-
type message struct {
214-
id string
215-
user userhash.Hash
216-
tag string
217-
time time.Time
218-
tups []brain.Tuple
219-
}
220-
cases := []struct {
221-
name string
222-
msgs []message
223-
forget []brain.Tuple
224-
want map[string]string
225-
}{
226-
{
227-
name: "none",
228-
msgs: []message{
229-
{
230-
id: "1",
231-
user: userhash.Hash{2},
232-
tag: "kessoku",
233-
time: time.Unix(0, 0),
234-
tups: []brain.Tuple{
235-
{
236-
Prefix: []string{"ryou", "bocchi"},
237-
Suffix: "kita",
238-
},
239-
},
240-
},
241-
},
242-
forget: []brain.Tuple{
243-
{
244-
Prefix: []string{"eliza", "kikuri"},
245-
Suffix: "shima",
246-
},
247-
},
248-
want: map[string]string{
249-
mkey("kessoku", "ryou\xffbocchi\xff\xff", "1"): "kita",
250-
},
251-
},
252-
{
253-
name: "suffix",
254-
msgs: []message{
255-
{
256-
id: "1",
257-
user: userhash.Hash{2},
258-
tag: "kessoku",
259-
time: time.Unix(0, 0),
260-
tups: []brain.Tuple{
261-
{
262-
Prefix: []string{"ryou", "bocchi"},
263-
Suffix: "kita",
264-
},
265-
},
266-
},
267-
},
268-
forget: []brain.Tuple{
269-
{
270-
Prefix: []string{"eliza", "kikuri"},
271-
Suffix: "kita",
272-
},
273-
},
274-
want: map[string]string{
275-
mkey("kessoku", "ryou\xffbocchi\xff\xff", "1"): "kita",
276-
},
277-
},
278-
{
279-
name: "prefix",
280-
msgs: []message{
281-
{
282-
id: "1",
283-
user: userhash.Hash{2},
284-
tag: "kessoku",
285-
time: time.Unix(0, 0),
286-
tups: []brain.Tuple{
287-
{
288-
Prefix: []string{"ryou", "bocchi"},
289-
Suffix: "kita",
290-
},
291-
},
292-
},
293-
},
294-
forget: []brain.Tuple{
295-
{
296-
Prefix: []string{"ryou", "bocchi"},
297-
Suffix: "shima",
298-
},
299-
},
300-
want: map[string]string{
301-
mkey("kessoku", "ryou\xffbocchi\xff\xff", "1"): "kita",
302-
},
303-
},
304-
{
305-
name: "tag",
306-
msgs: []message{
307-
{
308-
id: "1",
309-
user: userhash.Hash{2},
310-
tag: "sickhack",
311-
time: time.Unix(0, 0),
312-
tups: []brain.Tuple{
313-
{
314-
Prefix: []string{"ryou", "bocchi"},
315-
Suffix: "kita",
316-
},
317-
},
318-
},
319-
},
320-
forget: []brain.Tuple{
321-
{
322-
Prefix: []string{"ryou", "bocchi"},
323-
Suffix: "kita",
324-
},
325-
},
326-
want: map[string]string{
327-
mkey("sickhack", "ryou\xffbocchi\xff\xff", "1"): "kita",
328-
},
329-
},
330-
{
331-
name: "match",
332-
msgs: []message{
333-
{
334-
id: "1",
335-
user: userhash.Hash{2},
336-
tag: "kessoku",
337-
time: time.Unix(0, 0),
338-
tups: []brain.Tuple{
339-
{
340-
Prefix: []string{"ryou", "bocchi"},
341-
Suffix: "kita",
342-
},
343-
},
344-
},
345-
},
346-
forget: []brain.Tuple{
347-
{
348-
Prefix: []string{"ryou", "bocchi"},
349-
Suffix: "kita",
350-
},
351-
},
352-
want: map[string]string{},
353-
},
354-
{
355-
name: "single",
356-
msgs: []message{
357-
{
358-
id: "1",
359-
user: userhash.Hash{2},
360-
tag: "kessoku",
361-
time: time.Unix(0, 0),
362-
tups: []brain.Tuple{
363-
{
364-
Prefix: []string{"ryou", "bocchi"},
365-
Suffix: "kita",
366-
},
367-
},
368-
},
369-
{
370-
id: "2",
371-
user: userhash.Hash{2},
372-
tag: "kessoku",
373-
time: time.Unix(0, 0),
374-
tups: []brain.Tuple{
375-
{
376-
Prefix: []string{"ryou", "bocchi"},
377-
Suffix: "kita",
378-
},
379-
},
380-
},
381-
},
382-
forget: []brain.Tuple{
383-
{
384-
Prefix: []string{"ryou", "bocchi"},
385-
Suffix: "kita",
386-
},
387-
},
388-
want: map[string]string{
389-
mkey("kessoku", "ryou\xffbocchi\xff\xff", "2"): "kita",
390-
},
391-
},
392-
}
393-
for _, c := range cases {
394-
t.Run(c.name, func(t *testing.T) {
395-
t.Parallel()
396-
ctx := context.Background()
397-
db, err := badger.Open(badger.DefaultOptions("").WithInMemory(true).WithLogger(nil))
398-
if err != nil {
399-
t.Fatal(err)
400-
}
401-
br := New(db)
402-
for _, msg := range c.msgs {
403-
err := br.Learn(ctx, msg.tag, msg.id, msg.user, msg.time, msg.tups)
404-
if err != nil {
405-
t.Errorf("failed to learn: %v", err)
406-
}
407-
}
408-
if err := br.Forget(ctx, "kessoku", c.forget); err != nil {
409-
t.Errorf("failed to forget: %v", err)
410-
}
411-
dbcheck(t, db, c.want)
412-
})
413-
}
414-
}
415-
416212
func TestForgetMessage(t *testing.T) {
417213
type message struct {
418214
id string

brain/learn.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ type Learner interface {
2727
// Each tuple's prefix has entropy reduction transformations applied.
2828
// Tuples in the argument may share storage for prefixes.
2929
Learn(ctx context.Context, tag, id string, user userhash.Hash, t time.Time, tuples []Tuple) error
30-
// Forget removes a set of recorded tuples.
31-
// The tuples provided are as for Learn.
32-
// If a tuple has been recorded multiple times, only the first
33-
// should be deleted.
34-
// If a tuple has not been recorded, it should be ignored.
35-
Forget(ctx context.Context, tag string, tuples []Tuple) error
3630
// ForgetMessage forgets everything learned from a single given message.
3731
// If nothing has been learned from the message, it should be ignored.
3832
ForgetMessage(ctx context.Context, tag, id string) error
@@ -56,18 +50,6 @@ func Learn(ctx context.Context, l Learner, tag, id string, user userhash.Hash, t
5650
return l.Learn(ctx, tag, id, user, t, tt)
5751
}
5852

59-
// Forget removes tokens from a Learner.
60-
func Forget(ctx context.Context, l Learner, tag string, toks []string) error {
61-
if len(toks) == 0 {
62-
return nil
63-
}
64-
tt := tuplesPool.Get()
65-
defer func() { tuplesPool.Put(tt[:0]) }()
66-
tt = slices.Grow(tt, len(toks)+1)
67-
tt = tupleToks(tt, toks)
68-
return l.Forget(ctx, tag, tt)
69-
}
70-
7153
func tupleToks(tt []Tuple, toks []string) []Tuple {
7254
slices.Reverse(toks)
7355
pres := slices.Clone(toks)

0 commit comments

Comments
 (0)