;;
;; test-pmfg-minimal.scm - Minimal PMFG test
;;
(use-modules (opencog) (opencog exec))
(use-modules (opencog sensory) (opencog opencl))
(use-modules (ice-9 format))
(display "\n=== Minimal PMFG Test ===\n\n")
;; Build a tiny 5x5 MI matrix with known values
;; Words: 0="the", 1="cat", 2="sat", 3="on", 4="mat"
;; MI values set to favor: the-cat, cat-sat, sat-on, on-mat (consecutive)
(define vocab 5)
(define mi-vals
(list
;; Row 0: the
0.0 5.0 1.0 0.5 0.1 ; the-cat=5.0 is highest
;; Row 1: cat
5.0 0.0 4.0 0.8 0.2 ; cat-sat=4.0
;; Row 2: sat
1.0 4.0 0.0 3.0 0.3 ; sat-on=3.0
;; Row 3: on
0.5 0.8 3.0 0.0 2.0 ; on-mat=2.0
;; Row 4: mat
0.1 0.2 0.3 2.0 0.0))
(display "Test sentence: the cat sat on mat (indices 0 1 2 3 4)\n")
(display "Expected PMFG edges (by MI, no crossings):\n")
(display " [0-1] the-cat MI=5.0\n")
(display " [1-2] cat-sat MI=4.0\n")
(display " [2-3] sat-on MI=3.0\n")
(display " [3-4] on-mat MI=2.0\n")
(display " Max edges = 3*5-6 = 9\n\n")
;; Open GPU
(define gpu (OpenclNode "opencl://:/storage/projects/code/hypercore-kb/opencog-kb/language-learning/mvp/pmfg-kernel.cl"))
;; Parameters matching kernel signature:
;; pmfg_single(mi_matrix, words, n_words_arr, vocab_size_arr, pmfg_edges, n_edges_out, sz)
(define mi-matrix (apply Number mi-vals))
(define words (Number 0 1 2 3 4))
(define n-words (Number 5))
(define vocab-size (Number 5))
(define edges-out (Number 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) ; 9 edges * 2
(define n-edges-out (Number 0))
(display "Running GPU kernel...\n")
(define start (get-internal-real-time))
(cog-execute!
(SetValue gpu (Predicate "*-write-*")
(Section (Item "pmfg_single")
(ConnectorSeq mi-matrix words n-words vocab-size edges-out n-edges-out))))
(define result (cog-execute! (ValueOf gpu (Predicate "*-read-*"))))
(define elapsed (/ (- (get-internal-real-time) start) internal-time-units-per-second))
(format #t "GPU time: ~,3f seconds~%~%" elapsed)
;; Parse result
(display "GPU Result:\n")
(display result)
(newline)
;; The result is a Section with the output values
;; Let's extract the pmfg_edges and n_edges
(define args (cog-value-ref result 1)) ; ConnectorSeq or LinkValue
(format #t "~%Args type: ~a~%" (cog-type args))
;; The output arrays are at positions 4 and 5 (0-indexed)
(define edges-val (cog-value-ref args 4))
(define nedges-val (cog-value-ref args 5))
(format #t "~%Edges output: ~a~%" edges-val)
(format #t "N-edges output: ~a~%~%" nedges-val)
;; CPU verification
(display "=== CPU PMFG for comparison ===\n\n")
(define (get-mi i j)
(list-ref mi-vals (+ (* i vocab) j)))
;; Get pairs sorted by MI
(define pairs '())
(do ((i 0 (+ i 1))) ((= i 5))
(do ((j (+ i 1) (+ j 1))) ((= j 5))
(set! pairs (cons (list (get-mi i j) i j) pairs))))
(set! pairs (sort pairs (lambda (a b) (> (car a) (car b)))))
(display "Pairs by MI (descending):\n")
(for-each
(lambda (p)
(format #t " [~a-~a] MI=~a~%" (cadr p) (caddr p) (car p)))
pairs)
;; Greedy selection
(define (crosses? i j k l)
(let ((a (min i j)) (b (max i j))
(c (min k l)) (d (max k l)))
(or (and (< a c) (< c b) (< b d))
(and (< c a) (< a d) (< d b)))))
(define cpu-edges '())
(for-each
(lambda (p)
(when (< (length cpu-edges) 9)
(let ((pos1 (cadr p)) (pos2 (caddr p)) (ok #t))
(for-each
(lambda (e)
(when (crosses? pos1 pos2 (car e) (cadr e))
(set! ok #f)))
cpu-edges)
(when ok
(set! cpu-edges (cons (list pos1 pos2) cpu-edges))))))
pairs)
(display "\nCPU PMFG edges:\n")
(for-each
(lambda (e) (format #t " [~a-~a]~%" (car e) (cadr e)))
(reverse cpu-edges))
(format #t "Total: ~a edges~%" (length cpu-edges))