OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-agents commits / e8b282f

Redo the counting example
e8b282f737c5f930b9f43aad7067fc36dae5bfe4
by Linas Vepštas <linasvepstas@gmail.com> · 2024-05-14T02:07:50.000Z

Changed files (2) +45 -124

scm/pair-agent/count-agent.scm +38 -123
……@@ -9,161 +9,76 @@
99; to eventually auto-build these pipelines, but that code is not working
1010; yet.)
1111;
12; The hand-crafted pipe not only works, but works faster than the old
13; code, and so has been mad "official" and is now a part of the `learn`
14; module. See
15; https://github.com/opencog/learn/tree/master/sc,/pipe-parse/pipe-count.scm
16;
1217; The "rest of the demo", where we do something with the word pairs,
1318; is in "generate.scm".
1419
1520(use-modules (opencog) (opencog exec) (opencog persist))
1621(use-modules (opencog nlp) (opencog nlp lg-parse))
22(use-modules (opencog learn))
1723(use-modules (opencog sensory))
1824(use-modules (srfi srfi-1))
1925
2026; --------------------------------------------------------------
21; Return a text parser that counts words and word-pairs obtained from
22; parsing text on a stream. The `txt-stream` must be an Atom that can
23; serve as a source of text. Typically, `txt-stream` will be
24; (ValueOf (Concept "some atom") (Predicate "some key"))
25; and the Value there will be a LinkStream from some file or
26; other text source.
27;
28; These sets up a processing pipeline in Atomese, and returns that
29; pipeline. The actual parsing all happens in C++ code, not in scheme
30; code. The scheme here is just to glue the pipeline together.
31;
32; This is attempting to be backwards-compat with old pair-counting code.
33(define (make-parser txt-stream)
34 ;
35 ; Pipeline steps, from inside to out:
36 ; * LGParseBonds tokenizes a sentence, and then parses it.
37 ; * The PureExecLink makes sure that the parsing is done in a
38 ; sub-AtomSpace so that the main AtomSpace is not garbaged up.
39 ;
40 ; The result of parsing is a list of pairs. First item in a pair is
41 ; the list of words in the sentence; the second is a list of the edges.
42 ; Thus, each pair has the form
43 ; (LinkValue
44 ; (LinkValue (Word "this") (Word "is") (Word "a") (Word "test"))
45 ; (LinkValue (Edge ...) (Edge ...) ...))
46 ;
47 ; The outer Filter matches this, so that (Glob "$edge-list") is
48 ; set to the LinkValue of Edges.
49 ;
50 ; The inner Filter loops over the list of edges, and invokes a small
51 ; pipe to increment the count on each edge.
52 ;
53 ; The counter is a non-atomic pipe of (SetValue (Plus 1 (GetValue)))
54 ;
55 (define NUML (Number 6))
56 (define DICT (LgDict "any"))
57 (define any-parse (ParseNode "ANY"))
58
59 ; Increment the count on one atom.
60 (define (incr-cnt atom)
61 (SetValue atom (Predicate "count")
62 (Plus (Number 0 0 1)
63 (FloatValueOf atom (Predicate "count")
64 (FloatValueOf (Number 0 0 0))))))
65
66 ; Given a list (an Atomese LinkValue list) of Atoms,
67 ; increment the count on each Atom.
68 (define (atom-counter ATOM-LIST)
69 (Filter
70 (Rule
71 ; We could type for safety, but seems like no need...
72 ; (TypedVariable (Variable "$atom")
73 ; (TypeChoice (Type 'Edge) (Type 'Word)))
74 (Variable "$atom") ; vardecl
75 (Variable "$atom") ; body to match
76 (incr-cnt (Variable "$atom")))
77 ATOM-LIST))
78
79 ; Given PASRC holding a stream of parses, split it into a list of
80 ; words, and a list of edges, and apply FUNKY to both lists.
81 (define (stream-splitter PASRC FUNKY)
82 (Filter
83 (Rule
84 (LinkSignature
85 (Type 'LinkValue)
86 (Variable "$word-list")
87 (Variable "$edge-list"))
88 ; Apply the function FUNKY to the word and edge lists.
89 (FUNKY (Variable "$word-list"))
90 (FUNKY (Variable "$edge-list"))
91 ; Increment by one for each parse
92 (incr-cnt any-parse))
93 PASRC))
94
95 (define parser (LgParseBonds txt-stream DICT NUML))
96
97 ; Is there any benefit to private parsing?
98 ; (edge-filter (PureExecLink parser) edge-counter)
99
100 ; Return the assembled counting pipeline.
101 ; All that the user needs to do is to call `cog-execute!` on it,
102 ; until end of file is reached.
103 (stream-splitter parser atom-counter)
27(define (setup-parser STORAGE)
28"
29 Create parser attached to storage.
30"
31 ; (make-disjunct-parser ...
32 (make-random-pair-parser
33 (ValueOf (Anchor "parse pipe") (Predicate "text src"))
34 STORAGE)
10435)
10536
106; --------------------------------------------------------------
107; Demo wrapper: Parse a single text string.
108(define (obs-texty TXT-STRING)
109
110 ; We don't need to create this over and over; once is enough.
111 (define txt-stream
112 (ValueOf (Anchor "parse pipe") (Predicate "text src")))
113 (define parser (make-parser txt-stream))
114
115 (define phrali (Item TXT-STRING))
116 (cog-execute!
117 (SetValue (Anchor "parse pipe") (Predicate "text src") phrali))
118
119 ; Run parser once.
120 (cog-execute! parser)
121 (cog-extract-recursive! phrali)
122)
123
124; Example:
125; (obs-texty "this is a test")
126; (cog-execute! (ValueOf (ParseNode "ANY") (Predicate "count"))
127
128; --------------------------------------------------------------
12937; Demo wrapper: Parse contents of a file.
130(define (obs-file FILE-NAME)
38(define (obs-file FILE-NAME PARSER)
13139
132 ; We don't need to create this over and over; once is enough.
133 (define txt-stream
134 (ValueOf (Anchor "parse pipe") (Predicate "text src")))
135 (define parser (make-parser txt-stream))
136
137 (define phrali (Open (Type 'TextFileStream)
138 (Sensory (string-append "file://" FILE-NAME))))
40 (define sensor (Sensory (string-append "file://" FILE-NAME)))
13941
14042 (cog-execute!
141 (SetValue (Anchor "parse pipe") (Predicate "text src") phrali))
43 (SetValue
44 (Anchor "parse pipe") (Predicate "text src")
45 (Open (Type 'TextFileStream) sensor)))
14246
14347 ; Parse only first line of file:
144 ; (cog-execute! parser)
48 ; (cog-execute! PARSER)
49
50 ; Due to a design/implementation failure(??) the above only does
51 ; one line at a time, although it is sem-intended to stream
52 ; continuously. But whatever. For now, we loop manually.
14553
14654 ; Loop over all lines.
147 (define (looper) (cog-execute! parser) (looper))
55 (define (looper) (cog-execute! PARSER) (looper))
14856
14957 ; At end of file, exception will be thrown. Catch it. Print it.
15058 (catch #t looper
15159 (lambda (key . args) (format #t "The end ~A\n" key)))
15260
153 (cog-extract-recursive! phrali)
61 ; Cleanup up litter that we don't want in the atomspace.
62 (cog-extract-recursive! sensor)
15463)
15564
15665; --------------------------
15766; Run the above demo:
158; (obs-file "/tmp/demo.txt")
15967;
160; Look at results. Poke around, look at counts.
16168#|
69(use-modules (opencog persist-rocks))
70(define storage-node (MonoStorageNode "monospace:///tmp/foo.rdb"))
71(cog-open storage-node)
72(define parser (setup-parser storage-node))
73(obs-file "/tmp/demo.txt" parser)
74;
75; Look at results. Poke around, look at counts.
16276(cog-report-counts)
163(cog-execute! (ValueOf (Word "is") (Predicate "count")))
77(cog-execute! (ValueOf (Word "is") (Predicate "*-TruthValueKey-*")))
78(cog-get-atoms 'Edge)
16479(cog-execute! (ValueOf
165 (Edge (Bond "ANY") (List (Word "is") (Word "a")))
166 (Predicate "count")))
80 (car (cog-get-atoms 'Edge))
81 (Predicate "*-TruthValueKey-*")))
16782
16883; Erase all words, so we can try again.
16984(extract-type 'WordNode)
scm/pair-agent/generate-agent.scm +7 -1
……@@ -5,10 +5,16 @@
55; link-generator -c 4 -k 4 -l en
66; link-generator -l en -s 0
77; This is * test
8; echo 'This \* a te\* of \*.a sentence generation' | time link-generator -l en -s 0 --verbosity=2
9; echo 'This is a \*' | time link-generator -l en -s 0 --verbosity=2
10;
11; Early versions would take prior string and just add one more star.
12; Or maybe two.
813;
914; General issues:
1015; * Allow link-parser app to special case wild-cards for generation.
1116; * Loading of entire dict is unfeasible, so...
17; Load only possible links?
1218;
1319; Ideas:
1420; -- Parse given word seq containing blanks, use unknown word for
……@@ -20,7 +26,7 @@
2026OK, screw that. The diary part ten is exploring this, here are the best
2127ideas in summary form:
2228
231) Starting with a word A, use incoming set to randonly select some
291) Starting with a word A, use incoming set to randomly select some
2430subset of all possible edges. This will be called the "focus set" or the
2531"attentional focus". Because it is small, it can be exhaustively
2632iterated and sorted into high-to-low MI order. This provides a weighted