;;
;; test-pmfg-final.scm - Clean GPU vs CPU PMFG comparison
;;
;; Use unique variable names to avoid CogServer state contamination
;;
(use-modules (opencog) (opencog exec))
(use-modules (opencog sensory) (opencog opencl))
(use-modules (ice-9 format))
(display "\n")
(display "════════════════════════════════════════════════════════════════\n")
(display " GPU vs CPU PMFG - Final Verification\n")
(display "════════════════════════════════════════════════════════════════\n\n")
;; ═══════════════════════════════════════════════════════════════════════
;; Test data: 5 words with known MI values
;; ═══════════════════════════════════════════════════════════════════════
(define final-mi-matrix
(list 0.0 5.0 1.0 0.5 0.1 ; word 0
5.0 0.0 4.0 0.8 0.2 ; word 1
1.0 4.0 0.0 3.0 0.3 ; word 2
0.5 0.8 3.0 0.0 2.0 ; word 3
0.1 0.2 0.3 2.0 0.0)) ; word 4
(display "MI Matrix (5x5, symmetric):\n")
(display " [0-1]=5.0 [1-2]=4.0 [2-3]=3.0 [3-4]=2.0 [0-2]=1.0\n\n")
;; ═══════════════════════════════════════════════════════════════════════
;; GPU PMFG
;; ═══════════════════════════════════════════════════════════════════════
(display "═══ GPU PMFG ═══\n\n")
(define final-gpu (OpenclNode "opencl://:/storage/projects/code/hypercore-kb/opencog-kb/language-learning/mvp/pmfg-kernel.cl"))
;; Anchor for output
(define final-anchor (Anchor "final-pmfg"))
(cog-set-value! final-anchor (Predicate "out-edges")
(OpenclFloatValue 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
(cog-set-value! final-anchor (Predicate "out-n")
(OpenclFloatValue 0))
;; Run
(define final-start (get-internal-real-time))
(cog-execute!
(SetValue final-gpu (Predicate "*-write-*")
(Section (Item "pmfg_single")
(ConnectorSeq
(apply Number final-mi-matrix)
(Number 0 1 2 3 4)
(Number 5)
(Number 5)
(ValueOf final-anchor (Predicate "out-edges"))
(ValueOf final-anchor (Predicate "out-n"))))))
(cog-execute! (ValueOf final-gpu (Predicate "*-read-*")))
(define final-elapsed (/ (- (get-internal-real-time) final-start)
internal-time-units-per-second))
;; Extract
(define final-edges-raw (cog-execute! (ValueOf final-anchor (Predicate "out-edges"))))
(define final-n-raw (cog-execute! (ValueOf final-anchor (Predicate "out-n"))))
(define final-n-edges (inexact->exact (round (cog-value-ref final-n-raw 0))))
(format #t "GPU execution time: ~,3f seconds~%" final-elapsed)
(format #t "GPU found ~a edges:~%" final-n-edges)
(do ((i 0 (+ i 1))) ((= i final-n-edges))
(let ((p1 (inexact->exact (round (cog-value-ref final-edges-raw (* i 2)))))
(p2 (inexact->exact (round (cog-value-ref final-edges-raw (+ (* i 2) 1))))))
(format #t " [~a-~a]~%" p1 p2)))
;; ═══════════════════════════════════════════════════════════════════════
;; CPU PMFG (clean implementation)
;; ═══════════════════════════════════════════════════════════════════════
(display "\n═══ CPU PMFG ═══\n\n")
(define (final-crosses? i1 j1 i2 j2)
(let ((a (min i1 j1)) (b (max i1 j1))
(c (min i2 j2)) (d (max i2 j2)))
(or (and (< a c) (< c b) (< b d))
(and (< c a) (< a d) (< d b)))))
(define final-cpu-start (get-internal-real-time))
;; Build pairs
(define final-pairs '())
(do ((i 0 (+ i 1))) ((= i 5))
(do ((j (+ i 1) (+ j 1))) ((= j 5))
(let ((mi (list-ref final-mi-matrix (+ (* i 5) j))))
(set! final-pairs (cons (list mi i j) final-pairs)))))
;; Sort descending by MI
(set! final-pairs (sort final-pairs (lambda (a b) (> (car a) (car b)))))
;; Greedy PMFG
(define final-cpu-edges '())
(for-each
(lambda (p)
(when (< (length final-cpu-edges) 9) ; max 3*5-6 = 9
(let ((pos1 (cadr p)) (pos2 (caddr p)) (ok #t))
(for-each
(lambda (e)
(when (final-crosses? pos1 pos2 (car e) (cadr e))
(set! ok #f)))
final-cpu-edges)
(when ok
(set! final-cpu-edges (cons (list pos1 pos2) final-cpu-edges))))))
final-pairs)
(define final-cpu-elapsed (/ (- (get-internal-real-time) final-cpu-start)
internal-time-units-per-second))
(format #t "CPU execution time: ~,3f seconds~%" final-cpu-elapsed)
(format #t "CPU found ~a edges:~%" (length final-cpu-edges))
(for-each
(lambda (e) (format #t " [~a-~a]~%" (car e) (cadr e)))
(reverse final-cpu-edges))
;; ═══════════════════════════════════════════════════════════════════════
;; Comparison
;; ═══════════════════════════════════════════════════════════════════════
(display "\n═══ COMPARISON ═══\n\n")
(if (= final-n-edges (length final-cpu-edges))
(format #t "✓ Edge counts match: ~a edges~%" final-n-edges)
(format #t "✗ Edge counts differ: GPU=~a, CPU=~a~%"
final-n-edges (length final-cpu-edges)))
(display "\nExpected edges (by greedy PMFG on MI):\n")
(display " 1. [0-1] MI=5.0 (highest)\n")
(display " 2. [1-2] MI=4.0\n")
(display " 3. [2-3] MI=3.0\n")
(display " 4. [3-4] MI=2.0\n")
(display " 5. [0-2] MI=1.0 (no crossing)\n")
(display " 6. [1-3] MI=0.8 ← crosses [0-2], skip\n")
(display " 7. [0-3] MI=0.5 (no crossing)\n")
(display " 8. [2-4] ← crosses [0-3], skip\n")
(display " 9. [0-4] MI=0.1 (no crossing)\n")
(display "\nExpected 7 edges: [0-1],[1-2],[2-3],[3-4],[0-2],[0-3],[0-4]\n")