python examples added

This commit is contained in:
aarneranta
2021-03-24 09:16:47 +01:00
parent 7afba566d5
commit b7c3877756
17 changed files with 2109 additions and 0 deletions

47
python/Draw.gf Normal file
View File

@@ -0,0 +1,47 @@
abstract Draw = {
flags startcat = Command ;
cat
Command ;
Object ;
ObjectRef ;
Shape ;
Colour ;
Size ;
Place ;
fun
drawCommand : Object -> Command ;
removeCommand : ObjectRef -> Command ;
moveCommand : ObjectRef -> Place -> Command ;
shapeObject : Size -> Colour -> Shape -> Object ;
theObjectRef : Object -> ObjectRef ;
itObjectRef : ObjectRef ;
circle_Shape : Shape ;
square_Shape : Shape ;
big_Size : Size ;
small_Size : Size ;
noSize : Size ;
green_Colour : Colour ;
red_Colour : Colour ;
blue_Colour : Colour ;
yellow_Colour : Colour ;
noColour : Colour ;
upPlace : Place ;
downPlace : Place ;
leftPlace : Place ;
rightPlace : Place ;
midPlace : Place ;
noPlace : Place ;
}

55
python/DrawEng.gf Normal file
View File

@@ -0,0 +1,55 @@
concrete DrawEng of Draw =
open SyntaxEng, ParadigmsEng, LexiconEng, IrregEng
in {
lincat
Command = Utt ;
Object = CN ;
ObjectRef = NP ;
Shape = CN ;
Colour = AP ;
Size = AP ;
Place = Adv ;
lin
drawCommand object =
mkUtt (mkImp (mkVP (mkV2 draw_V) (mkNP a_Det object))) -- draw a circle
| mkUtt (mkNP a_Det object) -- a circle
| mkUtt object -- circle
;
removeCommand object =
mkUtt (mkImp (mkVP (mkV2 "remove") object)) ;
moveCommand object place =
mkUtt (mkImp (mkVP (mkVP (mkV2 "move") object) place)) ;
shapeObject size colour shape = mkCN size (mkCN colour shape) ;
theObjectRef object = mkNP the_Det object ;
itObjectRef = it_NP ;
circle_Shape = mkCN (mkN "circle") ;
square_Shape = mkCN (mkN "square") ;
big_Size = mkAP big_A ;
small_Size = mkAP small_A ;
noSize = mkAP (mkA "") ; ---
green_Colour = mkAP green_A ;
red_Colour = mkAP red_A ;
blue_Colour = mkAP blue_A ;
yellow_Colour = mkAP yellow_A ;
noColour = mkAP (mkA "") ; ---
upPlace = pmkAdv "up" ;
downPlace = pmkAdv "down" ;
leftPlace = pmkAdv "left" ;
rightPlace = pmkAdv "right" ;
midPlace = pmkAdv "to the middle" ;
noPlace = pmkAdv "" ;
oper
pmkAdv : Str -> Adv = ParadigmsEng.mkAdv ;
}

56
python/DrawFin.gf Normal file
View File

@@ -0,0 +1,56 @@
concrete DrawFin of Draw =
open SyntaxFin, ParadigmsFin, LexiconFin
in {
lincat
Command = Utt ;
Object = CN ;
ObjectRef = NP ;
Shape = CN ;
Colour = AP ;
Size = AP ;
Place = Adv ;
lin
drawCommand object =
mkUtt (mkImp (mkVP (mkV2 "piirtää") (mkNP a_Det object))) -- draw a circle
| mkUtt (mkNP a_Det object) -- a circle
| mkUtt object -- circle
;
removeCommand object =
mkUtt (mkImp (mkVP (mkV2 "poistaa") object)) ;
moveCommand object place =
mkUtt (mkImp (mkVP (mkVP (mkV2 (mkV "siirtää") partitive) object) place)) ;
shapeObject size colour shape = mkCN size (mkCN colour shape) ;
theObjectRef object = mkNP the_Det object ;
itObjectRef = it_NP ;
circle_Shape = mkCN (mkN "ympyrä" "ympyröitä") ;
square_Shape = mkCN (mkN "neliö" "neliöitä") ;
big_Size = mkAP big_A ;
small_Size = mkAP small_A ;
noSize = mkAP (invarA "") ; ---
green_Colour = mkAP green_A ;
red_Colour = mkAP red_A ;
blue_Colour = mkAP blue_A ;
yellow_Colour = mkAP yellow_A ;
noColour = mkAP (invarA "") ; ---
upPlace = pmkAdv "ylöspäin" ;
downPlace = pmkAdv "alaspäin" ;
leftPlace = pmkAdv "vasemmalle" ;
rightPlace = pmkAdv "oikealle" ;
midPlace = pmkAdv "keskelle" ;
noPlace = pmkAdv "" ;
oper
pmkAdv : Str -> Adv = ParadigmsFin.mkAdv ;
}

60
python/DrawSwe.gf Normal file
View File

@@ -0,0 +1,60 @@
concrete DrawSwe of Draw =
open SyntaxSwe, ParadigmsSwe, LexiconSwe, IrregSwe, Prelude,
(G = GrammarSwe)
in {
lincat
Command = Utt ;
Object = CN ;
ObjectRef = NP ;
Shape = CN ;
Colour = AP ** {isAdj : Bool} ;
Size = AP ** {isAdj : Bool} ;
Place = Adv ;
lin
drawCommand object =
mkUtt (mkImp (mkVP (mkV2 "rita") (mkNP a_Det object))) -- draw a circle
| mkUtt (mkNP a_Det object) -- a circle
| mkUtt object -- circle
;
removeCommand object =
mkUtt (mkImp (mkVP (mkV2 (mkV (mkV "ta") "bort")) object)) ;
moveCommand object place =
mkUtt (mkImp (mkVP (mkVP (mkV2 "flytta") object) place)) ;
shapeObject size colour shape =
G.AdjCN size (G.AdjCN colour shape ** {isMod = colour.isAdj})
** {isMod = orB size.isAdj colour.isAdj} ;
theObjectRef object = mkNP the_Det object ;
itObjectRef = mkNP (mkPN "den") ; --- it_NP = det ;
circle_Shape = mkCN (mkN "cirkel" "cirkeln" "cirklar" "cirklarna") ;
square_Shape = mkCN (mkN "kvadrat" "kvadrater") ;
big_Size = mkrAP big_A ;
small_Size = mkrAP small_A ;
noSize = emptyAP ;
green_Colour = mkrAP green_A ;
red_Colour = mkrAP red_A ;
blue_Colour = mkrAP blue_A ;
yellow_Colour = mkrAP yellow_A ;
noColour = emptyAP ;
upPlace = pmkAdv "upp" ;
downPlace = pmkAdv "ner" ;
leftPlace = pmkAdv "åt vänster" ;
rightPlace = pmkAdv "åt höger" ;
midPlace = pmkAdv "till mitten" ;
noPlace = pmkAdv "" ;
oper
emptyAP : AP ** {isAdj : Bool} = mkAP (invarA "") ** {isAdj = False} ; ---
mkrAP : A -> AP ** {isAdj : Bool} = \a -> mkAP a ** {isAdj = True} ;
pmkAdv : Str -> Adv = ParadigmsSwe.mkAdv ;
}

11
python/Makefile Normal file
View File

@@ -0,0 +1,11 @@
minilang:
gf -make ../lab2/grammar/english/MiniLangEng.gf ../lab2/grammar/swedish/MiniLangSwe.gf
query:
gf -make QueryEng.gf QuerySwe.gf
draw:
gf -make DrawEng.gf DrawSwe.gf DrawFin.gf

40
python/Query.gf Normal file
View File

@@ -0,0 +1,40 @@
abstract Query = {
flags startcat = Query ;
cat
Query ;
Kind ;
Property ;
Term ;
Element ;
fun
QWhich : Kind -> Property -> Query ; -- which numbers are prime
QWhether : Term -> Property -> Query ; -- is any number prime
QWhat : Element -> Query ; -- what is the factorial of 10
TAll : Kind -> Term ; -- all numbers
TAny : Kind -> Term ; -- any number
TElement : Element -> Term ; -- 42
PAnd : Property -> Property -> Property ; -- even and prime
POr : Property -> Property -> Property ; -- even or odd
PNot : Property -> Property ; -- not prime
KProperty : Property -> Kind -> Kind ; -- even number
-- lexicon
KNumber : Kind ;
EInteger : Int -> Element ;
PEven, POdd, PPrime : Property ;
PDivisible : Term -> Property ;
PSmaller, PGreater, PEqual : Term -> Property ;
PBetween : Term -> Term -> Property ;
EFactorial : Element -> Element ;
ESum, EProduct, EMinus, EDivided : Element -> Element -> Element ;
}

94
python/QueryEng.gf Normal file
View File

@@ -0,0 +1,94 @@
concrete QueryEng of Query =
open
SyntaxEng, ParadigmsEng,
SymbolicEng,
MarkupEng,
(M = MakeStructuralEng)
in {
lincat
Query = Utt ;
Kind = CN ;
Property = AP ;
Term = NP ;
Element = NP ;
lin
QWhich kind property =
mkUtt (mkQS (mkQCl (mkIP whichPl_IDet kind) property)) -- which numbers are prime
| mkUtt (mkImp (mkVP (mkV2 "list") (mkNP all_Predet (mkNP aPl_Det (mkCN property kind))))) -- list all prime numbers
| mkUtt (mkNP aPl_Det (mkCN property kind)) -- prime numbers
;
QWhether term property =
mkUtt (mkQS (mkQCl (mkCl term property))) -- is 51 prime
| mkUtt (mkQS (mkCl term property)) -- 51 is prime
;
QWhat element =
mkUtt (mkQS (mkQCl what_IP element)) -- what is 2 + 2
| mkUtt (mkImp (mkVP (mkV2 "compute") element)) -- compute 2 + 2
| mkUtt element -- 2 + 2
;
TAll kind =
mkNP all_Predet (mkNP aPl_Det kind) -- all numbers
| mkNP every_Det kind -- every number
;
TAny kind =
mkNP someSg_Det kind -- some number
| mkNP somePl_Det kind -- some numbers
| mkNP (M.mkDet "any" singular) kind -- any number
| mkNP (M.mkDet "any" plural) kind -- any numbers
;
TElement element = element ;
PAnd p q = mkAP and_Conj p q ;
POr p q = mkAP or_Conj p q ;
PNot p = mkAP (lin AdA {s = "not"}) p ;
KProperty property kind = mkCN property kind ;
-- lexicon
KNumber = mkCN (mkN "number") ;
EInteger i = symb i ;
PEven = mkAP (mkA "even") ;
POdd = mkAP (mkA "odd") ;
PPrime = mkAP (mkA "prime") ;
PDivisible term = mkAP (mkA2 (mkA "divisible") by8means_Prep) term ;
PSmaller term = mkAP (mkA "small") term ;
PGreater term = mkAP (mkA "great") term ;
PEqual term = mkAP (mkA2 (mkA "equal") to_Prep) term ;
PBetween x y = mkAP (mkA2 (mkA "between") (mkPrep "")) (mkNP and_Conj x y) ; ---
ESum x y =
mkNP the_Det (mkCN (mkN2 (mkN "sum")) (mkNP and_Conj x y)) -- the sum of x and y
| mkNP (mkConj "+" singular) x y -- x + y
| parenthNP (mkNP (mkConj "+" singular) x y) -- ( x + y )
;
EMinus x y =
mkNP the_Det (mkCN (mkN2 (mkN "difference")) (mkNP and_Conj x y)) -- the difference of x and y
| mkNP (mkConj "-" singular) x y -- x - y
| parenthNP (mkNP (mkConj "-" singular) x y) -- x - y
;
EProduct x y =
mkNP the_Det (mkCN (mkN2 (mkN "product")) (mkNP and_Conj x y)) -- the product of x and y
| mkNP (mkConj "*" singular) x y -- x * y
;
EDivided x y =
mkNP (mkConj "divided by" singular) x y -- the product of x and y
| mkNP (mkConj "/" singular) x y -- x * y
;
EFactorial x =
mkNP the_Det (mkCN (mkN2 (mkN "factorial")) x) -- the factorial of x
| mkNP x (ParadigmsEng.mkAdv "!") -- x !
;
oper
parenthNP : NP -> NP = \np -> MarkupNP (lin Mark {begin = "(" ; end = ")"}) np ;
}

45
python/QuerySwe.gf Normal file
View File

@@ -0,0 +1,45 @@
concrete QuerySwe of Query =
open
SyntaxSwe, ParadigmsSwe, SymbolicSwe, (L = LexiconSwe)
in {
lincat
Query = Utt ;
Kind = CN ;
Property = AP ;
Term = NP ;
Element = NP ;
lin
QWhich kind property = mkUtt (mkQS (mkQCl (mkIP whichPl_IDet kind) property)) ;
QWhether term property = mkUtt (mkQS (mkQCl (mkCl term property))) ;
QWhat element = mkUtt (mkQS (mkQCl what_IP element)) ;
TAll kind = mkNP all_Predet (mkNP aPl_Det kind) ;
TAny kind = mkNP someSg_Det kind ;
TElement element = element ;
PAnd p q = mkAP and_Conj p q ;
POr p q = mkAP or_Conj p q ;
PNot p = mkAP (lin AdA {s = "inte"}) p ; ---
KProperty property kind = mkCN property kind ;
-- lexicon
KNumber = mkCN (mkN "tal" "tal") ;
EInteger i = symb i ;
PEven = mkAP (mkA "jämn") ;
POdd = mkAP (invarA "udda") ;
PPrime = mkAP (mkA "prim") ; ----
PDivisible term = mkAP (mkA2 (mkA "delbar") with_Prep) term ;
PSmaller term = mkAP L.small_A term ;
PGreater term = mkAP L.big_A term ;
PBetween x y = mkAP (mkA2 (invarA "mellan") (mkPrep "")) (mkNP and_Conj x y) ; ---
ESum x y = mkNP the_Det (mkCN (mkN2 (mkN "summa")) (mkNP and_Conj x y)) ;
EProduct x y = mkNP the_Det (mkCN (mkN2 (mkN "produkt")) (mkNP and_Conj x y)) ;
EFactorial x = mkNP the_Det (mkCN (mkN2 (mkN "fakultet")) x) ;
}

122
python/README.md Normal file
View File

@@ -0,0 +1,122 @@
# Examples of embedded GF grammars in Python
The grammars use the Python binding available in
https://github.com/GrammaticalFramework/gf-core
see
`src/runtime/python/`
for installing the Python module `pgf`, and
`src/runtime/c/`
for the C runtime library that the bindings are based on.
You don't need Haskell to build these.
A general tutorial on the Python bindings can be found in
http://www.grammaticalframework.org/doc/runtime-api.html#python
A guide to GF for Python programmers can be found in
https://daherb.github.io/GF-for-Python-programmers/
## Translator
A minimal translator can be found in
[`minitranslator.py`](./minitranslator.py)
This program reads one line of input and translates it from English to Swedish by using `MiniGrammar.pgf`. Example:
```
$ echo "the cat is black" | python3 minitranslator.py
katten är svart
```
A more general version is in
[`translator.py`](./translator.py)
This program reads input line by line, tokenizes it (by a simple tokenizer), and uses an arbitrary pgf and language codes. Example:
```
$ cat findrawscript.txt | python3 translator.py Draw Fin Eng
# translating with Draw.pgf from DrawFin to DrawEng
draw a small red circle
draw a big yellow square
move the small red circle
remove it
```
## Drawing figures
A minimal drawing program with natural language input can found in
[`minidraw.py`](./minidraw.py)
This program reads one line of input in English and converts it to an action of drawing a circle or a square. Example:
```
$ python3 minidraw.py
draw a circle
```
The result is [this window](./dump-minidraw.png).
The program uses the simple graphics library from
https://mcsp.wartburg.edu/zelle/python/graphics.py
We also presuppose the grammar to be compiled with
`
make draw
`
A more complete version (using the same grammar) is in
[`draw.py`](./draw.py)
This program opens a session where it reads input line by line, in a language specified by a language code. Example:
```
$ python3 draw.py Eng
draw a small red circle
draw a blue square
move it
move the small red circle
```
The result is [this window](./dump-draw.png).
The grammar, [`Draw.gf`](./Draw.gf), illustrates a few things...
## Answering queries
A minimal query answering program with natural language input can found in
[`miniquery.py`](./miniquery.py)
This program reads one line of input in English and executes a query, which is either asking if a number is prime, or calculating a sum. Examples:
```
$ echo "is 143 prime" | python3 miniquery.py
False
$ echo "1 + 2 + 3" | python3 miniquery.py
6
```
We presuppose the grammar to be compiled with
`
make query
`
A more complete version (using the same grammar) is in
[`query.py`](./query.py)
This program uses a large grammar with more predicates, operations, and logical forms such as quantifiers. It still reads just one line of input, but allows the language to be specified by a language code. Example:
```
$ echo "what is the factorial of 12" | python3 query.py Eng
479001600
$ echo "prime numbers between 200 and 300" | python3 query.py Eng
[211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293]
WARNING: ambiguous
$ echo "are all prime numbers odd" | python3 query.py Eng
False
```
The grammar, [`Query.gf`](./Query.gf), illustrates a few things...

193
python/draw.py Normal file
View File

@@ -0,0 +1,193 @@
# drawing figures with natural language commands
# presupposes 'gf -make DrawEng.gf (DrawSwe.gf ...)'
import pgf
from graphics import *
import sys
from random import randrange
# we assume this abstract syntax
absmodule = "Draw"
# change this to change input language
langname = absmodule + "Eng"
# the size of canvas
hsize, vsize = 1000,1000
# the mid point of the canvas
midpoint = (hsize/2,vsize/2)
# unit size granularity
sizeunit = hsize//10
# big and small size factors
bigsize = 2
smallsize = 0.2
# limits of radius and diameter/2
maxradius = sizeunit
minradius = sizeunit/2
# distance of movement
distunit = 2*sizeunit
def execute(command,win):
"top level: execute a Command in a window (given in main)"
fun,args = command.unpack()
if fun == "drawCommand":
obj = shape(args[0])
obj.draw(win)
return str(args[0]),obj,fun
if fun == "removeCommand":
key = reference(args[0])
return key,None,fun
if fun == "moveCommand":
key = reference(args[0])
return key,direction(args[1]),fun
def reference(objectref):
fun,args = objectref.unpack()
if fun == "theObjectRef":
return(str(args[0]))
else:
return(str(objectref))
def shape(obj):
"draw a Shape of random size and position, possibly with colour and rough size specified"
fun,args = obj.unpack()
sz,xx = args[0].unpack()
if sz == "big_Size":
factor = bigsize
elif sz == "small_Size":
factor = smallsize
else:
factor = 1
midx,midy = midpoint
x1 = midx + randrange(-midx,midx,1)
y1 = midy + randrange(-midy,midy,1)
r = factor * randrange(minradius, maxradius, 1)
d = 2 * r
x2 = x1 + d
y2 = y1 + d
sh,xx = args[2].unpack()
if sh == "circle_Shape":
shap = Circle(Point(x1,y1),r)
elif sh == "square_Shape":
shap = Rectangle(Point(x1,y1),Point(x2,y2))
else:
shap = None
co,xx = args[1].unpack()
if co == "green_Colour":
shap.setFill('green')
elif co == "red_Colour":
shap.setFill('red')
elif co == "blue_Colour":
shap.setFill('blue')
elif co == "yellow_Colour":
shap.setFill('yellow')
else:
pass
return shap
def direction(place):
fun,args = place.unpack()
if fun == "upPlace":
return 0,-distunit
if fun == "downPlace":
return 0,distunit
if fun == "leftPlace":
return -distunit,0
if fun == "rightPlace":
return distunit,0
else:
return randrange(-2*distunit,2*distunit,1),randrange(-2*distunit,2*distunit,1)
def addRef(ref,obj,refs):
"adds a reference and object to the top of the stack"
return [(ref,obj)] + refs
def lookupRef(ref,refs):
"return the first value and index of ref in a list of pairs refs"
i = 0
for ro in refs:
r,obj = ro
if matchRef(ref,r):
return r,obj,i
else:
i = i + 1
return None,None,None
def removeRef(ref,refs):
"remove the first pair matching ref in refs"
r,obj,i = lookupRef(ref,refs)
refs.pop(i)
return refs
def matchRef(ref,r):
if ref == "itObjectRef":
return True
else:
refws = ref.split()
rws = r.split()
m = True
for i in range(1,4):
if (refws[i][0:2] != "no") and (refws[i] != rws[i]):
return False
return m
def main():
"initialize with a window, process Command input line by line; optional language argument"
win = GraphWin("GF Draw", hsize, vsize)
refs = []
latest = "it"
gr = pgf.readPGF(absmodule + ".pgf")
lang = langname
if len(sys.argv) > 1:
lang = absmodule + sys.argv[1]
eng = gr.languages[lang]
while True:
try:
line = input("")
except EOFError:
break
if not(line):
pass
else:
try:
px = eng.parse(line.lower())
p,tree = px.__next__()
key,obj,co = execute(tree,win)
if co == "drawCommand":
refs = addRef(key,obj,refs)
elif co == "removeCommand":
ref,sh,i = lookupRef(key,refs)
if sh is None:
print("no such object")
else:
sh.undraw()
refs = removeRef(key,refs)
elif co == "moveCommand":
x,y = obj
ref,sh,i = lookupRef(key,refs)
if sh is None:
print("no such object")
else:
sh.move(x,y)
refs = [(ref,sh)] + refs[:i] + refs[i+1:]
else:
print("nothing else can be done")
print(refs) ## debugging
except pgf.ParseError:
print("# NO PARSE", line)
main()

4
python/findrawscript.txt Normal file
View File

@@ -0,0 +1,4 @@
piirrä pieni punainen ympyrä
piirrä suuri keltainen neliö
siirrä pientä punaista ympyrää
poista se

1015
python/graphics.py Normal file

File diff suppressed because it is too large Load Diff

51
python/minidraw.py Normal file
View File

@@ -0,0 +1,51 @@
# minimal drawing from natural language input: just draw one square or circle
# presupposes 'gf -make DrawEng.gf'
import pgf
from graphics import *
# we assume this abstract syntax
absmodule = "Draw"
# change this to change input language
langname = absmodule + "Eng"
def execute(command,win):
"interpret drawCommand; other commands ignored"
fun,args = command.unpack()
if fun == "drawCommand":
obj = shape(args[0])
obj.draw(win)
else:
print("command not available")
def shape(obj):
"draw Shape, ignoring given colour and size in this simple example"
fun,args = obj.unpack()
sh,xx = args[2].unpack()
if sh == "circle_Shape":
shap = Circle(Point(300,300),200)
elif sh == "square_Shape":
shap = Rectangle(Point(200,200),Point(600,600))
else:
shap = None
return shap
def main():
"execute one line of input, quit by second Enter"
win = GraphWin("GF Draw", 1000, 1000)
gr = pgf.readPGF(absmodule + ".pgf")
eng = gr.languages[langname]
line = input()
px = eng.parse(line.lower())
p,tree = px.__next__()
execute(tree,win)
input()
main()

72
python/miniquery.py Normal file
View File

@@ -0,0 +1,72 @@
# a minimal query system for arithmetic, using Montague-style semantics
# and an embedded GF grammar
# examples: "is 131 prime", "2 + 2"
# presupposes 'gf -make QueryEng (QuerySwe ...)'
import pgf
import sys
# we assume this abstract syntax
absmodule = "Query"
# change this to change input language
langname = absmodule + "Eng"
# the meaning of "number" in unrestricted quantification
allNumbers = range(1,10000)
def answer(tree):
"top level Query interpreter"
fun,args = tree.unpack()
if fun == "QWhether":
ans = predicate(args[1])(value(args[0]))
else: # QWhat
ans = value(args[0])
return str(ans)
def predicate(property):
"takes Property or Kind to int -> bool"
prop,pargs = property.unpack()
if prop == "PPrime":
return prime
else:
print("property not available")
def value(term):
"takes Term to int, does not cover quantifiers"
fun,args = term.unpack()
if fun == "TElement":
return value(args[0])
elif fun == "EInteger":
return int(args[0].unpack())
elif fun == "ESum":
return value(args[0]) + value(args[1])
else:
print("term not availeble")
def prime(n):
"simple way to decide if a positive number is prime"
if n == 1:
r = False
else:
r = True
for k in range(2,n//2+1):
if n % k == 0: return False
return r
def main():
"main function to be called from stdio"
# read in the grammar, set up the input language
grammar = pgf.readPGF(absmodule + ".pgf")
lang = grammar.languages[langname]
# read a line of input, parse in lang, return answer
line = input("")
parseresult = lang.parse(line)
prob,tree = parseresult.__next__()
print(answer(tree))
main()

25
python/minitranslator.py Normal file
View File

@@ -0,0 +1,25 @@
# minimal translator that reads one line from stdio and translates from Eng to Swe with Minilang
# presupposes 'make minilang'
import pgf
# change these three to translate with other grammars and languages
absmodule = "MiniLang"
fromname = absmodule + "Eng"
toname = absmodule + "Swe"
def main():
# read in the grammar, set up to and from languages
grammar = pgf.readPGF(absmodule + ".pgf")
fromlang = grammar.languages[fromname]
tolang = grammar.languages[toname]
# read a line of input, parse in "from" language, linearize in "to" language
line = input("")
parseresult = fromlang.parse(line)
prob,tree = parseresult.__next__()
print(tolang.linearize(tree))
main()

151
python/query.py Normal file
View File

@@ -0,0 +1,151 @@
# a simple query system for arithmetic, using Montague-style semantics
# and an embedded GF grammar
# examples: "is 131 prime", "which numbers are prime", "365 * 24 * 60"
# presupposes 'gf -make QueryEng (QuerySwe ...)'
import pgf
import sys
# we assume this abstract syntax
absmodule = "Query"
# change this to change input language
langname = absmodule + "Eng"
# the meaning of "number" in unrestricted quantification
allNumbers = range(1,10000)
def answer(tree):
"top level Query interpreter"
fun,args = tree.unpack()
if fun == "QWhich":
ans = enumerate(lambda x: predicate(args[0])(x) and predicate(args[1])(x), allNumbers)
elif fun == "QWhether":
ans = quantifier(args[0])(predicate(args[1]))
else: # QWhat
ans = value(args[0])
return str(ans)
def predicate(property):
"takes Property or Kind to int -> bool"
prop,pargs = property.unpack()
if prop == "PAnd":
return lambda x: predicate(pargs[0])(x) and predicate(pargs[1])(x)
elif prop == "POr":
return lambda x: predicate(pargs[0])(x) or predicate(pargs[1])(x)
elif prop == "PNot":
return lambda x: not predicate(pargs[0])(x)
elif prop == "PEven":
return lambda x: x % 2 == 0
elif prop == "POdd":
return lambda x: x % 2 != 0
elif prop == "PEqual":
return lambda x: quantifier(pargs[0])(lambda y: x == y)
elif prop == "PSmaller":
return lambda x: quantifier(pargs[0])(lambda y: x < y)
elif prop == "PGreater":
return lambda x: quantifier(pargs[0])(lambda y: x > y)
elif prop == "PBetween":
return lambda y: quantifier(pargs[0])(lambda x: quantifier(pargs[1])(lambda z: x < y and y < z))
elif prop == "PPrime":
return prime
# works also for Kind:
elif prop == "KNumber":
return lambda x: True
elif prop == "KProperty":
return lambda x: predicate(pargs[0])(x) and predicate(pargs[1])(x)
else:
print("not a valid property",property)
def quantifier(term):
"takes Term to (int -> bool) -> bool"
fun,args = term.unpack()
if fun == "TElement":
return lambda p: p(value(args[0]))
elif fun == "TAll":
return lambda p: forAll(lambda x: not predicate(args[0])(x) or p(x), allNumbers)
elif fun == "TAny":
return lambda p: forSome(lambda x: predicate(args[0])(x) and p(x), allNumbers)
else:
print("not a valid term",term)
def value(element):
"takes Element to int"
fun,args = element.unpack()
if fun == "EInteger":
return int(args[0].unpack())
elif fun == "ESum":
return value(args[0]) + value(args[1])
elif fun == "EProduct":
return value(args[0]) * value(args[1])
elif fun == "EMinus":
return value(args[0]) - value(args[1])
elif fun == "EDivided":
return value(args[0]) / value(args[1]) ## // ?
elif fun == "EFactorial":
return factorial(value(args[0]))
else:
print("not a valid element",element)
def prime(n):
"simple way to decide if a positive number is prime"
if n == 1:
r = False
else:
r = True
for k in range(2,n//2+1):
if n % k == 0: return False
return r
def forAll(p,ns):
"universal quantifier over a list"
for n in ns:
if not p(n): return False
return True
def forSome(p,ns):
"existential quantifier over a list"
for n in ns:
if p(n): return True
return False
def enumerate(p,ns):
"filter over a list"
r = []
for n in ns:
if p(n): r = r + [n]
return r
def enumer(p,ns):
return [n for n in ns if p(n)]
def factorial(n):
"factorial of positive numbers"
r = 1
for k in range(1,n+1):
r = k*r
return r
def main():
"main function to be called from stdio, language code as optional argument"
# read in the grammar, set up the input language
grammar = pgf.readPGF(absmodule + ".pgf")
langcode = langname
if len(sys.argv) > 1:
langcode = absmodule + sys.argv[1]
lang = grammar.languages[langcode]
# read a line of input, parse in lang, return answer
line = input("")
parseresult = lang.parse(line)
prob,tree = parseresult.__next__()
# print(tree) ## debugging
print(answer(tree))
for r in parseresult: print("WARNING: ambiguous")
main()

68
python/translator.py Normal file
View File

@@ -0,0 +1,68 @@
# translator for arbitrary pgf grammar and language pair, given as arguments
import pgf
import sys
def trim(s0):
"lower-case first word and tokenize"
s = s0.strip()
if not(s):
return s
s = (s[0].lower() + s[1:])
r = ""
for c in s:
if c in [',','.',':','(',')']:
r = r + ' ' + c + ' '
else:
r = r + c
return r
def missing(eng,s):
"words in a sentence not found in morphological analysis"
ws = s.split()
ms = []
for w in ws:
if not eng.lookupMorpho(w): # strange behaviour of eng
ms = ms + [w]
return ms
def main():
"translation loop, reads stdio line by line"
if len(sys.argv) < 4:
print(" usage: python3 translator.py <pgf-file-prefix> <from-lang-suffix> <to-lang-suffix> -debug?")
print(" e.g. python3 translator.py CSETranslator Eng Swe")
print(" The program reads and writes stdio line by line, e.g")
print(" cat ../course_plans/TIN214Eng.txt | python3 translator.py CSEShallow Eng Swe")
return
pgfm = sys.argv[1]
pgff = pgfm + ".pgf"
ceng = pgfm + sys.argv[2]
cswe = pgfm + sys.argv[3]
debug = len(sys.argv) == 5 and sys.argv[4] == "-debug"
gr = pgf.readPGF(pgff)
eng = gr.languages[ceng]
swe = gr.languages[cswe]
print("#","translating with",pgff,"from",ceng,"to",cswe)
while True:
try:
line = input("")
except EOFError:
break
t = trim(line)
if not(t):
pass
else:
try:
px = eng.parse(t)
p,e = px.__next__()
if debug:
print("# TREE", e)
print(swe.linearize(e))
except pgf.ParseError:
print("# NO PARSE", t)
if debug:
print("# MISSING", missing(eng,t))
main()