Nobel queries

This commit is contained in:
Aarne Ranta
2025-05-07 08:52:51 +02:00
parent 82af461eb8
commit 262b3fe129
3 changed files with 265 additions and 0 deletions

48
lab2/query/Query.gf Normal file
View File

@@ -0,0 +1,48 @@
abstract Query = Nobel ** {
flags startcat = Query ;
cat
Query ;
Kind ;
Property ;
Term ;
Element ;
fun
QWhich : Kind -> Property -> Query ; -- which laureates are female
QHowMany : Kind -> Property -> Query ; -- how many women are there
QWhether : Term -> Property -> Query ; -- is Martti Ahtisaari from Finland
QWhat : Element -> Query ; -- who is the youngest laureate
TAll : Kind -> Term ; -- all laureate
TAny : Kind -> Term ; -- any laureate
KProperty : Property -> Kind -> Kind ; -- female laureate
ELaureate : Name -> Element ; -- Martti Ahtisaari
EYoungest : Kind -> Element ; -- the youngest laureate
EOldest : Kind -> Element ; -- the oldest laureate
KMan : Kind ;
KWoman : Kind ;
KLaureate : Kind ;
KChemistryLaureate : Kind ;
KLiteratureLaureate : Kind ;
KMedicineLaureate : Kind ;
KPeaceLaureate : Kind ;
KPhysicsLaureate : Kind ;
PCountry : Country -> Property ;
PBornIn : Date -> Property ;
PAwardedIn : Date -> Property ;
PMale : Property ;
PFemale : Property ;
BeforeYearDate : Int -> Date ;
AfterYearDate : Int -> Date ;
}

104
lab2/query/QueryEng.gf Normal file
View File

@@ -0,0 +1,104 @@
--# -path=.:alltenses:../grammars
concrete QueryEng of Query = NobelEng **
open
SyntaxEng, ParadigmsEng,
SymbolicEng,
(G = GrammarEng),
(M = MakeStructuralEng),
Prelude
in {
lincat
Query = Utt ;
Kind = CN ;
Property = {ap : AP ; adv : Adv ; isAdv : Bool} ;
Term = NP ;
Element = NP ;
lin
QWhich kind property =
mkUtt (mkQS tenses (mkQCl (mkIP whichPl_IDet kind) (propertyVP property)))
| mkUtt (mkNP aPl_Det (propertyCN property kind))
;
QHowMany kind property =
mkUtt (mkQS tenses (mkQCl (mkIP how8many_IDet kind) (propertyVP property)))
| mkUtt (mkIP how8many_IDet (propertyCN property kind))
;
QWhether term property =
mkUtt (mkQS tenses (mkQCl (mkCl term (propertyVP property))))
;
QWhat element =
mkUtt (mkQS tenses (mkQCl who_IP element)) -- what is 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
;
KProperty property kind = propertyCN property kind ;
ELaureate name = name ;
EYoungest kind = mkNP (mkDet the_Quant (SyntaxEng.mkOrd (mkA "young" "younger"))) kind ;
EOldest kind = mkNP (mkDet the_Quant (SyntaxEng.mkOrd (mkA "old"))) kind ;
KMan = mkCN (mkN "man" "men") ;
KWoman = mkCN (mkN "woman" "women") ;
KLaureate = mkCN (mkN "laureate") | mkCN (mkN "Nobel prize laureate") ;
KChemistryLaureate = mkCN (mkN "chemistry laureate") ;
KLiteratureLaureate = mkCN (mkN "literature laureate") ;
KMedicineLaureate = mkCN (mkN "medicine laureate") ;
KPeaceLaureate = mkCN (mkN "peace laureate") ;
KPhysicsLaureate = mkCN (mkN "physics laureate") ;
PCountry country = mkProperty (SyntaxEng.mkAdv from_Prep country) ;
PBornIn date = mkProperty (G.AdvAP (mkAP (mkA "born")) date) ;
PAwardedIn date = mkProperty date ;
PMale = mkProperty "male" ;
PFemale = mkProperty "female" ;
BeforeYearDate y = SyntaxEng.mkAdv before_Prep <symb y : NP> ;
AfterYearDate y = SyntaxEng.mkAdv after_Prep <symb y : NP> ;
oper
tenses = presentTense | pastTense ;
mkProperty = overload {
mkProperty : Str -> Property = \s ->
lin Property {ap = mkAP (mkA s) ; adv = ParadigmsEng.mkAdv "" ; isAdv = False} ;
mkProperty : AP -> Property = \ap ->
lin Property {ap = ap ; adv = ParadigmsEng.mkAdv "" ; isAdv = False} ;
mkProperty : Adv -> Property = \adv ->
lin Property {ap = mkAP (mkA "") ; adv = adv ; isAdv = True} ;
} ;
propertyCN : {ap : AP ; adv : Adv ; isAdv : Bool} -> CN -> CN = \prop, cn ->
case prop.isAdv of {
True => mkCN cn prop.adv ;
False => mkCN prop.ap cn
} ;
propertyVP : {ap : AP ; adv : Adv ; isAdv : Bool} -> VP = \prop ->
case prop.isAdv of {
True => mkVP prop.adv ;
False => mkVP prop.ap
} ;
}

113
lab2/query/query.py Normal file
View File

@@ -0,0 +1,113 @@
import sys
import json
import pgf
# we assume this abstract syntax
ABSMODULE = "Query"
# data file with laureates
DATAFILE = '../data/query.json'
WIKIDATA_PREFIX = 'http://www.wikidata.org/entity/'
# the domain of quantification is the list of laureates with their properties, built from the query result
with open(DATAFILE) as file:
data = json.load(file)
def listNames(ds):
return [d['personLabel'] for d in ds]
def funQID(fun):
return WIKIDATA_PREFIX + str(fun).split('_')[0]
def age(d):
return int(d['date'][:4]) - int(d['birthDate'][:4])
def answer(tree):
"top level Query interpreter"
match tree.unpack():
case ("QWhich", [kind, property]):
return listNames([x for x in data if predicate(kind)(x) and predicate(property)(x)])
case ("QHowMany", [kind, property]):
return len([x for x in data if predicate(kind)(x) and predicate(property)(x)])
case ( "QWhether", [term, property]):
return quantifier(term)(predicate(property))
case ( "QWhat", [element]):
return value(element)
print('not yet', str(tree))
def predicate(tree):
"takes Property or Kind to int -> bool"
match tree.unpack():
case ("PCountry", [fun]):
return lambda d: d['country'] == funQID(fun)
case ("PMale", []):
return lambda d: d['sexLabel'] == 'male'
case ("PFemale", []):
return lambda d: d['sexLabel'] == 'female'
case ("KProperty", [property, kind]):
return lambda d: predicate(property)(d) and predicate(kind(d))
case ("KLaureate", []):
return lambda d: True
case ("KMan", []):
return lambda d: d['sexLabel'] == 'male'
case ("KWoman", []):
return lambda d: d['sexLabel'] == 'female'
print('not yet', str(tree))
def quantifier(term):
"takes Term to (int -> bool) -> bool"
match term.unpack():
case ("TElement", element):
return lambda p: p(value(element))
case ("TAll", [kind]):
return lambda p: all(lambda x: not predicate(kind)(x) or p(x), data)
case ("TAny", [kind]):
return lambda p: any(lambda x: predicate(kind)(x) and p(x), data)
print('not yet', str(tree))
def value(element):
"takes Element to a laureate record"
match element.unpack():
case ('ELaureate', [name]):
_, string = name.unpack
return [d for d in data if d['personLabel'] == string][0] ## uncertain !
case ('EYoungest', [kind]):
return min(data, key = age)
case ('EOldest', [kind]):
return max(data, key = age)
print('not yet', str(tree))
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")
LANG = ABSMODULE + sys.argv[1]
lang = grammar.languages[LANG]
# 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()