| … | … | @@ -259,7 +259,7 @@ |
| 259 | 259 | ; |
| 260 | 260 | ; https://github.com/opencog/sensory/raw/master/examples/file-read.scm |
| 261 | 261 | ; |
| 262 | | ; Repeated here. |
| 262 | ; The last part of that demo is repeated here. |
| 263 | 263 | |
| 264 | 264 | ; Opening the text stream will create a ValueStream. It needs to be |
| 265 | 265 | ; placed where the parser can find it. Anywhere will do, as long as the |
| … | … | @@ -284,174 +284,10 @@ |
| 284 | 284 | ; That's it. Now wire it all together: |
| 285 | 285 | (cog-execute! (edge-filter parse-stream edge-counter)) |
| 286 | 286 | |
| 287 | | ; -------------------------------------------------------------- |
| 288 | | ; Return a text parser that counts edges on a stream. The |
| 289 | | ; `txt-stream` must be an Atom that can serve as a source of text. |
| 290 | | ; Typically, `txt-stream` will be |
| 291 | | ; (ValueOf (Concept "some atom") (Predicate "some key")) |
| 292 | | ; and the Value there will be a LinkStream from some file or |
| 293 | | ; other text source. |
| 294 | | ; |
| 295 | | ; These sets up a processing pipeline in Atomese, and returns that |
| 296 | | ; pipeline. The actual parsing all happens in C++ code, not in scheme |
| 297 | | ; code. The scheme here is just to glue the pipeline together. |
| 298 | | (define (make-parser txt-stream) |
| 299 | | ; |
| 300 | | ; Pipeline steps, from inside to out: |
| 301 | | ; * LGParseBonds tokenizes a sentence, and then parses it. |
| 302 | | ; * The PureExecLink makes sure that the parsing is done in a |
| 303 | | ; sub-AtomSpace so that the main AtomSpace is not garbaged up. |
| 304 | | ; |
| 305 | | ; The result of parsing is a list of pairs. First item in a pair is |
| 306 | | ; the list of words in the sentence; the second is a list of the edges. |
| 307 | | ; Thus, each pair has the form |
| 308 | | ; (LinkValue |
| 309 | | ; (LinkValue (Word "this") (Word "is") (Word "a") (Word "test")) |
| 310 | | ; (LinkValue (Edge ...) (Edge ...) ...)) |
| 311 | | ; |
| 312 | | ; The outer Filter matches this, so that (Glob "$edge-list") is |
| 313 | | ; set to the LinkValue of Edges. |
| 314 | | ; |
| 315 | | ; The inner Filter loops over the list of edges, and invokes a small |
| 316 | | ; pipe to increment the count on each edge. |
| 317 | | ; |
| 318 | | ; The counter is a non-atomic pipe of (SetValue (Plus 1 (GetValue))) |
| 319 | | ; |
| 320 | | (define NUML (Number 4)) |
| 321 | | (define DICT (LgDict "any")) |
| 322 | | |
| 323 | | ; Increment the count on one edge. |
| 324 | | (define (incr-cnt edge) |
| 325 | | (SetValue edge (Predicate "count") |
| 326 | | (Plus (Number 0 0 1) |
| 327 | | (FloatValueOf edge (Predicate "count") (FloatValueOf (Number 0 0 0)))))) |
| 328 | | |
| 329 | | ; Given a list (an Atomese LinkValue list) of parse results, |
| 330 | | ; extract the edges and increment the count on them. |
| 331 | | (define (count-edges parsed-stuff) |
| 332 | | (Filter |
| 333 | | (Rule |
| 334 | | ; (Variable "$edge") |
| 335 | | (TypedVariable (Variable "$edge") (Type 'Edge)) |
| 336 | | (Variable "$edge") |
| 337 | | (incr-cnt (Variable "$edge"))) |
| 338 | | parsed-stuff)) |
| 339 | | |
| 340 | | ; Parse text in a private space. |
| 341 | | (define (parseli phrali) |
| 342 | | (PureExecLink (LgParseBonds phrali DICT NUML))) |
| 343 | | |
| 344 | | ; Given an Atom `phrali` holding text to be parsed, get that text, |
| 345 | | ; parse it, and increment the counts on the edges. |
| 346 | | (define (filty phrali) |
| 347 | | (Filter |
| 348 | | (Rule |
| 349 | | ; Type decl |
| 350 | | (Glob "$x") |
| 351 | | ; Match clause - one per parse. |
| 352 | | (LinkSignature |
| 353 | | (Type 'LinkValue) ; the wrapper for the pair |
| 354 | | (Type 'LinkValue) ; the word-list |
| 355 | | (LinkSignature ; the edge-list |
| 356 | | (Type 'LinkValue) ; edge-list wrapper |
| 357 | | (Glob "$edge-list"))) ; all of the edges |
| 358 | | ; Pipeline to apply to the resulting match. |
| 359 | | (count-edges (Glob "$edge-list")) |
| 360 | | ) |
| 361 | | (parseli phrali))) |
| 362 | | |
| 363 | | ; Return the parser. |
| 364 | | (filty txt-stream) |
| 365 | | ) |
| 366 | | |
| 367 | | ; -------------------------------------------------------------- |
| 368 | | ; Demo wrapper showing how to use the above: Parse a string. |
| 369 | | ; PLAIN-TEXT should be a scheme string. |
| 370 | | ; |
| 371 | | ; Verify this works as follows: |
| 372 | | ; (obs-txt "this is a test") |
| 373 | | ; (cog-report-counts) |
| 374 | | ; Note the abundance of WordNodes listed in the report. |
| 375 | | ; (cog-get-atoms 'WordNode) |
| 376 | | ; Cleanup after use: |
| 377 | | ; (for-each cog-extract-recursive! (cog-get-atoms 'WordNode)) |
| 378 | | ; (extract-type 'WordNode) |
| 379 | | (define (obs-txt PLAIN-TEXT) |
| 380 | | |
| 381 | | ; We don't need to create this over and over; once is enough. |
| 382 | | (define txt-stream (ValueOf (Concept "foo") (Predicate "some place"))) |
| 383 | | (define parser (make-parser txt-stream)) |
| 384 | | |
| 385 | | (define phrali (Phrase PLAIN-TEXT)) |
| 386 | | (cog-set-value! (Concept "foo") (Predicate "some place") phrali) |
| 387 | | |
| 388 | | (cog-execute! parser) |
| 389 | | |
| 390 | | ; Remove the phrase-link, return the list of edges. |
| 391 | | (cog-set-value! (Concept "foo") (Predicate "some place") #f) |
| 392 | | (cog-extract-recursive! phrali) |
| 393 | | ) |
| 287 | ; Note the actual flow is different from the how this is written, above. |
| 288 | ; First, the parse stream flows to the edge-filter, and then the |
| 289 | ; edge-counter runs. Some twiddling about in scheme could straighten |
| 290 | ; this out into a "natural" direction, but there does not seem to be |
| 291 | ; much point to re-engineering this. |
| 394 | 292 | |
| 395 | 293 | ; -------------------------------------------------------------- |
| 396 | | ; Demo wrapper: Parse contents of a file. |
| 397 | | (define (obs-file FILE-NAME) |
| 398 | | |
| 399 | | ; We don't need to create this over and over; once is enough. |
| 400 | | (define txt-stream (ValueOf (Concept "foo") (Predicate "some place"))) |
| 401 | | (define parser (make-parser txt-stream)) |
| 402 | | |
| 403 | | (define phrali (Open (Type 'TextFileStream) |
| 404 | | (Sensory (string-append "file://" FILE-NAME)))) |
| 405 | | |
| 406 | | (cog-execute! |
| 407 | | (SetValue (Concept "foo") (Predicate "some place") phrali)) |
| 408 | | |
| 409 | | ; Parse only first line of file: |
| 410 | | ; (cog-execute! parser) |
| 411 | | |
| 412 | | ; Loop over all lines. |
| 413 | | (define (looper) (cog-execute! parser) (looper)) |
| 414 | | |
| 415 | | ; At end of file, exception will be thrown. Catch it. |
| 416 | | (catch #t looper |
| 417 | | (lambda (key . args) (format #t "The end ~A\n" key))) |
| 418 | | |
| 419 | | (cog-extract-recursive! phrali) |
| 420 | | ) |
| 421 | | |
| 422 | | ; -------------------------- |
| 423 | | ; Issues. |
| 424 | | ; Parses arrive as LinkValues. We want to apply a function to each. |
| 425 | | ; How? Need: |
| 426 | | ; 4) IncrementLink just like cog-inc-value! |
| 427 | | ; or is it enough to do atomic lock? |
| 428 | | ; Make SetValue exec under lock. ... easier said than done. |
| 429 | | ; risks deadlock. |
| 430 | | ; |
| 431 | | ; cog-update-value calls |
| 432 | | ; Ideally, call asp->increment_count(h, key, fvp->value())); |
| 433 | | |
| 434 | | ; Below works but is a non-atomic increment. |
| 435 | | (define ed (Edge (Bond "ANY") (List (Word "words") (Word "know")))) |
| 436 | | (define (doinc) |
| 437 | | (cog-execute! |
| 438 | | (SetValue ed (Predicate "count") |
| 439 | | (Plus (Number 0 0 1) |
| 440 | | (FloatValueOf ed (Predicate "count") (Number 0 0 0)))))) |
| 441 | | |
| 442 | | ; Here's a demo of what file-access looks like. |
| 443 | | (cog-execute! |
| 444 | | (SetValue (Concept "foo") (Predicate "some place") |
| 445 | | (FileRead "file:///tmp/demo.txt"))) |
| 446 | | |
| 447 | | ; Wait ... |
| 448 | | (define txt-stream-gen |
| 449 | | (ValueOf (Concept "foo") (Predicate "some place"))) |
| 450 | | |
| 451 | | ; (cog-execute! (LgParseBonds txt-stream-gen DICT NUML)) |
| 452 | | |
| 453 | | ; (load "count-agent.scm") |
| 454 | | ; (obs-txt "Some kind of sentence to process, hell yeah!") |
| 455 | | ; (obs-file "/tmp/demo.txt") |
| 456 | | ; (cog-report-counts) |
| 457 | | ; (cog-get-atoms 'WordNode) |