Add example of logic programming to find rhymes
parent
0bd7683020
commit
2a2d5adc35
@ -0,0 +1,158 @@
|
|||||||
|
(ns com.owoga.prhyme.logic.core
|
||||||
|
(:refer-clojure :exclude [==])
|
||||||
|
(:require [clojure.core.logic.fd :as fd]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[clojure.core.logic.pldb :as db]
|
||||||
|
[com.owoga.prhyme.data.dictionary :as dict]
|
||||||
|
[com.owoga.prhyme.syllabify :as syllabify])
|
||||||
|
(:use [clojure.core.logic]))
|
||||||
|
|
||||||
|
(defn productsumo [vars dens sum]
|
||||||
|
(fresh [vhead vtail dhead dtail product run-sum]
|
||||||
|
(conde
|
||||||
|
[(emptyo vars) (== sum 0)]
|
||||||
|
[(conso vhead vtail vars)
|
||||||
|
(conso dhead dtail dens)
|
||||||
|
(fd/* vhead dhead product)
|
||||||
|
(fd/+ product run-sum sum)
|
||||||
|
(productsumo vtail dtail run-sum)])))
|
||||||
|
|
||||||
|
(defn change [amount denoms]
|
||||||
|
(let [dens (sort > denoms)
|
||||||
|
vars (repeatedly (count dens) lvar)]
|
||||||
|
(run* [q]
|
||||||
|
(== q (zipmap dens vars))
|
||||||
|
(everyg #(fd/in % (fd/interval 0 amount)) vars)
|
||||||
|
(productsumo vars dens amount))))
|
||||||
|
|
||||||
|
(change 14 #{1 2 5 10})
|
||||||
|
|
||||||
|
(run* [s p o]
|
||||||
|
(membero s [:mother :child])
|
||||||
|
(membero o [:mother :child])
|
||||||
|
(membero p [:loves :has])
|
||||||
|
(!= s o))
|
||||||
|
|
||||||
|
(run* [s p o]
|
||||||
|
(everyg #(membero % [:mother :child])
|
||||||
|
[s o])
|
||||||
|
(membero p [:loves :has])
|
||||||
|
(distincto [s o]))
|
||||||
|
|
||||||
|
(def words-for-db dict/cmu-with-stress)
|
||||||
|
|
||||||
|
(defn phonemes-for-rhyme [word-phonemes]
|
||||||
|
(->> word-phonemes
|
||||||
|
reverse
|
||||||
|
(split-with #(re-matches #".*[^1]" %))
|
||||||
|
(#(concat (first %) (take 1 (second %))))))
|
||||||
|
|
||||||
|
(defn perfect-rhyme? [a b]
|
||||||
|
(= (phonemes-for-rhyme a)
|
||||||
|
(phonemes-for-rhyme b)))
|
||||||
|
|
||||||
|
(defn remove-consonants [w]
|
||||||
|
(remove #(re-matches #".*[^\d]" %) w))
|
||||||
|
|
||||||
|
(defn perfect-vowel-rhyme? [a b]
|
||||||
|
(= (remove-consonants (phonemes-for-rhyme a))
|
||||||
|
(remove-consonants (phonemes-for-rhyme b))))
|
||||||
|
|
||||||
|
(db/db-rel
|
||||||
|
word
|
||||||
|
^:index w
|
||||||
|
^:index syllable-count
|
||||||
|
^:index perfect-rhyme-phonemes)
|
||||||
|
|
||||||
|
(defn make-word [w]
|
||||||
|
[word
|
||||||
|
w
|
||||||
|
(->> w
|
||||||
|
rest
|
||||||
|
(map #(string/replace % #"\d" ""))
|
||||||
|
syllabify/syllabify
|
||||||
|
count)
|
||||||
|
(remove-consonants (phonemes-for-rhyme w))])
|
||||||
|
|
||||||
|
(remove-consonants (phonemes-for-rhyme ["po" "P" "AA1" "V" "ER0" "T" "IY0"]))
|
||||||
|
(def words
|
||||||
|
(apply
|
||||||
|
db/db
|
||||||
|
(map make-word words-for-db)))
|
||||||
|
|
||||||
|
(db/with-db words
|
||||||
|
(run 5 [sentence]
|
||||||
|
(fresh [w s p
|
||||||
|
w1 s1 p1]
|
||||||
|
(== p '("IY0" "OW1"))
|
||||||
|
(== sentence `(~w ~w1))
|
||||||
|
(fd/+ s s1 7)
|
||||||
|
(word w s p)
|
||||||
|
(word w1 s1 p1)
|
||||||
|
(== p p1)
|
||||||
|
(!= w w1))))
|
||||||
|
|
||||||
|
(db/db-rel test-word w)
|
||||||
|
(def test-db (db/db [test-word "hello"]
|
||||||
|
[test-word "world"]))
|
||||||
|
(db/with-db test-db
|
||||||
|
(run 5 [q]
|
||||||
|
(test-word q)))
|
||||||
|
|
||||||
|
(db/db-rel test-word w ^:index pos)
|
||||||
|
(def test-db (db/db [test-word "hello" :greeting]
|
||||||
|
[test-word "world" :noun]))
|
||||||
|
(db/with-db test-db
|
||||||
|
(run 5 [e a v]
|
||||||
|
(test-word "hello" a)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(run* [q r]
|
||||||
|
(membero q ["linux" "windows" "mac" "android" ""])
|
||||||
|
(conda
|
||||||
|
[fail]
|
||||||
|
[(membero q ["linux" "windows"]) (== r 1)]
|
||||||
|
[(== q "mac") (== r 2)]
|
||||||
|
[succeed (== q "") (== r 3)]))
|
||||||
|
;; => (["linux" 1] ["windows" 1])
|
||||||
|
(run* [q r]
|
||||||
|
(conde
|
||||||
|
[fail]
|
||||||
|
[(membero q ["linux" "windows"]) (== r 1)]
|
||||||
|
[(== q "mac") (== r 2)]
|
||||||
|
[succeed (== q "") (== r 3)]))
|
||||||
|
;; => (["mac" 2] ["" 3] ["linux" 1] ["windows" 1])
|
||||||
|
(run* [q r]
|
||||||
|
(membero q ["linux" "windows" "mac" "android" ""])
|
||||||
|
(condu
|
||||||
|
[(membero q ["linux" "windows"]) (== r 1)]
|
||||||
|
[(== q "mac") (== r 2)]
|
||||||
|
[succeed (== q "") (== r 3)]))
|
||||||
|
;; => (["linux" 1] ["windows" 1] ["mac" 2] ["" 3])
|
||||||
|
|
||||||
|
|
||||||
|
(run* [q r]
|
||||||
|
(conde
|
||||||
|
[(membero q ["linux" "windows"]) (membero r ["iOS" "android"])]
|
||||||
|
[(== q "mac") (== r 2)]
|
||||||
|
[succeed (== q "") (== r 3)]))
|
||||||
|
;; => (["linux" "iOS"] ["linux" "android"] ["windows" "iOS"] ["windows" "android"])
|
||||||
|
(run* [q r]
|
||||||
|
(condu
|
||||||
|
[(== q "linux") (== r 1)]
|
||||||
|
[(membero q ["linux" "windows"]) (membero r ["iOS" "android"])]
|
||||||
|
[(== q "windows") (== r 2)]
|
||||||
|
[(== q "linux") (== r 3)]))
|
||||||
|
|
||||||
|
;; => (["linux" "iOS"] ["linux" "android"])
|
||||||
|
)
|
||||||
|
|
||||||
|
(let [people (repeatedly 5 lvar)
|
||||||
|
magazines (repeatedly 5 lvar)
|
||||||
|
cheeses (repeatedly 5 lvar)
|
||||||
|
reservations (repeatedly 5 lvar)
|
||||||
|
answers (map list people magazines cheeses reservations)]
|
||||||
|
(run* [q]
|
||||||
|
(== q answers)))
|
||||||
|
(run* [q]
|
||||||
|
(fd/in q (apply fd/domain (take 10 (iterate #(* % 2) 1)))))
|
Loading…
Reference in New Issue