diff --git a/lab2/query/Query.gf b/lab2/query/Query.gf new file mode 100644 index 0000000..38c6f30 --- /dev/null +++ b/lab2/query/Query.gf @@ -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 ; + +} \ No newline at end of file diff --git a/lab2/query/QueryEng.gf b/lab2/query/QueryEng.gf new file mode 100644 index 0000000..39b6b33 --- /dev/null +++ b/lab2/query/QueryEng.gf @@ -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 ; + AfterYearDate y = SyntaxEng.mkAdv after_Prep ; + +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 + } ; + +} \ No newline at end of file diff --git a/lab2/query/query.py b/lab2/query/query.py new file mode 100644 index 0000000..852a7e8 --- /dev/null +++ b/lab2/query/query.py @@ -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()