;;; Quick demo for exploring synonyms in Wordnet.

(in-package :cl)

(defpackage word
  (:use :cl :excl
 	:db.agraph
	:sparql))

(in-package :word)

;; I've already built the triple store.
;; Otherwise, create it, load, and (index-all-triples :wait t).
(open-triple-store "/s/tmp/rnewman/wn")

;; Because you always end up needing it!
(register-namespace "wn" "http://www.w3.org/2006/03/wn/wn20/schema/")

;; This query will find synonyms and their senses.
;; Because it's finding senses, too, it'll return some 
;; answers with the same lexical form.
(run-sparql
    "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

  SELECT DISTINCT ?otherSense ?otherLexicalForm {

    # Work backwards from the word to its synset...
    ?word wn:lexicalForm 'car'@en-us .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense ,
                                 # ... then back out to its other lexical forms.
                                 ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
    
  }")

;; This one will return synonyms with only different
;; lexical forms.
(run-sparql
    "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

  SELECT DISTINCT ?otherSense ?otherLexicalForm {
    ?word wn:lexicalForm 'car'@en-us .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
    FILTER ( !sameTerm(?otherLexicalForm, 'car'@en-us ) ) .
  }")

;; ... and if you only want a list of words...
(mapcar #'(lambda (rlist)
	    (upi->value (car rlist)))
	(run-sparql
    "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

  SELECT DISTINCT ?otherLexicalForm {
    ?word wn:lexicalForm 'car'@en-us .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
    FILTER ( !sameTerm(?otherLexicalForm, 'car'@en-us ) ) .
  }" :results-format :lists))

;; Let's make it a function.
(defun synonyms (word)
  "Don't put quotes in word!"
  (when word
    (mapcar #'(lambda (rlist)
		(upi->value (car rlist)))
	    (run-sparql
	     (format nil 
		     "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

  SELECT DISTINCT ?otherLexicalForm {
    ?word wn:lexicalForm '~A'@en-us .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
    FILTER ( !sameTerm(?otherLexicalForm, '~A'@en-us ) ) .
  }" word word)
	     :results-format :lists))))


;;;;;;;;;;;; Fixing bugs.
(run-sparql "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
            
  SELECT DISTINCT ?otherSense ?otherLexicalForm {
    ?word wn:lexicalForm ?lexicalForm .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
    FILTER ( !sameTerm(?otherLexicalForm, 'car'@en-us ) ) .
  }" :with-variables '((lexicalForm . !"car"@en-us)
                       (?lexicalForm . !"car"@en-us)))

(run-sparql "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  SELECT DISTINCT ?otherSense ?otherLexicalForm {
    ?word wn:lexicalForm ?lexicalForm .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
  }" :with-variables '((?lexicalForm . !"car"@en-us)) :results-format :count)

(run-sparql "
  PREFIX wn: <http://www.w3.org/2006/03/wn/wn20/schema/>
  SELECT DISTINCT ?otherSense ?otherLexicalForm {
    ?word wn:lexicalForm 'car'@en-us .
    ?sense wn:word ?word .
    ?synset wn:containsWordSense ?sense , ?otherSense .
    ?otherSense wn:word [ wn:lexicalForm ?otherLexicalForm ] .
  }" :with-variables () :results-format :count)
