├── src ├── __init__.py ├── build │ ├── __init__.py │ ├── base.py │ ├── grammar.py │ ├── conjunctions.py │ ├── adjectives.py │ ├── nouns.py │ ├── verbs.py │ └── names.py ├── drt │ ├── __init__.py │ ├── resolve.py │ └── drs.py ├── ext │ ├── __init__.py │ ├── plural.py │ └── LICENSE.txt ├── prover │ ├── mace4 │ ├── prover9 │ ├── mace4.exe │ ├── cygwin1.dll │ ├── prover9.exe │ ├── README │ └── cnf.c.patch ├── grammar.tar.gz ├── data │ ├── crystal.ico │ └── conjunctions.pickle ├── tokenizer.py ├── logic.py ├── utterance.py ├── cfg_parser.py ├── engine.py ├── __main__.py └── grammar │ ├── base_rules.fcfg │ └── base_lexicon.fcfg ├── crystal.ico ├── docs ├── img │ ├── S1.png │ ├── S2.png │ ├── Thumbs.db │ ├── boxes.png │ ├── drs1.png │ ├── drs2.png │ ├── drs3.png │ ├── drs4.png │ ├── drs5.png │ ├── drs6.png │ ├── drs7.png │ ├── tree.png │ ├── Overview.png │ └── Overview_old.png └── report.odt ├── brainstorming ├── conjunctions.ods ├── catdog-dilemma.txt ├── resolution_examples.txt ├── grammar_toadd.txt ├── examples.txt ├── verb_rules.txt ├── lambdas.txt ├── questions_blackboard.txt ├── demo_plan.txt └── bookmarks.html └── README.md /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/build/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/drt/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ext/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /crystal.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/crystal.ico -------------------------------------------------------------------------------- /docs/img/S1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/S1.png -------------------------------------------------------------------------------- /docs/img/S2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/S2.png -------------------------------------------------------------------------------- /docs/report.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/report.odt -------------------------------------------------------------------------------- /src/prover/mace4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/prover/mace4 -------------------------------------------------------------------------------- /docs/img/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/Thumbs.db -------------------------------------------------------------------------------- /docs/img/boxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/boxes.png -------------------------------------------------------------------------------- /docs/img/drs1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs1.png -------------------------------------------------------------------------------- /docs/img/drs2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs2.png -------------------------------------------------------------------------------- /docs/img/drs3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs3.png -------------------------------------------------------------------------------- /docs/img/drs4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs4.png -------------------------------------------------------------------------------- /docs/img/drs5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs5.png -------------------------------------------------------------------------------- /docs/img/drs6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs6.png -------------------------------------------------------------------------------- /docs/img/drs7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/drs7.png -------------------------------------------------------------------------------- /docs/img/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/tree.png -------------------------------------------------------------------------------- /src/grammar.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/grammar.tar.gz -------------------------------------------------------------------------------- /src/prover/prover9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/prover/prover9 -------------------------------------------------------------------------------- /docs/img/Overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/Overview.png -------------------------------------------------------------------------------- /src/data/crystal.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/data/crystal.ico -------------------------------------------------------------------------------- /src/prover/mace4.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/prover/mace4.exe -------------------------------------------------------------------------------- /src/prover/cygwin1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/prover/cygwin1.dll -------------------------------------------------------------------------------- /src/prover/prover9.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/src/prover/prover9.exe -------------------------------------------------------------------------------- /docs/img/Overview_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/docs/img/Overview_old.png -------------------------------------------------------------------------------- /brainstorming/conjunctions.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max99x/crystal/HEAD/brainstorming/conjunctions.ods -------------------------------------------------------------------------------- /src/prover/README: -------------------------------------------------------------------------------- 1 | This folder should contain the LADR binaries, Mace4 and Prover9. 2 | For Unix, use "mace4" and "prover9" (32-bit binaries). 3 | For Windows, use "mace4.exe", "prover9.exe". This also uses "cygwin1.dll". 4 | 5 | This folder also includes a patch for LADR's cnf.c that has to be applied to 6 | version LADR-2009-11A (latest at the time of writing) to produce the binaries 7 | stored here. 8 | -------------------------------------------------------------------------------- /src/tokenizer.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | TOKEN_PATTERN = r'\.\.\.|\.|\?!|\?|!|,|;|\(|\)|\$|"|&|\d+|[-\w]+|\'[-\w]*' 5 | TOKEN_REGEX = re.compile(TOKEN_PATTERN) 6 | SENTENCE_REGEX = re.compile('^(?:(?:%s)|\s+)+$' % TOKEN_PATTERN) 7 | 8 | 9 | class TokenizerError(Exception): pass 10 | 11 | 12 | def Tokenize(sentence): 13 | if not SENTENCE_REGEX.match(sentence): 14 | raise TokenizerError('Could not parse sentence: %s' % sentence) 15 | else: 16 | return TOKEN_REGEX.findall(sentence.lower()) 17 | -------------------------------------------------------------------------------- /src/prover/cnf.c.patch: -------------------------------------------------------------------------------- 1 | *** ladr/cnf_OLD.c 2011-04-30 19:43:00.040309423 +0300 2 | --- ladr/cnf.c 2011-04-30 19:34:34.850296998 +0300 3 | *************** 4 | *** 509,514 **** 5 | f->kids[i] = cnf(f->kids[i]); 6 | 7 | if (f->type == AND_FORM) { 8 | - f = flatten_top(f); 9 | f = simplify_and_share(f); 10 | return f; 11 | --- 509,514 ---- 12 | f->kids[i] = cnf(f->kids[i]); 13 | 14 | + f = flatten_top(f); 15 | if (f->type == AND_FORM) { 16 | f = simplify_and_share(f); 17 | return f; 18 | -------------------------------------------------------------------------------- /src/build/base.py: -------------------------------------------------------------------------------- 1 | import re 2 | import nltk.corpus 3 | 4 | 5 | def SplitLemma(lemma): 6 | if hasattr(lemma, 'name'): 7 | lemma = lemma.name 8 | lemma = lemma.lower() 9 | lemma = re.sub(r"(\'[-\w]+)", r'_\1_', lemma) 10 | return re.split('_+', lemma.strip('_')) 11 | 12 | 13 | def LemmaToTerminals(lemma): 14 | return ' '.join('"%s"' % i for i in SplitLemma(lemma)) 15 | 16 | 17 | def GetCompoundCount(lemma): 18 | pieces = SplitLemma(lemma) 19 | if len(pieces) == 1: 20 | return lemma.count() 21 | else: 22 | get_lemmas = nltk.corpus.wordnet.lemmas 23 | pieces_counts = [max([0] + [i.count() for i in get_lemmas(piece)]) 24 | for piece in pieces] 25 | return lemma.count() + sum(pieces_counts) 26 | -------------------------------------------------------------------------------- /brainstorming/catdog-dilemma.txt: -------------------------------------------------------------------------------- 1 | A dog is a cat. 2 | [x, y | dog(x), cat(y), x=y] 3 | [x | dog(x), cat(x)] 4 | A dog is not a cat. 5 | [x | dog(x), -[y | cat(y), x=y]] 6 | [x | dog(x), -[y | cat(x), x=y]] 7 | *A dog is the cat. 8 | [x | dog(x), y ? cat(y), x=y] 9 | [x | dog(x), cat(x)] 10 | *A dog is not the cat. 11 | [x | dog(x), -[ | y ? cat(y), x=y]] 12 | [x, y | dog(x), cat(y), -[ | x=y]] 13 | *The dog is the cat. 14 | [ | x ? dog(x), y ? cat(y), x=y] 15 | [x | dog(x), cat(x)] 16 | *The dog is not the cat. 17 | [ | x ? dog(x), -[ | y ? cat(y), x=y]] 18 | [x, y | dog(x), cat(y) -[ | x=y]] 19 | [a, b | cat(a), dog(b)] 20 | *A dog is the cat. 21 | [x | dog(x), y ? cat(y), x=y] 22 | [a, b | cat(a), dog(b), dog(a)] 23 | *A dog is not the cat. 24 | [x | dog(x), -[ | y ? cat(y), x=y]] 25 | [a, b, x | cat(a), dog(b), dog(x), -[ | x=a]] 26 | *The dog is the cat. 27 | [ | x ? dog(x), y ? cat(y), x=y] 28 | [a | cat(a), dog(a)] 29 | *The dog is not the cat. 30 | [ | x ? dog(x), -[ | y ? cat(y), x=y]] 31 | [a, b | dog(a), cat(b) -[ | a=b]] 32 | -------------------------------------------------------------------------------- /brainstorming/resolution_examples.txt: -------------------------------------------------------------------------------- 1 | A dog is hungry. 2 | The dog is hungry. 3 | A dog waltzes. 4 | A dog waltzes. The dog is hungry. 5 | A dog waltzes. The cat is hungry. 6 | A dog waltzes. The man is hungry. 7 | A dog waltzes. It is hungry. 8 | *A dog waltzes. She is hungry. 9 | *A spoon waltzes. 10 | *He dances. 11 | *A dog eats it. 12 | A dog is a dog. 13 | A dog is not a dog. (animal != sausage) 14 | *A candelabra is not a candelabra. 15 | A dog is not a cat. 16 | The dog is not the cat. 17 | A dog is not the cat. 18 | Mary is the best. 19 | If a dog is hungry then it is angry. 20 | If a dog is hungry then the dog is angry. 21 | If a dog is hungry then the cat is angry. 22 | If a dog is hungry then a dog is angry. 23 | *If a hippo is hungry then she is angry. 24 | If Alice dances, she is happy. 25 | If a farmer owns a donkey, he beats it. 26 | If Mia is married, she has a husband. 27 | If Mia is aghast, she is not aghast. 28 | If a farmer owns a hippo, he eats it. 29 | Alice likes pets. The dog is hers. 30 | Alice has a cat. The dog is hers. 31 | Alice has a cat. Her cat is cute. 32 | The man's assistant is lazy. 33 | Bob is busy. His assistant is lazy. 34 | Bob is busy. The man is lazy. 35 | Bob is busy. The man's assistant is lazy. 36 | -------------------------------------------------------------------------------- /src/build/grammar.py: -------------------------------------------------------------------------------- 1 | import os 2 | import adjectives 3 | import conjunctions 4 | import names 5 | import nouns 6 | import verbs 7 | 8 | 9 | PATTERNS_PATH = 'data/patterns.pickle' 10 | GRAMMAR_FOLDER = 'grammar' 11 | GRAMMAR_PATH = 'grammar.fcfg' 12 | 13 | 14 | def BuildGrammar(): 15 | outfile = open(GRAMMAR_PATH, 'w') 16 | patterns_file = open(PATTERNS_PATH, 'w') 17 | 18 | for filename in os.listdir(GRAMMAR_FOLDER): 19 | s = open(os.path.join(GRAMMAR_FOLDER, filename)).read() 20 | outfile.write('\n### %s ###\n' % filename) 21 | outfile.write(s) 22 | 23 | print '\tBuilding conjunctions...' 24 | outfile.write('\n### Conjunctions ###\n') 25 | conjunctions.WriteRules(outfile) 26 | 27 | print '\tBuilding verbs...' 28 | outfile.write('\n### VPs and Verbs ###\n') 29 | verbs.WriteRules(outfile, patterns_file) 30 | 31 | print '\tBuilding names...' 32 | outfile.write('\n### Proper Nouns ###\n') 33 | names.WriteRules(outfile) 34 | 35 | print '\tBuilding adjectives...' 36 | outfile.write('\n### Adjectives ###\n') 37 | adjectives.WriteRules(outfile) 38 | 39 | print '\tBuilding nouns...' 40 | outfile.write('\n### Nouns ###\n') 41 | nouns.WriteRules(outfile) 42 | 43 | outfile.close() 44 | patterns_file.close() 45 | 46 | print '\tDone.' 47 | -------------------------------------------------------------------------------- /src/build/conjunctions.py: -------------------------------------------------------------------------------- 1 | import cPickle as pickle 2 | import base 3 | 4 | 5 | CONJUNCTIONS_PATH = 'data/conjunctions.pickle' 6 | SINGLE_TEMPLATE = 'Cnj[SEM="%s",%ss,%snp,%scv,%svp,%sadj,%sajp,%spp,%sdt,%sadv,%sseries,-compound] -> %s\n' 7 | PAIR_TEMPLATE = 'Cnj[GRP="%s",SEM="%s",%ss,%snp,%scv,%svp,%sadj,%sajp,%spp,%sdt,%sadv,%sseries,%sinit,+compound] -> %s\n' 8 | 9 | 10 | def WriteRules(outfile): 11 | conjunctions = pickle.load(open(CONJUNCTIONS_PATH)) 12 | for conjunction in conjunctions: 13 | name = conjunction[0].replace(' ', '_') 14 | semantics = conjunction[-2] 15 | is_series = '-+'[conjunction[-1]] 16 | flags = tuple('-+'[i] for i in conjunction[1:-2]) 17 | if '...' in name: 18 | group = name 19 | first, second = [i.strip() for i in name.split('...')] 20 | 21 | first_terminals = base.LemmaToTerminals(first) 22 | second_terminals = base.LemmaToTerminals(second) 23 | 24 | common_args = (group, semantics) + flags + (is_series,) 25 | 26 | outfile.write(PAIR_TEMPLATE % (common_args + ('+', first_terminals))) 27 | outfile.write(PAIR_TEMPLATE % (common_args + ('-', second_terminals))) 28 | else: 29 | terminals = base.LemmaToTerminals(name) 30 | args = (semantics,) + flags + (is_series, terminals) 31 | outfile.write(SINGLE_TEMPLATE % args) 32 | -------------------------------------------------------------------------------- /brainstorming/grammar_toadd.txt: -------------------------------------------------------------------------------- 1 | Automate the grammar optimization 2 | for r in s: 3 | ... for i in xrange(1, 158): 4 | ... out.append(re.sub(r'\b(\w+)(\[\S*?),PTRN=\?\w+', r'\1_%s\2' % i, r)) 5 | ... out.append('\n') 6 | Find a way to enforce semantic limitations on adjectives 7 | Properly resolve plural anaphora to multiple singular referents 8 | Convert resolution to a generator 9 | Syntax 10 | Verb Subject Questions 11 | PP Subject Questions 12 | Semantics 13 | Verb Subject Questions 14 | PP Subject Questions 15 | Reflexive pronouns 16 | Disambiguate 17 | [A man]'s wallet / A [man's wallet] 18 | [PP] There VB ... 19 | [PP] It VB ... 20 | Non-personal pronouns 21 | Something / Everything / Someone / Everyone 22 | Demonstrative: this, that, such 23 | Interrogative: who, which (in WH questions) 24 | Relative: who, which 25 | Indefinite: each, either, some, any, many, few, all 26 | Semantics of 1st- and 2nd-person pronouns 27 | Because / Due to 28 | Series Conjunctions 29 | NP[NUM=pl,PER=3,CASE=?c,RUL=399] -> NP[CASE=?c] (',' NP[CASE=?c])* Cnj[-compound,+np,+series] NP[CASE=?c] 30 | Adverbs (including verb- or adjective-modifying prepositional phrases) 31 | Temporal data 32 | Tense distinction 33 | Modals 34 | Passive voice 35 | Semantic understanding of numbers 36 | Compound adjectives? 37 | Multiple instances of proper names 38 | Entities with multiple proper names 39 | Subordinate clauses 40 | Numbers 41 | Subject/Object scope ambiguity 42 | Imperative 43 | Subjunctive 44 | Tagged questions 45 | Pro-verbs in declarative sentences 46 | Pro-adjectives and pro-adverbs 47 | "Minor" (verbless) sentences 48 | Echo questions 49 | Multi-target questions 50 | -------------------------------------------------------------------------------- /src/logic.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import platform 3 | 4 | 5 | if platform.system() == 'Windows': 6 | MACE_PATH = r'prover\mace4.exe' 7 | PROVER_PATH = r'prover\prover9.exe' 8 | else: 9 | MACE_PATH = r'prover/mace4' 10 | PROVER_PATH = r'prover/prover9' 11 | MACE_FAILURE_MARKER = 'Exiting with failure.' 12 | MACE_SUCCESS_MARKER = 'Exiting with 1 model.' 13 | PROVER_FAILURE_MARKER = 'SEARCH FAILED' 14 | PROVER_SUCCESS_MARKER = 'THEOREM PROVED' 15 | MACE_TEMPLATE = """ 16 | formulas(assumptions). 17 | %s. 18 | end_of_list. 19 | 20 | assign(domain_size, %d). 21 | clear(print_models). 22 | """ 23 | PROVER_TEMPLATE = """ 24 | formulas(assumptions). 25 | %s. 26 | end_of_list. 27 | 28 | formulas(goals). 29 | %s. 30 | end_of_list. 31 | 32 | assign(max_proofs, 1). 33 | clear(auto_denials). 34 | """ 35 | 36 | 37 | class ProverError(Exception): pass 38 | 39 | 40 | def IsConsistent(drs): 41 | model = MACE_TEMPLATE % (drs.Formulate(), max(len(drs.referents), 2)) 42 | return Run(MACE_PATH, model, MACE_SUCCESS_MARKER, MACE_FAILURE_MARKER) 43 | 44 | 45 | def IsProvable(assumption_drs, theorem_drs): 46 | assumptions = assumption_drs.FormulateConditions() 47 | theorem = theorem_drs.Formulate(enforce_unique=False) 48 | theorem = PROVER_TEMPLATE % (assumptions, theorem) 49 | return Run(PROVER_PATH, theorem, PROVER_SUCCESS_MARKER, PROVER_FAILURE_MARKER) 50 | 51 | 52 | def Run(command, input, success_marker, failure_marker): 53 | p = subprocess.Popen(command, 54 | shell=True, 55 | stdin=subprocess.PIPE, 56 | stdout=subprocess.PIPE, 57 | stderr=subprocess.PIPE) 58 | result = p.communicate(input)[0] 59 | if success_marker in result: 60 | return True 61 | elif failure_marker in result: 62 | return False 63 | else: 64 | raise ProverError('Could not understand mace/prover output:\n%s' % result) 65 | -------------------------------------------------------------------------------- /brainstorming/examples.txt: -------------------------------------------------------------------------------- 1 | > Mia is a woman. 2 | > Alice and John waltz. 3 | > He is happy. 4 | > Vincent eats a tasty sandwich. 5 | ! Jack does not waltz. 6 | 7 | ? What is Mary doing? 8 | -> Waltzing. 9 | ? Who is eating? 10 | -> Vincent. 11 | ? What is Jack eating? 12 | -> No known entities match the query. 13 | ? What is Vincent eating? 14 | -> The tasty sandwich. 15 | ? Who is happy? 16 | -> Jack. 17 | 18 | -------------------------------------------------------------------------------- 19 | 20 | > A cat is sitting under a tree. 21 | > The cat is eating a fish. 22 | > There are flowers under the tree. 23 | > The red flowers are blooming. 24 | > The blue flowers are wilted. 25 | > All flowers are in the shade of the tree. 26 | > Everything that is in the shade is not in the sun. 27 | ! Some flowers are in the sun. 28 | 29 | ? What is under the tree? 30 | -> The cat and the flowers. 31 | -> The cat and the flowers are under the tree. 32 | -> The cat, the red flowers and the blue flowers. 33 | -> The cat, the red flowers and the blue flowers are under the tree. 34 | ? What is blooming? 35 | -> The red flowers. 36 | -> The red flowers are blooming. 37 | ? What does the cat like? 38 | -> The fish. 39 | -> It likes the fish. 40 | -> The cat likes the fish. 41 | 42 | -------------------------------------------------------------------------------- 43 | 44 | > A tree is a tall plant. 45 | > It has a trunk and branches. 46 | > The roots of the tree are under the ground. 47 | > The tree's leaves are green. 48 | ? What does the tree have? 49 | ? What is under the ground? 50 | 51 | ? What are the parts of a tree? 52 | -> The roots, the trunk, the branches and the leaves. 53 | -> The parts of a tree are the roots, the trunk, the branches and the leaves. 54 | ? What is a tree? 55 | -> A tree is a tall plant. 56 | It has a trunk and branches. 57 | Its main parts which are the roots, the trunk, the branches and the leaves. 58 | ? What are roots? 59 | -> Roots are parts of a tree. 60 | They are usually under the ground. 61 | -------------------------------------------------------------------------------- /src/utterance.py: -------------------------------------------------------------------------------- 1 | import drt.drs 2 | import ext.plural 3 | import nltk 4 | 5 | 6 | MAX_ADJECTIVES = 3 7 | 8 | 9 | def UtterancePlanningError(Exception): pass 10 | 11 | 12 | def DescribeResult(result, question_drs, context_drs): 13 | if result is None: 14 | # TODO: Expand. 15 | return 'That is unknown.' 16 | elif result == True: 17 | # TODO: Expand. 18 | return 'Yes.' 19 | elif result == False: 20 | # TODO: Expand. 21 | return 'No.' 22 | elif result == []: 23 | # TODO: Expand. 24 | return 'No known entities match the query.' 25 | else: 26 | if len(result) > 1: 27 | described_refs = [DescribeReferent(i, context_drs, short=True) 28 | for i in result] 29 | args = (', '.join(described_refs[:-1]), described_refs[-1]) 30 | result = '%s and %s' % args 31 | else: 32 | result = DescribeReferent(result[0], context_drs) 33 | return result[0].upper() + result[1:] + '.' 34 | 35 | 36 | def DescribeReferent(ref, drs, definite=True, short=False): 37 | if isinstance(ref, drt.drs.NamedReferent): 38 | return ref.Pretty() 39 | else: 40 | nouns = [] 41 | adjectives = [] 42 | owner = None 43 | modifier = None 44 | prepositions = {} 45 | 46 | for cond in drs.conditions: 47 | if (isinstance(cond, drt.drs.PredicateCondition) and 48 | cond.informative and ref in cond.args): 49 | predicate = cond.predicate 50 | args = cond.args 51 | if len(args) == 1: 52 | synset = nltk.corpus.wordnet.synset(predicate) 53 | if '.n.' in predicate: 54 | nouns.append(synset) 55 | elif '.a.' in predicate or '.s.' in predicate: 56 | adjectives.append(synset) 57 | else: 58 | raise UtterancePlanningError('Unknown predicate: %s' % predicate) 59 | elif cond.predicate.startswith('_'): 60 | if cond.predicate == '_possess' and args[1] == ref: 61 | # TODO: Handle multiple owners. 62 | owner = cond.args[0] 63 | elif cond.predicate == '_modify' and args[1] == ref: 64 | # TODO: Handle multiple modifiers. 65 | modifier = cond.args[0] 66 | elif '/' not in predicate and args[0] == ref: 67 | prepositions[predicate] = args[1] 68 | 69 | assert nouns, 'A referent with no noun predicates found!' 70 | 71 | head_noun = max(nouns, key=lambda s: s.max_depth()) 72 | head_noun = head_noun.lemmas[0].name.replace('_', ' ') 73 | if ref.type == drt.drs.PLURAL_TYPE: 74 | head_noun = ext.plural.noun_plural(head_noun) 75 | 76 | description = head_noun 77 | 78 | if modifier: 79 | description = DescribeReferent(modifier, drs, False) + ' ' + description 80 | 81 | # TODO: Select most relevant adjectives. 82 | adjectives = [i.lemmas[0].name.replace('_', ' ') 83 | for i in adjectives][:MAX_ADJECTIVES] 84 | # TODO: Sort adjectives. E.g. "thin green book" not "green thin book". 85 | 86 | description = ' '.join(adjectives + [description]) 87 | 88 | # TODO: Deal with prepositions. 89 | 90 | if definite: 91 | if owner and not short: 92 | owner_description = DescribeReferent(owner, drs) 93 | if owner_description.endswith('s'): 94 | owner_description += "' " 95 | else: 96 | owner_description += "'s " 97 | description = owner_description + description 98 | else: 99 | description = 'the ' + description 100 | 101 | return description 102 | -------------------------------------------------------------------------------- /src/cfg_parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import nltk 3 | 4 | 5 | GRAMMAR = 'grammar.fcfg' 6 | MAX_TREES = 10000 7 | 8 | 9 | _TYPE_FEATURE = nltk.featstruct.Feature('type') 10 | _KNOWN_WORDS = set([ 11 | "'re", "'s", "'t", 'a', 'about', 'above', 'across', 'against', 'all', 'along', 12 | 'alongside', 'am', 'ambassador', 'amid', 'among', 'amongst', 'an', 'and', 13 | 'another', 'any', 'are', 'aren', 'around', 'assuming', 'astride', 'at', 14 | 'athwart', 'been', 'being', 'before', 'behind', 'below', 'beneath', 'beside', 15 | 'between', 'beyond', 'but', 'by', 'capt', 'captain', 'certain', 'cmdr', 16 | 'coach', 'col', 'colonel', 'commander', 'corporal', 'cpl', 'did', 'didn', 17 | 'do', 'doctor', 'does', 'doesn', 'don', 'down', 'dr', 'each', 'every', 'few', 18 | 'for', 'from', 'front', 'gen', 'general', 'given', 'gov', 'governor', 'had', 19 | 'have', 'haven', 'hasn', 'has', 'he', 'her', 'hers', 'herself', 'him', 20 | 'himself', 'his', 'hon', 'honorable', 'i', 'if', 'in', 'inside', 'into', 21 | 'is', 'isn', 'it', 'its', 'itself', 'judge', 'lieutenant', 'little', 'lot', 22 | 'lt', 'maj', 'major', 'many', 'master', 'me', 'mine', 'miss', 'mister', 23 | 'more', 'most', 'mr', 'mrs', 'ms', 'much', 'my', 'myself', 'near', 'next', 24 | 'no', 'none', 'not', 'of', 'ofc', 'off', 'officer', 'on', 'one', 'oneself', 25 | 'onto', 'opposite', 'or', 'our', 'ours', 'ourself', 'out', 'outside', 'over', 26 | 'past', 'pres', 'president', 'private', 'prof', 'professor', 'pvt', 'rep', 27 | 'representative', 'rev', 'reverend', 'round', 'sargent', 'sec', 'secretary', 28 | 'sen', 'senator', 'several', 'sgt', 'she', 'sir', 'some', 'than', 'that', 29 | 'the', 'their', 'them', 'themselves', 'then', 'these', 'they', 'this', 30 | 'those', 'through', 'throughout', 'to', 'towards', 'under', 'underneath', 31 | 'up', 'upon', 'us', 'was', 'wasn', 'we', 'were', 'weren', 'what', 'which', 32 | 'when', 'whenever', 'where', 'who', 'whom', 'within', 'you', 'your', 'yours', 33 | 'yourself' 34 | ]) 35 | 36 | _parser = None 37 | 38 | 39 | class ParserError(Exception): pass 40 | 41 | 42 | def ReloadGrammar(path=GRAMMAR, **kwds): 43 | global _parser 44 | nltk.data._resource_cache = {} 45 | _parser = nltk.load_parser('file:' + os.path.abspath(path), **kwds) 46 | 47 | 48 | def Parse(tokens, max_trees=MAX_TREES): 49 | if _parser is None: ReloadGrammar() 50 | trees = _parser.nbest_parse(tokens, max_trees) 51 | if trees: 52 | return trees 53 | else: 54 | raise ParserError('No parse trees found for sentence: %s' % tokens) 55 | 56 | 57 | def SelectTree(trees): 58 | return max(trees, key=GradeTree) 59 | 60 | 61 | def GradeTree(tree): 62 | if isinstance(tree, basestring): 63 | return 0 64 | else: 65 | score = 0 66 | 67 | # Prefer Ss and VPs that directly contain prepositions. For matching 68 | # phrasal verbs like "switch _ on" and objects like "give _ to _". 69 | if tree.node[_TYPE_FEATURE] in ('S', 'VP'): 70 | score = (sum(2000 for i in tree if isinstance(i, basestring)) + 71 | sum(1000 for i in tree 72 | if hasattr(i, 'node') and i.node[_TYPE_FEATURE] == 'Prep')) 73 | 74 | # Terminals used in the manual rules take precendence. 75 | if (len(tree) == 1 and 76 | isinstance(tree[0], basestring) and 77 | tree[0] in _KNOWN_WORDS and 78 | tree.node[_TYPE_FEATURE] in ('Noun', 'Adj', 'Verb')): 79 | score -= 500 80 | 81 | # Ambiguous names are less likely to come as proper nouns. 82 | # Nouns that have been observed by the wordnet frequency counter are better. 83 | if 'FRQ' in tree.node: 84 | score += tree.node['FRQ'] 85 | 86 | return sum(GradeTree(i) for i in tree) + score 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crystal 2 | 3 | ## Overview 4 | 5 | Crystal is a natural language question answering program. It converts natural 6 | text into a semantic representation based on Discourse Representation Theory 7 | and performs inferences on the result. Its features include anaphora and 8 | presupposition resolution, semantic reasoning through the use of WordNet and 9 | VerbNet databases and logical inference. The application currently covers only 10 | a small subset of English, but it is sufficiently interesting to mess around. 11 | 12 | Crystal is not a chatbot - it will accept only 100% grammatical sentences and 13 | will reject anything that can not be completely understood or conflicts with 14 | information provided previously. 15 | 16 | For examples sessions, see . 17 | 18 | For documentation, see the downloads section. 19 | 20 | ## Getting Started 21 | 22 | 1. Checkout the Crystal code or unpack a source package. 23 | 24 | 2. Install Python 2.7. 25 | 26 | 3. Install NLTK (from a repository or from ). 27 | 28 | 4. Install the following NLTK corpora: 29 | * wordnet 30 | * verbnet 31 | * names 32 | * cmudict 33 | 34 | You can do this by running "import nltk; nltk.download()" in a Python REPL. 35 | This will display a GUI to select the corpora to download. Take note of the 36 | folder where the corpora are downloaded. 37 | 38 | 5. If the VerbNet corpus in the NLTK repository is still version 2.1 (as it is 39 | at the time of writing), you will need to manually update it to version 3.1. 40 | Download it from , 41 | unpack and place in the corpora folder specified in step 4. 42 | 43 | 6. Either unpack the optimized grammar by running `tar -xf grammar.tar.gz` in 44 | the src folder or run `./__main__.py --grammar` to rebuild an unoptimized 45 | grammar from scratch. 46 | 47 | 7. Run `./__main__.py`. 48 | 49 | 8. Take a good long walk while the grammar is being loaded. 50 | 51 | 9. Use. 52 | 53 | Note that compiled binaries for Mace4 and Prover9 for Windows and 32-bit Unix 54 | are already included. If you want to build your own copies, download the LADR 55 | source from , apply 56 | `src/prover/cnf.c.patch` to `ladr/cnf.c` and run `make all` in the LADR root. 57 | 58 | ## Grammar 59 | 60 | The repository includes a hand-optimized grammar file in `grammar.tar.gz`. This 61 | file is based on the result of the grammar building pipeline in the build 62 | folder. Some optimizations were added manually but the details of what happened 63 | that night have been lost. 64 | 65 | To rebuild the default unoptimized grammar, run `./__main__.py --grammar`. Be 66 | careful, however, as that this will overwrite the current optimized grammar. 67 | 68 | ## Usage 69 | 70 | The workflow is pretty simple. The user can tell Crystal facts in the form of 71 | declarative sentences, including conditionals and compound statements, and it 72 | will incrementally build up a context and check every new statement against it, 73 | resolving anaphora (pronouns) and presuppositions (definite NPs). At any point 74 | in the interaction, the user can ask Crystal subject or object questions which 75 | will be answered (if possible) based on the context. 76 | 77 | ## Code 78 | 79 | The program is written in Python 2 and uses the NLTK chart parser with a 80 | VerbNet-based unification grammar for parsing, DRT techniques for converting 81 | parse trees into semantic representations, a vocabulary derived from WordNet and 82 | VerbNet semantic limitations for word senses, and finally an inference system 83 | powered by the Prover9/Mace4 theorem prover and model builder. 84 | 85 | Crystal was written by someone who had never touched NLP before in about 2 86 | months of part-time work, so the code is riddled with algorithms, techniques and 87 | design decisions that will cause many a facepalm to most linguists, NLP 88 | practitioners and even software engineers, for which I apologize in advance. 89 | 90 | I do not plan to continue the development of the project, but I have received 91 | several requests to put the code on GitHub, so I figured it can't hurt. 92 | 93 | ## Performance 94 | 95 | The performance of the program is pretty abysmal, taking about a second or two 96 | per sentence for simple sentences on a midrange PC, 5-10 seconds for complex or 97 | highly ambiguous sentences and up to several minutes in degenerate cases. The 98 | bottlenecks are mostly fixable, but since the system was never meant to be more 99 | than a proof of concept, I do not plan to ever fix them properly. Memory usage 100 | is similarly ugly, at about 800MB on 32-bit systems when the full WordNet 101 | vocabulary is loaded. 102 | 103 | ## License 104 | 105 | This project is licensed under the GNU GPL. 106 | -------------------------------------------------------------------------------- /brainstorming/verb_rules.txt: -------------------------------------------------------------------------------- 1 | Verb[FORM=(inf, tps, pret, pp, ger),PTRN=...,ROOT=...] -> terminal 2 | 3 | # Present (to be) 4 | CV[SEM=pos,TENS=r,PERS=1,NUM=sg,PTRN=0,ROOT=be] -> "am" 5 | CV[SEM=pos,TENS=r,PERS=1,NUM=ms,PTRN=0,ROOT=be] -> "am" 6 | CV[SEM=neg,TENS=r,PERS=1,NUM=sg,PTRN=0,ROOT=be] -> "am" "not" 7 | CV[SEM=neg,TENS=r,PERS=1,NUM=ms,PTRN=0,ROOT=be] -> "am" "not" 8 | CV[SEM=pos,TENS=r,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "is" 9 | CV[SEM=pos,TENS=r,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "is" 10 | CV[SEM=neg,TENS=r,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "is" "not" 11 | CV[SEM=neg,TENS=r,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "is" "not" 12 | CV[SEM=neg,TENS=r,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "isn" "'t" 13 | CV[SEM=neg,TENS=r,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "isn" "'t" 14 | CV[SEM=pos,TENS=r,NUM=pl,PTRN=0,ROOT=be] -> "are" 15 | CV[SEM=neg,TENS=r,NUM=pl,PTRN=0,ROOT=be] -> "are" "not" 16 | CV[SEM=neg,TENS=r,NUM=pl,PTRN=0,ROOT=be] -> "aren" "'t" 17 | 18 | # Past (to be) 19 | CV[SEM=pos,TENS=p,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "was" 20 | CV[SEM=pos,TENS=p,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "was" 21 | CV[SEM=neg,TENS=p,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "was" "not" 22 | CV[SEM=neg,TENS=p,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "was" "not" 23 | CV[SEM=neg,TENS=p,PERS=3,NUM=sg,PTRN=0,ROOT=be] -> "wasn" "'t" 24 | CV[SEM=neg,TENS=p,PERS=3,NUM=ms,PTRN=0,ROOT=be] -> "wasn" "'t" 25 | CV[SEM=pos,TENS=p,NUM=pl,PTRN=0,ROOT=be] -> "were" 26 | CV[SEM=neg,TENS=p,NUM=pl,PTRN=0,ROOT=be] -> "were" "not" 27 | CV[SEM=neg,TENS=p,NUM=pl,PTRN=0,ROOT=be] -> "weren" "'t" 28 | 29 | # Present 30 | CV[SEM=pos,TENS=r,PTRN=?t,ROOT=?r] -> Verb[FORM=inf,PTRN=?t,ROOT=?r] 31 | CV[SEM=pos,TENS=r,PERS=3,NUM=sg,PTRN=?t,ROOT=?r] -> Verb[FORM=tps,PTRN=?t,ROOT=?r] 32 | CV[SEM=pos,TENS=r,PERS=3,NUM=ms,PTRN=?t,ROOT=?r] -> Verb[FORM=tps,PTRN=?t,ROOT=?r] 33 | CV[SEM=neg,TENS=r,PTRN=?t] -> "do" "not" Verb[FORM=inf,PTRN=?t,ROOT=?r] 34 | CV[SEM=neg,TENS=r,PTRN=?t] -> "don" "'t" Verb[FORM=inf,PTRN=?t,ROOT=?r] 35 | CV[SEM=pos,TENS=r,PERS=3,NUM=sg,PTRN=?t,ROOT=?r] -> "does" "not" Verb[FORM=inf,PTRN=?t,ROOT=?r] 36 | CV[SEM=pos,TENS=r,PERS=3,NUM=ms,PTRN=?t,ROOT=?r] -> "does" "not" Verb[FORM=inf,PTRN=?t,ROOT=?r] 37 | CV[SEM=pos,TENS=r,PERS=3,NUM=sg,PTRN=?t,ROOT=?r] -> "doesn" "'t" Verb[FORM=inf,PTRN=?t,ROOT=?r] 38 | CV[SEM=pos,TENS=r,PERS=3,NUM=ms,PTRN=?t,ROOT=?r] -> "doesn" "'t" Verb[FORM=inf,PTRN=?t,ROOT=?r] 39 | 40 | # Present Continuous 41 | CV[SEM=?s,TENS=rc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=r,PERS=?p,NUM=?n,ROOT=be] Verb[FORM=ger,PTRN=?t,ROOT=?r] 42 | 43 | # Present Perfect 44 | CV[SEM=?s,TENS=rp,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=r,PERS=?p,NUM=?n,ROOT=have] Verb[FORM=pp,PTRN=?t,ROOT=?r] 45 | 46 | # Present Perfect Continuous 47 | CV[SEM=?s,TENS=rpc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=r,PERS=?p,NUM=?n,ROOT=have] "been" Verb[FORM=ger,PTRN=?t,ROOT=?r] 48 | 49 | # Past 50 | CV[SEM=pos,TENS=p,PTRN=?t,ROOT=?r] -> Verb[FORM=pret,PTRN=?t,ROOT=?r] 51 | CV[SEM=neg,TENS=p,PTRN=?t,ROOT=?r] -> "did" "not" Verb[FORM=inf,PTRN=?t,ROOT=?r] 52 | CV[SEM=neg,TENS=p,PTRN=?t,ROOT=?r] -> "did" "'t" Verb[FORM=inf,PTRN=?t,ROOT=?r] 53 | 54 | # Past Continuous 55 | CV[SEM=?s,TENS=pc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=p,PERS=?p,NUM=?n,ROOT=be] Verb[FORM=ger,PTRN=?t,ROOT=?r] 56 | 57 | # Past Perfect 58 | CV[SEM=?s,TENS=pc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=p,PERS=?p,NUM=?n,ROOT=have] Verb[FORM=pp,PTRN=?t,ROOT=?r] 59 | 60 | # Past Perfect Continuous 61 | CV[SEM=?s,TENS=pc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> CV[SEM=?s,TENS=p,PERS=?p,NUM=?n,ROOT=have] "been" Verb[FORM=ger,PTRN=?t,ROOT=?r] 62 | 63 | # Future 64 | CV[SEM=pos,TENS=f,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" Verb[FORM=inf,PTRN=?t,ROOT=?r] 65 | CV[SEM=neg,TENS=f,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "not" Verb[FORM=inf,PTRN=?t,ROOT=?r] 66 | CV[SEM=neg,TENS=f,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "won't" Verb[FORM=inf,PTRN=?t,ROOT=?r] 67 | 68 | # Future Continuous 69 | CV[SEM=pos,TENS=fc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "be" Verb[FORM=ger,PTRN=?t,ROOT=?r] 70 | CV[SEM=neg,TENS=fc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "not" "be" Verb[FORM=ger,PTRN=?t,ROOT=?r] 71 | CV[SEM=neg,TENS=fc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "won't" "be" Verb[FORM=ger,PTRN=?t,ROOT=?r] 72 | 73 | # Future Perfect 74 | CV[SEM=pos,TENS=fp,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "have" Verb[FORM=pp,PTRN=?t,ROOT=?r] 75 | CV[SEM=neg,TENS=fp,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "not" "have" Verb[FORM=pp,PTRN=?t,ROOT=?r] 76 | CV[SEM=neg,TENS=fp,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "won't" "have" Verb[FORM=pp,PTRN=?t,ROOT=?r] 77 | 78 | # Future Perfect Continuous 79 | CV[SEM=pos,TENS=fpc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "have" "been" Verb[FORM=ger,PTRN=?t,ROOT=?r] 80 | CV[SEM=neg,TENS=fpc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "will" "not" "have" "been" Verb[FORM=ger,PTRN=?t,ROOT=?r] 81 | CV[SEM=neg,TENS=fpc,PERS=?p,NUM=?n,PTRN=?t,ROOT=?r] -> "won't" "have" "been" Verb[FORM=ger,PTRN=?t,ROOT=?r] 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/data/conjunctions.pickle: -------------------------------------------------------------------------------- 1 | (lp1 2 | (S'after' 3 | p2 4 | I01 5 | I01 6 | I00 7 | I00 8 | I00 9 | I00 10 | I00 11 | I00 12 | I00 13 | S'*a&b' 14 | p3 15 | I00 16 | tp4 17 | a(S'although' 18 | I01 19 | I00 20 | I00 21 | I00 22 | I00 23 | I00 24 | I00 25 | I00 26 | I00 27 | S'a&b' 28 | p5 29 | I00 30 | tp6 31 | a(S'and also' 32 | I01 33 | I01 34 | I00 35 | I01 36 | I01 37 | I00 38 | I01 39 | I01 40 | I01 41 | g5 42 | I00 43 | tp7 44 | a(S'and' 45 | p8 46 | I01 47 | I01 48 | I01 49 | I01 50 | I01 51 | I01 52 | I01 53 | I01 54 | I01 55 | g5 56 | I01 57 | tp9 58 | a(S'as' 59 | p10 60 | I01 61 | I00 62 | I00 63 | I00 64 | I00 65 | I00 66 | I00 67 | I00 68 | I00 69 | g5 70 | I00 71 | tp11 72 | a(S'as if' 73 | I01 74 | I00 75 | I00 76 | I00 77 | I00 78 | I00 79 | I00 80 | I00 81 | I00 82 | S'a&-b' 83 | p12 84 | I00 85 | tp13 86 | a(S'as though' 87 | I01 88 | I00 89 | I00 90 | I00 91 | I00 92 | I00 93 | I00 94 | I00 95 | I00 96 | g12 97 | I00 98 | tp14 99 | a(S'because' 100 | I01 101 | I00 102 | I00 103 | I00 104 | I00 105 | I00 106 | I00 107 | I00 108 | I00 109 | S'*cause' 110 | p15 111 | I00 112 | tp16 113 | a(S'before' 114 | I01 115 | I01 116 | I00 117 | I00 118 | I00 119 | I00 120 | I00 121 | I00 122 | I00 123 | g3 124 | I00 125 | tp17 126 | a(S'both ... and' 127 | I00 128 | I01 129 | I01 130 | I01 131 | I01 132 | I01 133 | I01 134 | I01 135 | I01 136 | g5 137 | I00 138 | tp18 139 | a(S'but' 140 | I01 141 | I00 142 | I00 143 | I01 144 | I01 145 | I00 146 | I00 147 | I00 148 | I01 149 | g5 150 | I01 151 | tp19 152 | a(S'either ... or' 153 | I01 154 | I01 155 | I01 156 | I01 157 | I01 158 | I01 159 | I01 160 | I00 161 | I00 162 | S'a|b' 163 | p20 164 | I00 165 | tp21 166 | a(S'even if' 167 | I01 168 | I00 169 | I00 170 | I00 171 | I00 172 | I00 173 | I00 174 | I00 175 | I01 176 | S'a' 177 | I00 178 | tp22 179 | a(S'for' 180 | p23 181 | I01 182 | I00 183 | I00 184 | I00 185 | I00 186 | I00 187 | I00 188 | I00 189 | I00 190 | g15 191 | I00 192 | tp24 193 | a(S'if' 194 | p25 195 | I00 196 | I00 197 | I00 198 | I00 199 | I01 200 | I00 201 | I00 202 | I00 203 | I00 204 | g5 205 | I00 206 | tp26 207 | a(S'in case' 208 | I01 209 | I00 210 | I00 211 | I00 212 | I00 213 | I00 214 | I00 215 | I00 216 | I00 217 | g15 218 | I00 219 | tp27 220 | a(S'in case that' 221 | I01 222 | I00 223 | I00 224 | I00 225 | I00 226 | I00 227 | I00 228 | I00 229 | I00 230 | g15 231 | I00 232 | tp28 233 | a(S'in order that' 234 | I01 235 | I00 236 | I00 237 | I00 238 | I00 239 | I00 240 | I00 241 | I00 242 | I00 243 | g15 244 | I00 245 | tp29 246 | a(S'lest' 247 | I00 248 | I00 249 | I00 250 | I00 251 | I00 252 | I00 253 | I00 254 | I00 255 | I00 256 | g15 257 | I00 258 | tp30 259 | a(S'neither ... nor' 260 | I00 261 | I01 262 | I01 263 | I01 264 | I01 265 | I01 266 | I01 267 | I01 268 | I01 269 | S'!(a|b)' 270 | I00 271 | tp31 272 | a(S'not only ... but also' 273 | I00 274 | I01 275 | I01 276 | I01 277 | I01 278 | I01 279 | I01 280 | I01 281 | I01 282 | g5 283 | I00 284 | tp32 285 | a(S'only' 286 | I01 287 | I00 288 | I00 289 | I00 290 | I00 291 | I00 292 | I00 293 | I00 294 | I00 295 | g5 296 | I00 297 | tp33 298 | a(S'or' 299 | p34 300 | I01 301 | I01 302 | I01 303 | I01 304 | I01 305 | I01 306 | I01 307 | I01 308 | I01 309 | g20 310 | I01 311 | tp35 312 | a(S'or else' 313 | I01 314 | I00 315 | I00 316 | I00 317 | I00 318 | I00 319 | I01 320 | I00 321 | I00 322 | S'(-a)->b' 323 | I00 324 | tp36 325 | a(S'scarcely ... when' 326 | I00 327 | I00 328 | I00 329 | I00 330 | I00 331 | I00 332 | I00 333 | I00 334 | I00 335 | g3 336 | I00 337 | tp37 338 | a(S'so' 339 | I01 340 | I00 341 | I00 342 | I00 343 | I00 344 | I00 345 | I00 346 | I00 347 | I00 348 | g5 349 | I00 350 | tp38 351 | a(S'so as to' 352 | I00 353 | I00 354 | I00 355 | I00 356 | I00 357 | I00 358 | I00 359 | I00 360 | I00 361 | g15 362 | I00 363 | tp39 364 | a(S'so that' 365 | I00 366 | I00 367 | I00 368 | I00 369 | I00 370 | I00 371 | I00 372 | I00 373 | I00 374 | g15 375 | I00 376 | tp40 377 | a(S'though' 378 | I01 379 | I00 380 | I00 381 | I00 382 | I00 383 | I00 384 | I00 385 | I00 386 | I00 387 | g5 388 | I00 389 | tp41 390 | a(S'till' 391 | I01 392 | I00 393 | I00 394 | I00 395 | I00 396 | I00 397 | I00 398 | I00 399 | I00 400 | g3 401 | I00 402 | tp42 403 | a(S'unless' 404 | I01 405 | I00 406 | I00 407 | I00 408 | I00 409 | I00 410 | I00 411 | I00 412 | I00 413 | S'(-b)->a' 414 | I00 415 | tp43 416 | a(S'until' 417 | I01 418 | I00 419 | I00 420 | I00 421 | I00 422 | I00 423 | I00 424 | I00 425 | I00 426 | g3 427 | I00 428 | tp44 429 | a(S'whereas' 430 | I01 431 | I00 432 | I00 433 | I00 434 | I00 435 | I00 436 | I00 437 | I00 438 | I00 439 | g5 440 | I00 441 | tp45 442 | a(S'whether or not' 443 | I01 444 | I00 445 | I00 446 | I00 447 | I00 448 | I00 449 | I00 450 | I00 451 | I00 452 | S'a' 453 | I00 454 | tp46 455 | a(S'while' 456 | p47 457 | I01 458 | I00 459 | I00 460 | I00 461 | I00 462 | I00 463 | I00 464 | I00 465 | I00 466 | g3 467 | I00 468 | tp48 469 | a(S'yet' 470 | I01 471 | I00 472 | I00 473 | I01 474 | I01 475 | I00 476 | I00 477 | I00 478 | I01 479 | g5 480 | I00 481 | tp49 482 | a. -------------------------------------------------------------------------------- /src/engine.py: -------------------------------------------------------------------------------- 1 | import nltk 2 | import cfg_parser 3 | import drt.drs 4 | import drt.rules 5 | import drt.resolve 6 | import logic 7 | import tokenizer 8 | import utterance 9 | 10 | 11 | CONDITION_TRIGGERS = set(['if', 'when', 'whenever', 'given', 'as', 'assuming', 12 | 'provided', 'proposing', 'since', 'supposing']) 13 | 14 | 15 | def GetInformativeCopy(drs): 16 | copy = drs.Copy() 17 | for d in copy.Walk(): 18 | d._conditions = [i for i in d._conditions if i.informative] 19 | return copy 20 | 21 | 22 | def AnswerQuestion(question_drs, context_drs): 23 | result = None 24 | if isinstance(question_drs, drt.drs.BooleanQuestionDRS): 25 | informative_question_drs = GetInformativeCopy(question_drs) 26 | positive = logic.IsProvable(context_drs, informative_question_drs) 27 | inverse_drs = drt.drs.DRS([], [drt.drs.NegationCondition(question_drs)]) 28 | negative = logic.IsProvable(context_drs, inverse_drs) 29 | if positive and negative: 30 | raise Exception('This is madness!') 31 | elif positive: 32 | result = True 33 | elif negative: 34 | result = False 35 | else: 36 | answers = [] 37 | target = question_drs.target 38 | for possible in context_drs.referents: 39 | cond = drt.drs.EqualityCondition(target, possible) 40 | question_drs.AddCondition(cond) 41 | informative_question_drs = GetInformativeCopy(question_drs) 42 | if logic.IsProvable(context_drs, informative_question_drs): 43 | answers.append(possible) 44 | question_drs.RemoveCondition(cond) 45 | result = answers 46 | 47 | return result 48 | 49 | 50 | def GetDRSFromTrees(trees, tokens, old_drs): 51 | strict_mode_values = [True] 52 | if CONDITION_TRIGGERS.intersection(tokens): 53 | strict_mode_values.append(False) 54 | 55 | for strict_mode in strict_mode_values: 56 | drt.rules._strict_mode = strict_mode 57 | 58 | for tree in trees: 59 | try: 60 | drs = drt.rules.Evaluate(tree) 61 | except drt.rules.EvaluatorError: 62 | continue 63 | 64 | is_question = isinstance(drs, drt.drs.QuestionDRS) 65 | try: 66 | drs = drt.resolve.Resolve(drs, old_drs, is_question) 67 | except drt.resolve.ConsistencyError: 68 | continue 69 | 70 | if logic.IsConsistent(drs): 71 | yield tree, drs 72 | 73 | 74 | def ProcessString(input, context_drs, queue): 75 | queue.put(('post', input, 'input')) 76 | 77 | # Get trees. 78 | try: 79 | tokens = tokenizer.Tokenize(input) 80 | except: 81 | queue.put(('post', 'Could not tokenize the input.', 'problem')) 82 | return 83 | 84 | try: 85 | trees = cfg_parser.Parse(tokens) 86 | except: 87 | trees = [] 88 | 89 | trees_count = len(trees) 90 | if trees_count == 0: 91 | message = 'Could not find any parse trees for the input.' 92 | queue.put(('post', message, 'problem')) 93 | return 94 | if trees_count == cfg_parser.MAX_TREES: 95 | trees_count = '%d+' % trees_count 96 | queue.put(('post', 'Found %s parse trees.' % trees_count, 'comment')) 97 | 98 | # Order trees. 99 | trees.sort(key=cfg_parser.GradeTree, reverse=True) 100 | 101 | # Evaluate trees and find the best valid tree. 102 | if not context_drs: 103 | context_drs = drt.drs.DRS() 104 | best_tree = None 105 | state = None 106 | interpretations = 0 107 | for tree, drs in GetDRSFromTrees(trees, tokens, context_drs): 108 | interpretations += 1 109 | if isinstance(drs, drt.drs.QuestionDRS): 110 | result = AnswerQuestion(drs, context_drs) 111 | 112 | if result not in (None, []): 113 | best_tree = tree 114 | state = 'question' 115 | break 116 | elif not best_tree: 117 | state = 'question' 118 | best_tree = tree 119 | else: 120 | best_tree = tree 121 | result = drs 122 | state = 'statement' 123 | break 124 | 125 | # Post results. 126 | if interpretations == 1: 127 | message = 'Evaluated 1 interpretation.' 128 | else: 129 | message = 'Evaluated %d interpretations.' % interpretations 130 | queue.put(('post', message, 'comment')) 131 | 132 | if not best_tree: 133 | best_tree = trees[0] 134 | #queue.put(('post', str(best_tree), 'comment')) 135 | queue.put(('post', GetTerminalDefinitions(best_tree), 'comment')) 136 | 137 | if state == 'question': 138 | result = utterance.DescribeResult(result, drs, context_drs) 139 | queue.put(('post', result, 'result')) 140 | elif state == 'statement': 141 | queue.put(('post', 'Statement understood and added to context.', 'result')) 142 | queue.put(('update_context', result, None)) 143 | else: 144 | message = 'Could not find any consistent interpretation of the input.' 145 | queue.put(('post', message, 'problem')) 146 | 147 | 148 | def GetTerminalDefinitions(tree): 149 | stack = [tree] 150 | buffer = ['Inferred word senses:'] 151 | while stack: 152 | subtree = stack.pop() 153 | if isinstance(subtree, basestring): 154 | continue 155 | stack += list(reversed(subtree)) 156 | if ('SNS' in subtree.node and 157 | all(isinstance(i, basestring) for i in subtree)): 158 | definition = nltk.corpus.wordnet.synset(subtree.node['SNS']).definition 159 | buffer.append(' %s: %s.' % (' '.join(subtree), definition)) 160 | 161 | return '\n'.join(buffer) 162 | 163 | -------------------------------------------------------------------------------- /brainstorming/lambdas.txt: -------------------------------------------------------------------------------- 1 | d: DRT 2 | x: entity referent (lowercase for singular, uppercase for plural/mass). 3 | v: verb referent 4 | s: string 5 | [?]: list of elements of type ? 6 | ?x, ?y, ...: type variable 7 | 8 | S :: d 9 | VP :: [(x -> d) -> d] -> (x -> d) 10 | NP :: (x -> d) -> d 11 | Verb :: v 12 | CV :: v 13 | PP :: x -> d 14 | PN :: (x -> d) -> d 15 | Ttl :: s 16 | PrpN :: s 17 | DT :: ((x -> d), (x -> d)) -> d 18 | AJP :: x -> d 19 | Adj :: x -> d 20 | Noun :: x -> d 21 | Prep :: s 22 | Cnj :: ?x, ?x -> ?x 23 | Cond :: - 24 | Art :: ((x -> d), (x -> d)) -> d 25 | Pro :: (x -> d) -> d 26 | 27 | 28 | --------------- 29 | 30 | 31 | ((a cat) and (a dog)) (eat and drink) 32 | 33 | a: P,Q -> [y|] + P(y) + Q(y) 34 | cat: x -> [|cat(x)] 35 | and: A,B -> (Q -> Q(A) + Q(B)) 36 | a: P,Q -> [z|] + P(z) + Q(z) 37 | dog: x -> [|dog(x)] 38 | eat: x -> [|eat(x)] 39 | and: A,B -> (Q -> Q(A) + Q(B)) 40 | drink: x -> [|drink(x)] 41 | 42 | a cat: Q -> [y|] + [|cat(y)] + Q(y) 43 | a dog: Q -> [z|] + [|dog(z)] + Q(z) 44 | a cat and a dog: Q -> [y|] + [|cat(y)] + Q(y) + [z|] + [|dog(z)] + Q(z) 45 | eat and drink: x-> [|eat(x)] + [|drink(x)] 46 | a cat and a dog eat and drink: [y,z|cat(y), eat(y), drink(y), dog(z), eat(z), drink(z)] 47 | 48 | 49 | --------------- 50 | 51 | 52 | ((a cat) and (a dog)) (eat and drink) 53 | 54 | a: P,Q -> [y|] + P(y) + Q(y) 55 | cat: x -> [|cat(x)] 56 | and: A,B -> (Q -> Q(A) + Q(B)) 57 | a: P,Q -> [z|] + P(z) + Q(z) 58 | dog: x -> [|dog(x)] 59 | eat: x -> [v|eat(v), Agent(v, x), animate(x)] 60 | and: A,B -> (Q -> Q(A) + Q(B)) 61 | drink: x -> [w|drink(w), Agent(w, x), animate(x)] 62 | 63 | a cat: Q -> [y|] + [|cat(y)] + Q(y) 64 | a dog: Q -> [z|] + [|dog(z)] + Q(z) 65 | a cat and a dog: Q -> [y|] + [|cat(y)] + Q(y) + [z|] + [|dog(z)] + Q(z) 66 | eat and drink: x -> [v|eat(v), Agent(v, x), animate(x)] + [w|drink(w), Agent(w, x), animate(x)] 67 | a cat and a dog eat and drink: [y,v,w,z,v2,w2|cat(y), eat(v), Agent(v, y), animate(y), drink(w), Agent(w, y), animate(y), dog(z), eat(v2), Agent(v2, z), animate(z), drink(w), Agent(w2, z), animate(z)] 68 | 69 | .------------------. 70 | |y, z, v, w, v2, w2| 71 | |------------------| 72 | |animate(y) | 73 | |cat(y) | 74 | | | 75 | |eat(v) | 76 | |Agent(v, y) | 77 | | | 78 | |drink(w) | 79 | |Agent(w, y) | 80 | | | 81 | | | 82 | |animate(z) | 83 | |dog(z) | 84 | | | 85 | |eat(v2) | 86 | |Agent(v2, z) | 87 | | | 88 | |drink(w2) | 89 | |Agent(w2, z) | 90 | '------------------' 91 | 92 | 93 | --------------- 94 | 95 | 96 | Jack eats an apple: [x1,x2,v|eat(v), _agent(v, x1), animate(x1), _patient(v, x2), comestible(x2), solid(x2)] 97 | 98 | [v|eat(v)] + 99 | NP_agent(x->[_agent(v, x), animate(x)]) + 100 | NP_patient(x->[_patient(v, x), comestible(x), solid(x)]) 101 | 102 | 103 | --------------- 104 | 105 | 106 | no dog drinks 107 | 108 | no: P,Q -> [|([y|] + P(y)) -> [ | not(Q(y))] 109 | dog: x -> [|dog(x)] 110 | drinks: x -> [|drink(x)] 111 | 112 | no dog: Q -> [|not([y|] + [|dog(y)] + Q(y))] 113 | no dog drinks: [ | not([y | dog(y), drink(y))] 114 | 115 | 116 | --------------- 117 | 118 | 119 | the dog drinks 120 | 121 | the: P,Q -> <<[y|] + P(y)>> Q(y) 122 | dog: x -> [|dog(x)] 123 | drinks: x -> [|drink(x)] 124 | 125 | the dog: Q -> <<[y|] + [|dog(y)]>> Q(y) 126 | the dog drinks: <<[y|dog(y)]>> drink(y) 127 | 128 | 129 | --------------- 130 | 131 | 132 | no dog eats a cat 133 | 134 | no: P,Q -> [|([y|] + P(y)) -> [ | not(Q(y))] 135 | dog: x -> [|dog(x)] 136 | eats: x,P -> [w|eat(w), Agent(w, x), animate(x)] + P(?) 137 | y -> [w|eat(w), Patient(w, y), comestible(y)] 138 | a: P,Q -> [y|] + P(y) + Q(y) 139 | cat: x -> [|cat(x)] 140 | 141 | no dog: Q -> [|[x|dog(x)] -> [ | not(Q(x))] 142 | a cat: Q -> [y|cat(y)] + Q(y) 143 | eats a cat: x -> [w,y|Agent(w, x), animate(x), cat(y), Patient(w, y), comestible(y)] 144 | no dog eats a cat: [|[x|dog(x)] -> [ | not([w,y|Agent(w, x), animate(x), cat(y), Patient(w, y), comestible(y)])] 145 | 146 | 147 | --------------- 148 | 149 | 150 | the dog is drunk 151 | 152 | the: P,Q -> <<[y|] + P(y)>> Q(y) 153 | dog: x -> [|dog(x)] 154 | is: - 155 | drunk: x -> [|drunk(x)] 156 | 157 | the dog: Q -> <<[y|] + [|dog(y)]>> Q(y) 158 | the dog is drunk: <<[y|] + [|dog(y)]>> [|drunk(y)] 159 | 160 | 161 | --------------- 162 | 163 | 164 | the dog is a common animal 165 | 166 | the: P,Q -> <<[y|] + P(y)>> Q(y) 167 | dog: x -> [|dog(x)] 168 | is: - 169 | a: P,Q -> [y|] + P(y) + Q(y) 170 | common: x -> [|common(x)] 171 | animal: x -> [|animal(x)] 172 | 173 | the dog: Q -> <<[x|dog(x)]>> Q(x) 174 | a common animal: Q -> [y|common(y), animal(y)] + Q(y) 175 | the dog is a common animal: <<[x|dog(x)]>> [y|common(y), animal(y), x=y] 176 | 177 | 178 | --------------- 179 | 180 | 181 | a cat in the yard is hungry 182 | 183 | a: P,Q -> [y|] + P(y) + Q(y) 184 | cat: x -> [|cat(x)] 185 | in: - 186 | the: P,Q -> <<[y|] + P(y)>> Q(y) 187 | yard: x -> [|yard(x)] 188 | is: - 189 | hungry: x -> [|hungry(x)] 190 | 191 | a cat: P -> [y|cat(y)] + P(y) 192 | the yard: Q -> <<[x|yard(x)]>> Q(x) 193 | in the yard: y -> <<[x|yard(x)]>> [in(y,x)] 194 | a cat in the yard: P -> <<[x|yard(x)]>> [y|cat(y),in(y,x)] + P(y) 195 | a cat in the yard is hungry: P -> <<[x|yard(x)]>> [y|cat(y),in(y,x),hungry(y)] 196 | 197 | 198 | -------------------------------------------------------------------------------- /src/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import Tkinter as tk 4 | import tkFont 5 | import threading 6 | import Queue 7 | import engine 8 | import os 9 | import sys 10 | 11 | 12 | class CrystalApp(tk.Tk): 13 | TITLE = 'Crystal' 14 | WIDTH = 500 15 | HEIGHT = 500 16 | INPUT_COLOR = '#000000' 17 | INPUT_BACKGROUND = '#DDDDDD' 18 | RESULT_COLOR = '#007000' 19 | COMMENT_COLOR = '#555555' 20 | PROBLEM_COLOR = '#700000' 21 | ICON = 'data/crystal.ico' 22 | 23 | def __init__(self, parent=None): 24 | tk.Tk.__init__(self, parent) 25 | 26 | self.title(CrystalApp.TITLE) 27 | self.resizable(True, True) 28 | self.config(background='white') 29 | try: 30 | self.iconbitmap(CrystalApp.ICON) 31 | except: 32 | # Tkinter doesn't support color icons in Unix. Oh well. 33 | pass 34 | self.Position() 35 | 36 | self.prompt = tk.Entry(self) 37 | self.label = tk.Label(self) 38 | self.frame = tk.Frame(self) 39 | self.text = tk.Text(self.frame) 40 | self.scrollbar = tk.Scrollbar(self.frame) 41 | 42 | self.font = tkFont.Font(self.text, size=12, family='Calibri') 43 | 44 | self.ConfigureWidgets() 45 | self.ConfigureLayout() 46 | self.ConfigureTags() 47 | 48 | self.drs = None 49 | self.thread = None 50 | self.queue = Queue.Queue() 51 | 52 | self.after_idle(self.StartLoadingGrammar) 53 | 54 | def Position(self): 55 | screen_width = self.winfo_screenwidth() 56 | screen_height = self.winfo_screenheight() 57 | 58 | x = (screen_width - CrystalApp.WIDTH) / 2 59 | y = (screen_height - CrystalApp.HEIGHT) / 2 60 | 61 | self.geometry('%dx%d+%d+%d' % 62 | (CrystalApp.WIDTH, CrystalApp.HEIGHT, x, y)) 63 | 64 | def ConfigureLayout(self): 65 | self.frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) 66 | self.prompt.pack(side=tk.RIGHT, fill=tk.X, expand=True) 67 | self.label.pack(side=tk.LEFT) 68 | 69 | self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) 70 | self.text.pack(side=tk.TOP, fill=tk.BOTH, expand=True) 71 | 72 | def ConfigureTags(self): 73 | self.text.tag_configure('input', foreground=CrystalApp.INPUT_COLOR, 74 | background=CrystalApp.INPUT_BACKGROUND) 75 | self.text.tag_configure('result', foreground=CrystalApp.RESULT_COLOR) 76 | self.text.tag_configure('comment', foreground=CrystalApp.COMMENT_COLOR) 77 | self.text.tag_configure('problem', foreground=CrystalApp.PROBLEM_COLOR) 78 | self.text.tag_raise('sel') 79 | 80 | def ConfigureWidgets(self): 81 | self.frame.config(borderwidth=0) 82 | self.label.config(font=self.font, background='white', text='>>>') 83 | self.text.config(font=self.font, borderwidth=0, state=tk.DISABLED, 84 | wrap=tk.WORD, selectforeground='white') 85 | self.prompt.config(font=self.font, background='white', borderwidth=0, 86 | disabledbackground='white') 87 | self.prompt.bind('', self.Evaluate) 88 | 89 | self.scrollbar.config(command=self.text.yview) 90 | self.text.config(yscrollcommand=self.scrollbar.set) 91 | 92 | def PostMessage(self, text, type): 93 | assert type in ('input', 'result', 'comment', 'problem', 'divider') 94 | self.text.config(state=tk.NORMAL) 95 | self.text.insert(tk.END, text + '\n', type) 96 | self.text.config(state=tk.DISABLED) 97 | self.text.yview('moveto', 1.0) 98 | 99 | def StartLoadingGrammar(self): 100 | self.StartThread(LoadGrammar, (self.queue,)) 101 | 102 | def Evaluate(self, _): 103 | input = self.prompt.get() 104 | if input == '/reset': 105 | self.prompt.delete(0, tk.END) 106 | self.text.config(state=tk.NORMAL) 107 | self.text.delete(1.0, tk.END) 108 | self.text.config(state=tk.DISABLED) 109 | self.drs = None 110 | else: 111 | self.StartThread(ProcessStringGateway, (input, self.drs, self.queue)) 112 | 113 | def StartThread(self, target, args): 114 | self.thread = threading.Thread(target=target, args=args) 115 | self.thread.start() 116 | 117 | self.prompt.delete(0, tk.END) 118 | self.prompt.config(state=tk.DISABLED) 119 | self.label.config(foreground='gray') 120 | 121 | self.after(50, self.CheckQueue) 122 | 123 | def CheckQueue(self): 124 | while not self.queue.empty(): 125 | command, content, type = self.queue.get_nowait() 126 | if command == 'post': 127 | self.PostMessage(content, type) 128 | elif command == 'update_context': 129 | self.drs = content 130 | else: 131 | self.PostMessage('Got unknown command from child thread.', 'problem') 132 | 133 | if self.thread.isAlive(): 134 | self.after(50, self.CheckQueue) 135 | else: 136 | self.prompt.config(state=tk.NORMAL) 137 | self.label.config(foreground='black') 138 | 139 | 140 | def ProcessStringGateway(input, drs, queue): 141 | try: 142 | engine.ProcessString(input, drs, queue) 143 | except Exception, e: 144 | queue.put(('post', 'Error encountered in child thread.', 'problem')) 145 | raise 146 | 147 | 148 | def LoadGrammar(queue): 149 | if not engine.cfg_parser._parser: 150 | queue.put(('post', 'Loading grammar. This may take a while...', 'comment')) 151 | engine.cfg_parser.ReloadGrammar() 152 | queue.put(('post', 'Grammar loaded.', 'comment')) 153 | 154 | 155 | if __name__ == '__main__': 156 | if sys.argv[-1] == '--grammar': 157 | from build import grammar 158 | print 'Building Grammar' 159 | grammar.BuildGrammar() 160 | else: 161 | app = CrystalApp() 162 | app.mainloop() 163 | -------------------------------------------------------------------------------- /src/build/adjectives.py: -------------------------------------------------------------------------------- 1 | import cPickle as pickle 2 | import nltk.corpus 3 | import verbs 4 | import base 5 | 6 | 7 | QUANTIFIERS = set([ 8 | 'all', 'any', 'both', 'each', 'every', 'few', 'less', 'many', 'most', 9 | 'a lot of', 'some', 'several', 'a few', 'a couple of', 'no' 10 | ]) 11 | INCOMPARABLE_ADJECTIVES = set([ 12 | 'perfect', 'unique', 'fatal', 'universal', 'dead', 'wrong', 'straight', 13 | 'blind', 'final', 'vertical', 'right', 'left', 'such' 14 | ]) 15 | IRREGULAR_ADJECTIVES = { 16 | 'good': ('better', 'best'), 17 | 'well': ('better', 'best'), 18 | 'bad': ('worse', 'worst'), 19 | 'ill': ('worse', 'worst'), 20 | 'evil': ('worse', 'worst'), 21 | 'little': (('less', 'lesser'), 'least'), 22 | 'much': ('more', 'most'), 23 | 'old': (('older', 'elder'), ('oldest', 'eldest')), 24 | 'nigh': ('nigher', 'nighest'), 25 | 'near': ('nearer', 'nearest'), 26 | 'far': (('farther', 'further'), ('farthest', 'furthest')), 27 | 'late': (('later', 'latter'), ('latest', 'last')), 28 | 'hind': ('hinder', ('hindmost', 'hindermost')), 29 | 'upper': ('upper', ('upmost', 'uppermost')), 30 | 'inner': ('inner', ('inmost', 'innermost')), 31 | 'outer': (('outer', 'utter'), ('outmost', 'outermost', 'utmost', 'uttermost')), 32 | 'clever': (('cleverer', 'more clever'), ('cleverest', 'most clever')), 33 | 'gentle': (('gentler', 'more gentle'), ('gentlest', 'most gentle')), 34 | 'friendly': (('friendlier', 'more friendly'), ('friendliest', 'most friendly')), 35 | 'quiet': (('quieter', 'more quiet'), ('quietest', 'most quiet')), 36 | 'simple': (('simpler', 'more simple'), ('simpler', 'most simple')), 37 | 'beat': ('more beat', 'most beat'), 38 | } 39 | CMU_DICTIONARY = nltk.corpus.cmudict.dict() 40 | VOWELS = set('aeiou') 41 | DOUBLEABLE = set('bdgfhkjmlnpsrtvz') 42 | PAST_PARTICIPLES = set( 43 | i[-1] for i in pickle.load(open(verbs.VERBS_LIST)).values()) 44 | 45 | 46 | def WriteRules(outfile): 47 | for synset in nltk.corpus.wordnet.all_synsets(nltk.corpus.wordnet.ADJ): 48 | # Skip quantifiers. 49 | if QUANTIFIERS.intersection(synset.lemma_names): continue 50 | # Skip numbers. 51 | if any(i[0].isdigit() for i in synset.lemma_names): continue 52 | 53 | WriteRule(outfile, synset) 54 | 55 | 56 | def WriteRule(outfile, synset): 57 | for lemma in synset.lemmas: 58 | adjective = lemma.name.replace('_', ' ') 59 | 60 | standard = True 61 | # Check for abbreviations. 62 | if '.' in adjective or adjective.isupper(): standard = False 63 | # Check for incomparable adjective. 64 | if adjective in INCOMPARABLE_ADJECTIVES: standard = False 65 | # Check for proper adjective. 66 | if adjective.title() in ' '.join(synset.examples).split(): standard = False 67 | 68 | # Generate comparative and superlative. 69 | comparatives = superlatives = () 70 | if standard: 71 | if adjective in IRREGULAR_ADJECTIVES: 72 | comparatives, superlatives = IRREGULAR_ADJECTIVES[adjective] 73 | if isinstance(comparatives, basestring): comparatives = [comparatives] 74 | if isinstance(superlatives, basestring): superlatives = [superlatives] 75 | standard = False 76 | else: 77 | conjugated = Conjugate(adjective) 78 | if conjugated: 79 | comparatives, superlatives = [[i] for i in conjugated] 80 | standard = False 81 | 82 | # Write ordinary positive adjective. 83 | WriteAdjective(outfile, 'pos', lemma, adjective, standard) 84 | 85 | # Write comparative and superlative adjectives if any. 86 | for comparative in comparatives: 87 | WriteAdjective(outfile, 'cmp', lemma, comparative) 88 | for superlative in superlatives: 89 | WriteAdjective(outfile, 'sup', lemma, superlative) 90 | 91 | 92 | def WriteAdjective(outfile, degree, lemma, adjective, standard=None): 93 | synset = lemma.synset.name 94 | count = base.GetCompoundCount(lemma) 95 | standard = '+' if standard else '-' 96 | terminals = base.LemmaToTerminals(adjective) 97 | outfile.write('Adj[DEG=%s,SNS="%s",FRQ=%d,%sstd] -> %s\n' % 98 | (degree, synset, count, standard, terminals)) 99 | 100 | 101 | def Conjugate(adjective): 102 | if (' ' in adjective or 103 | '-' in adjective or 104 | "'" in adjective or 105 | adjective in PAST_PARTICIPLES or 106 | adjective.endswith('ed')): 107 | return 108 | else: 109 | syllables = SyllableCount(adjective) 110 | assert syllables > 0, adjective 111 | if syllables == 1: 112 | if adjective.endswith('e'): 113 | comparative = adjective + 'r' 114 | superlative = adjective + 'st' 115 | elif (adjective[-1] in DOUBLEABLE and 116 | adjective[-2] in VOWELS and 117 | (len(adjective) < 3 or adjective[-3] not in VOWELS)): 118 | comparative = adjective + adjective[-1] + 'er' 119 | superlative = adjective + adjective[-1] + 'est' 120 | else: 121 | comparative = adjective + 'er' 122 | superlative = adjective + 'est' 123 | elif syllables == 2: 124 | if adjective.endswith('y') and adjective[-2] not in VOWELS: 125 | comparative = adjective[:-1] + 'ier' 126 | superlative = adjective[:-1] + 'iest' 127 | elif adjective[-2:] in ('er', 'le', 'ow'): 128 | comparative = adjective + 'er' 129 | superlative = adjective + 'est' 130 | else: 131 | return 132 | else: 133 | return 134 | 135 | return comparative, superlative 136 | 137 | 138 | def SyllableCount(word): 139 | assert ' ' not in word, word 140 | if word in CMU_DICTIONARY: 141 | return max(len([phonem for phonem in pronunciation if phonem[-1].isdigit()]) 142 | for pronunciation in CMU_DICTIONARY[word]) 143 | else: 144 | vowels_count = len([c for c in word if c in VOWELS]) 145 | if word.endswith('y') and word[-2] not in VOWELS: 146 | vowels_count += 1 147 | return vowels_count 148 | -------------------------------------------------------------------------------- /src/build/nouns.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import nltk.corpus 3 | import ext.plural 4 | import base 5 | 6 | 7 | IGNORE_UNCOMMON = False 8 | IGNORE_PROPER_MULTIWORD = False 9 | IGNORE_NON_PROPER_MULTIWORD = True 10 | IGNORE_ALL_MULTIWORD = IGNORE_PROPER_MULTIWORD and IGNORE_NON_PROPER_MULTIWORD 11 | 12 | UNCOUNTABLE_SYNSETS = set([ 13 | nltk.corpus.wordnet.synset('substance.n.01'), 14 | nltk.corpus.wordnet.synset('substance.n.04'), 15 | nltk.corpus.wordnet.synset('substance.n.07'), 16 | nltk.corpus.wordnet.synset('data.n.01'), 17 | nltk.corpus.wordnet.synset('information.n.01'), 18 | nltk.corpus.wordnet.synset('system_of_measurement.n.01'), 19 | nltk.corpus.wordnet.synset('feeling.n.01'), 20 | nltk.corpus.wordnet.synset('quality.n.01'), 21 | nltk.corpus.wordnet.synset('event.n.01'), 22 | nltk.corpus.wordnet.synset('state.n.02'), 23 | ]) 24 | AMBIGUOUS_COUNTABILITY_SYNSETS = set([ 25 | nltk.corpus.wordnet.synset('food.n.01'), 26 | nltk.corpus.wordnet.synset('food.n.02'), 27 | nltk.corpus.wordnet.synset('event.n.01'), 28 | nltk.corpus.wordnet.synset('state.n.02'), 29 | ]) 30 | MALE_SYNSETS = set([ 31 | nltk.corpus.wordnet.synset('male.n.02'), 32 | nltk.corpus.wordnet.synset('actor.n.01'), 33 | nltk.corpus.wordnet.synset('husband.n.01'), 34 | nltk.corpus.wordnet.synset('father.n.01'), 35 | nltk.corpus.wordnet.synset('brother.n.01'), 36 | nltk.corpus.wordnet.synset('son.n.01'), 37 | nltk.corpus.wordnet.synset('king.n.01'), 38 | nltk.corpus.wordnet.synset('prince.n.01'), 39 | ]) 40 | FEMALE_SYNSETS = set([ 41 | nltk.corpus.wordnet.synset('female.n.02'), 42 | nltk.corpus.wordnet.synset('woman.n.01'), 43 | nltk.corpus.wordnet.synset('wife.n.01'), 44 | nltk.corpus.wordnet.synset('actress.n.01'), 45 | nltk.corpus.wordnet.synset('female_aristocrat.n.01'), 46 | nltk.corpus.wordnet.synset('mother.n.01'), 47 | nltk.corpus.wordnet.synset('sister.n.01'), 48 | nltk.corpus.wordnet.synset('daughter.n.01'), 49 | nltk.corpus.wordnet.synset('queen.n.01'), 50 | nltk.corpus.wordnet.synset('princess.n.01'), 51 | ]) 52 | NONPERSON_SYNSETS = set([ 53 | nltk.corpus.wordnet.synset('animal.n.01'), 54 | nltk.corpus.wordnet.synset('artifact.n.01'), 55 | nltk.corpus.wordnet.synset('abstraction.n.06'), 56 | ]) 57 | PERSON_SYNSET = nltk.corpus.wordnet.synset('person.n.01') 58 | EXCEPTIONS = set(['he', 'be', 'an', 'no']) 59 | 60 | 61 | def WriteRules(outfile): 62 | for synset in nltk.corpus.wordnet.all_synsets(nltk.corpus.wordnet.NOUN): 63 | if IGNORE_ALL_MULTIWORD and all('_' in i for i in synset.lemma_names): 64 | continue 65 | WriteSynset(outfile, synset) 66 | 67 | 68 | def WriteSynset(outfile, synset): 69 | hypernyms = GetAllHypernyms(synset) 70 | if IsProperNoun(synset, hypernyms): 71 | gender = GetProperNounGender(synset) 72 | for lemma in synset.lemmas: 73 | WriteProperNoun(outfile, lemma, gender) 74 | else: 75 | uncountable = IsUncountable(synset, hypernyms) 76 | if uncountable in (True, None): 77 | for lemma in synset.lemmas: 78 | WriteNoun(outfile, lemma, 'n', 'ms') 79 | if uncountable in (False, None): 80 | gender = GetNounGender(hypernyms) 81 | for lemma in synset.lemmas: 82 | WriteNoun(outfile, lemma, gender, 'sg') 83 | for plural in Pluralize(lemma.name): 84 | WriteNoun(outfile, lemma, gender, 'pl', plural) 85 | 86 | 87 | def Pluralize(noun): 88 | return set([ext.plural.noun_plural(noun, classical=True), 89 | ext.plural.noun_plural(noun, classical=False)]) 90 | 91 | 92 | def ShouldBeIgnored(lemma): 93 | return ((IGNORE_PROPER_MULTIWORD and '_' in lemma.name) or 94 | (IGNORE_UNCOMMON and not base.GetCompoundCount(lemma)) or 95 | lemma.name in EXCEPTIONS or 96 | len(lemma.name) == 1) 97 | 98 | 99 | def WriteProperNoun(outfile, lemma, gender): 100 | if ShouldBeIgnored(lemma): return 101 | 102 | noun = base.LemmaToTerminals(lemma.name) 103 | count = base.GetCompoundCount(lemma) - 1 104 | if gender: 105 | outfile.write('PrpN[NUM=sg,SNS="%s",SEX=%s,FRQ=%d] -> %s\n' % 106 | (lemma.synset.name, gender, count, noun)) 107 | else: 108 | outfile.write('PrpN[NUM=sg,SNS="%s",FRQ=%d] -> %s\n' % 109 | (lemma.synset.name, count, noun)) 110 | 111 | 112 | def WriteNoun(outfile, lemma, gender, number, name_override=None): 113 | if ShouldBeIgnored(name_override or lemma): return 114 | 115 | noun = base.LemmaToTerminals(name_override or lemma.name) 116 | count = base.GetCompoundCount(lemma) 117 | if gender: 118 | outfile.write('Noun[NUM=%s,SNS="%s",SEX=%s,FRQ=%s] -> %s\n' % 119 | (number, lemma.synset.name, gender, count, noun)) 120 | else: 121 | outfile.write('Noun[NUM=%s,SNS="%s",FRQ=%s] -> %s\n' % 122 | (number, lemma.synset.name, count, noun)) 123 | 124 | 125 | def GetAllHypernyms(synset): 126 | return set(itertools.chain(*synset.hypernym_paths())) 127 | 128 | 129 | def IsUncountable(synset, hypernyms): 130 | uncountable = bool(UNCOUNTABLE_SYNSETS.intersection(hypernyms) or 131 | any(i.endswith('ness') for i in synset.lemma_names)) 132 | if uncountable and AMBIGUOUS_COUNTABILITY_SYNSETS.intersection(hypernyms): 133 | return None 134 | else: 135 | return uncountable 136 | 137 | 138 | def IsProperNoun(synset, hypernyms): 139 | if not synset.hyponyms(): 140 | return bool(len(hypernyms) == 1 and synset.instance_hypernyms()) 141 | 142 | 143 | def GetProperNounGender(synset): 144 | cls = synset.instance_hypernyms()[0] 145 | cls_hypernyms = GetAllHypernyms(cls) 146 | if PERSON_SYNSET in cls_hypernyms: 147 | if cls_hypernyms.intersection(MALE_SYNSETS): 148 | return 'm' 149 | elif cls_hypernyms.intersection(FEMALE_SYNSETS): 150 | return 'f' 151 | else: 152 | return None 153 | else: 154 | return 'n' 155 | 156 | 157 | def GetNounGender(hypernyms): 158 | if NONPERSON_SYNSETS.intersection(hypernyms): 159 | return 'n' 160 | elif MALE_SYNSETS.intersection(hypernyms): 161 | return 'm' 162 | elif FEMALE_SYNSETS.intersection(hypernyms): 163 | return 'f' 164 | -------------------------------------------------------------------------------- /src/drt/resolve.py: -------------------------------------------------------------------------------- 1 | import logic 2 | from drs import * 3 | 4 | 5 | class ConsistencyError(Exception): pass 6 | class ResolutionError(ConsistencyError): pass 7 | class AccommodationError(ResolutionError): pass 8 | 9 | 10 | def Resolve(drs, context, is_question): 11 | # Questions are not added to the context as facts. 12 | if is_question: 13 | drs = drs.Copy() 14 | else: 15 | drs = (context or DRS()) + drs 16 | 17 | # Eliminate repeated named referents. 18 | drs.RaiseNamedRefs() 19 | 20 | # Remove presuppositions resolved by existing equalities (e.g. generated by 21 | # verb to be). 22 | ResolveEqualities(drs) 23 | 24 | const_context = context if is_question else None 25 | 26 | # Bind presuppositions as possible. 27 | ResolveAnaphora(drs, const_context, accommodate=False, pronouns=False) 28 | 29 | # Accommodate presuppositions that could not have been bound. This might 30 | # create new referents for pronouns. 31 | ResolveAnaphora(drs, const_context, accommodate=True, pronouns=False) 32 | 33 | # Bind all pronouns. 34 | ResolveAnaphora(drs, const_context, accommodate=False, pronouns=True) 35 | 36 | # Apply all equation conditions. 37 | drs.Simplify() 38 | 39 | # Remove referents known to the context. 40 | if is_question: 41 | for ref in drs.referents.copy(): 42 | if ref in context.referents or isinstance(ref, NamedReferent): 43 | drs.referents.remove(ref) 44 | 45 | return drs 46 | 47 | 48 | def ResolveAnaphora(drs, const_context, accommodate, pronouns): 49 | for cond in drs.conditions: 50 | for subdrs in cond.GetChildDRSs(): 51 | ResolveAnaphora(subdrs, const_context, accommodate, pronouns) 52 | 53 | if isinstance(cond, ResolutionCondition): 54 | if not pronouns and cond.type.startswith('pronoun-'): 55 | continue 56 | drs.RemoveCondition(cond) 57 | target = ResolveCondition(cond, const_context) 58 | ## print 'Resolving', cond 59 | if target: 60 | target_ref, target_drs = target 61 | outermost = drs 62 | if not const_context: 63 | target_drs += cond.requirements 64 | while outermost.parent: 65 | outermost = outermost.parent 66 | assert isinstance(outermost, DRS) 67 | ## print 'Replacing', cond.ref, 'with', target_ref, 'in', outermost.summary 68 | outermost.ReplaceReferent(cond.ref, target_ref, add_new=True) 69 | ## print 'Result', outermost.summary 70 | elif accommodate: 71 | ## print 'Accomodating' 72 | if const_context: 73 | raise AccommodationError('Accommodation requested in const context.') 74 | 75 | accommodating_drs = DRS([cond.ref]) + cond.requirements 76 | accomodated = False 77 | ancestors = [drs] 78 | temp = drs 79 | while temp.parent: 80 | temp = temp.parent.parent 81 | ancestors.append(temp) 82 | for potential_drs in reversed(ancestors): 83 | temp_drs = potential_drs.Copy() 84 | temp_drs += accommodating_drs 85 | temp_drs.EliminateResolutions() 86 | temp_drs.Simplify() 87 | if logic.IsConsistent(temp_drs): 88 | ## print potential_drs.summary, '+=', temp_drs.summary 89 | potential_drs += accommodating_drs 90 | accomodated = True 91 | break 92 | if not accomodated: 93 | raise ResolutionError('Could not accommodate anaphor.', cond) 94 | else: 95 | drs.AddCondition(cond) 96 | 97 | 98 | def ResolveCondition(cond, context_drs=None): 99 | ref, requirements = cond.ref, cond.requirements 100 | assert not isinstance(ref, NamedReferent) 101 | 102 | accessible_refs = requirements.parent.GetAccessibleReferents().items() 103 | accessible_refs.reverse() 104 | if context_drs: 105 | extra_refs = list(reversed(context_drs.GetAccessibleReferents().items())) 106 | accessible_refs = accessible_refs + extra_refs 107 | test = IsProvable if cond.type == 'presuppose' else IsConsistent 108 | 109 | for target, base_drs in accessible_refs: 110 | if not AreRefsCompatible(target, ref): 111 | continue 112 | if test(ref, target, base_drs, requirements): 113 | return target, base_drs 114 | 115 | if cond.type.startswith('pronoun-'): 116 | raise ResolutionError('Could not resolve anaphor.', cond) 117 | 118 | 119 | def AreRefsCompatible(target, ref): 120 | return (target != ref and 121 | (target.type == ref.type or 122 | ref.type == SINGULAR_TYPE and target.type == PLURAL_TYPE)) 123 | 124 | 125 | def IsConsistent(ref, target, base_drs, requirements): 126 | assert not isinstance(ref, NamedReferent) 127 | ## print 'Validating', ref, '=', target 128 | temp_drs = base_drs + requirements 129 | temp_drs.EliminateResolutions() 130 | temp_drs.Simplify() 131 | temp_drs.ReplaceReferent(ref, target, add_new=True) 132 | return logic.IsConsistent(temp_drs) 133 | 134 | 135 | def IsProvable(ref, target, base_drs, requirements): 136 | assert not isinstance(ref, NamedReferent) 137 | ## print 'Proving', ref, '=', target 138 | ## print ' IF ', base_drs 139 | ## print ' THEN ', requirements 140 | temp_base = base_drs.Copy() 141 | temp_base.EliminateResolutions() 142 | ## print ' IF2 ', temp_base 143 | temp_base.Simplify() 144 | ## print ' IF3 ', temp_base 145 | temp_base.ReplaceReferent(ref, target, add_new=True) 146 | ## print ' IF4 ', temp_base 147 | 148 | temp_reqs = requirements.Copy() 149 | temp_reqs.ReplaceReferent(ref, target, add_new=False) 150 | temp_reqs.EliminateResolutions() 151 | temp_reqs.Simplify() 152 | 153 | ## print ' IF_RES ', temp_base 154 | ## print ' THEN_RES ', temp_reqs 155 | mace_result = logic.IsConsistent(temp_base) 156 | ## print ' MACE RESULT:', mace_result 157 | if not mace_result: 158 | return False 159 | prover_result = logic.IsProvable(temp_base, temp_reqs) 160 | ## print ' PROVER RESULT:', prover_result 161 | return mace_result and prover_result 162 | 163 | 164 | def ResolveEqualities(root_drs): 165 | for drs in root_drs.Walk(): 166 | for cond in drs.conditions: 167 | if isinstance(cond, EqualityCondition): 168 | if (isinstance(cond.ref1, NamedReferent) and 169 | isinstance(cond.ref2, NamedReferent)): 170 | raise ResolutionError('Cannot unify two named entities: %s' % cond) 171 | ResolveEquality(drs, cond) 172 | 173 | 174 | def ResolveEquality(root_drs, cond): 175 | refs = set([cond.ref1, cond.ref2]) 176 | for drs in root_drs.Walk(): 177 | for cond in drs.conditions: 178 | if isinstance(cond, ResolutionCondition) and cond.ref in refs: 179 | drs.referents.add(cond.ref) 180 | drs += cond.requirements 181 | drs.RemoveCondition(cond) 182 | 183 | 184 | def ResolveStatement(drs, context): 185 | return Resolve(drs, context, False) 186 | 187 | 188 | def ResolveQuestion(drs, context): 189 | return Resolve(drs, context, True) 190 | -------------------------------------------------------------------------------- /src/build/verbs.py: -------------------------------------------------------------------------------- 1 | # NOTE: As of writing, this requires VerbNet 3.1 while the NLTK repository 2 | # uses 2.1. The new version has to be downloaded and replaced manually. 3 | 4 | import collections 5 | import cPickle as pickle 6 | import nltk.corpus 7 | import base 8 | 9 | 10 | VERBS_LIST = 'data/verbs.pickle' 11 | VERB_TEMPLATE = 'Verb[FORM=%s,PTRN=%d,CLS="%s",SNS="%s",FRQ=%d] -> %s' 12 | CV_TEMPLATE = 'CV[PTRN=%d,NUM=?n,PER=?p,TENS=?t]' 13 | VP_TEMPLATE = 'VP[NUM=?n,PER=?p,TENS=?t] -> %s' 14 | VPQ_TEMPLATE = 'VPQ[NUM=?n,PER=?p,TENS=?t,TRGT=%d,PTCL=%s] -> %s' 15 | PREP_TEMPLATE = 'Prep[TYP=spatial,%s]' 16 | VERB_FORMS = ('inf', 'tps', 'ger', 'pret', 'pp') 17 | 18 | 19 | class VerbNetError(Exception): pass 20 | 21 | 22 | def HandleLex(node, *_): 23 | value = node.attrib['value'].replace('[+be]', '').strip() 24 | if value: 25 | return [base.LemmaToTerminals(i) for i in value.split()] 26 | else: 27 | return [] 28 | 29 | 30 | def HandlePrep(node, *_): 31 | if 'value' in node.attrib: 32 | return HandleLex(node) 33 | elif node.findall('.//SELRESTR'): 34 | restrictions = node.findall('.//SELRESTR') 35 | args = [r.attrib['Value'] + r.attrib['type'] for r in restrictions] 36 | if len(args) == 1: 37 | return PREP_TEMPLATE % args[0] 38 | elif node.find('.//SELRESTRS').attrib.get('logic') == 'or': 39 | return [PREP_TEMPLATE % i for i in args] 40 | else: 41 | return PREP_TEMPLATE % ','.join(args) 42 | else: 43 | raise VerbNetError('Unexpected generic preposition.') 44 | 45 | 46 | def HandleNp(node, *_): 47 | # TODO: Deal with syntactic restrictions (inc. and/or), e.g. get-13.5.1. 48 | # See HandlePrep. 49 | return 'NP' 50 | 51 | 52 | def FlattenRule(rule): 53 | for i, node in enumerate(rule): 54 | if not isinstance(node, basestring): 55 | if node: 56 | for choice in node: 57 | for product in FlattenRule(rule[:i] + (choice,) + rule[i + 1:]): 58 | yield product 59 | else: 60 | for product in FlattenRule(rule[:i] + rule[i + 1:]): 61 | yield product 62 | return 63 | yield rule 64 | 65 | 66 | def GetBasicSentenceRules(): 67 | for cls in nltk.corpus.verbnet.classids(): 68 | frames = nltk.corpus.verbnet.vnclass(cls).findall('FRAMES/FRAME') 69 | for index, frame in enumerate(frames): 70 | syntax = frame.find('SYNTAX') 71 | rule = tuple(HANDLERS[node.tag](node, cls) 72 | for node in syntax.getchildren()) 73 | for r in FlattenRule(rule): 74 | yield cls, index, r, frame.find('.//EXAMPLE').text 75 | 76 | 77 | def GetFramePatterns(): 78 | patterns = collections.defaultdict(lambda: collections.defaultdict(set)) 79 | for cls, frame_index, rule, example in GetBasicSentenceRules(): 80 | # TODO: Stop ignoring adverbs. 81 | if 'Adv' in rule: continue 82 | # TODO: Deal with patterns not starting with "NP". 83 | if not (rule[0].startswith('NP') and rule[1].startswith('CV')): continue 84 | for index, node in enumerate(rule): 85 | if node.startswith('CV'): 86 | generic_rule = rule[:index] + ('CV',) + rule[index + 1:] 87 | patterns[generic_rule][cls].add(frame_index) 88 | break 89 | 90 | return [(i, j, dict(k)) for i, (j, k) in enumerate(patterns.items())] 91 | 92 | 93 | def PrepareVPRule(rule, index): 94 | return ' '.join(rule[1:]).replace('CV', CV_TEMPLATE % index) 95 | 96 | 97 | def MakeQuestionRule(index, rule, node_index, preposition=None): 98 | rule = list(rule) 99 | if preposition: 100 | del rule[node_index - 1:node_index + 1] 101 | if preposition.startswith("Prep"): 102 | preposition = 'PREP,' + preposition[17:-1] 103 | else: 104 | preposition = preposition.replace('"', '') 105 | preposition = preposition.replace(' ', '_').replace("'", '_') 106 | else: 107 | del rule[node_index:node_index + 1] 108 | preposition = 'NONE' 109 | 110 | return VPQ_TEMPLATE % (node_index, preposition, PrepareVPRule(rule, index)) 111 | 112 | 113 | def GetQuestionRules(patterns): 114 | rules = [] 115 | 116 | # Verb phrase rules for object questions. 117 | for index, rule, _ in patterns: 118 | for node_index, node in enumerate(rule[1:]): 119 | node_index += 1 120 | if node.startswith('NP'): 121 | rules.append(MakeQuestionRule(index, rule, node_index)) 122 | 123 | previous = rule[node_index - 1] 124 | if previous.startswith('"') or previous.startswith('Prep'): 125 | rules.append(MakeQuestionRule(index, rule, node_index, previous)) 126 | 127 | return rules 128 | 129 | 130 | def GetSentenceRules(patterns): 131 | rules = [] 132 | 133 | # Verb phrase rules. 134 | for index, rule, _ in patterns: 135 | rules.append(VP_TEMPLATE % PrepareVPRule(rule, index)) 136 | 137 | return rules 138 | 139 | 140 | def GetVerbRules(patterns): 141 | conjugation = pickle.load(open(VERBS_LIST)) 142 | rules = [] 143 | 144 | with_children = collections.defaultdict(set) 145 | for cls in nltk.corpus.verbnet.classids(): 146 | if cls.count('-') > 1: 147 | name, number, suffix = cls.split('-', 2) 148 | base_class = name + '-' + number 149 | 150 | for number in suffix.split('-'): 151 | with_children[base_class].add(cls) 152 | base_class += '-' + number 153 | with_children[base_class].add(cls) 154 | else: 155 | with_children[cls].add(cls) 156 | 157 | for index, pattern, classes in patterns: 158 | for cls in classes: 159 | for frame_cls in with_children[cls]: 160 | frame_cls = nltk.corpus.verbnet.vnclass(frame_cls) 161 | for member in frame_cls.findall('MEMBERS/MEMBER'): 162 | verb = member.attrib['name'] 163 | lemmas = member.attrib['wn'].replace('?', '').split() 164 | if lemmas: 165 | lemmas = [nltk.corpus.wordnet.lemma_from_key(i + '::') 166 | for i in lemmas] 167 | else: 168 | lemmas = nltk.corpus.wordnet.lemmas(verb, 'v') 169 | if len(lemmas) > 1: 170 | lemmas = [] 171 | for lemma in lemmas: 172 | synset = lemma.synset.name 173 | count = base.GetCompoundCount(lemma) 174 | if verb not in conjugation: continue 175 | for form, conjugated_verb in zip(VERB_FORMS, conjugation[verb]): 176 | conjugated_verb = base.LemmaToTerminals(conjugated_verb) 177 | args = (form, index, cls, synset, count, conjugated_verb) 178 | rules.append(VERB_TEMPLATE % args) 179 | 180 | return rules 181 | 182 | 183 | def WriteRules(rules_file, patterns_file): 184 | patterns = GetFramePatterns() 185 | sentence_rules = GetSentenceRules(patterns) 186 | question_rules = GetQuestionRules(patterns) 187 | verb_rules = GetVerbRules(patterns) 188 | 189 | pickle.dump(patterns, patterns_file) 190 | 191 | for ruleset in (sentence_rules, question_rules, verb_rules): 192 | for rule in ruleset: 193 | rules_file.write(rule) 194 | rules_file.write('\n') 195 | rules_file.write('\n') 196 | 197 | 198 | HANDLERS = { 199 | 'LEX': HandleLex, 200 | 'PREP': HandlePrep, 201 | 'NP': HandleNp, 202 | 'VERB': lambda _, cls: 'CV[CLS="%s"]' % cls, 203 | 'ADV': lambda *_: 'Adv', 204 | 'ADJ': lambda *_: 'AJP' 205 | } 206 | -------------------------------------------------------------------------------- /src/build/names.py: -------------------------------------------------------------------------------- 1 | import nltk.corpus 2 | import base 3 | 4 | 5 | POPULAR_MALE_NAMES = [ 6 | 'wade', 'freddie', 'enrique', 'terrence', 'eduardo', 'rene', 'terrance', 7 | 'kent', 'seth', 'tracy', 'marion', 'sergio', 'kirk', 'perry', 'salvador', 8 | 'marshall', 'andy', 'virgil', 'ross', 'daryl', 'willard', 'clifton', 'morris', 9 | 'isaac', 'julian', 'byron', 'sidney', 'johnnie', 'ivan', 'dave', 'alberto', 10 | 'alfredo', 'casey', 'jaime', 'bob', 'ken', 'wallace', 'ian', 'jordan', 11 | 'everett', 'jimmie', 'felix', 'armando', 'dwight', 'dwayne', 'max', 'hugh', 12 | 'clayton', 'guy', 'nelson', 'allan', 'kurt', 'kelly', 'julio', 'cody', 13 | 'lance', 'lonnie', 'darren', 'tyrone', 'mathew', 'ted', 'clinton', 'fernando', 14 | 'javier', 'christian', 'jessie', 'neil', 'jamie', 'darryl', 'erik', 'claude', 15 | 'cory', 'karl', 'adrian', 'jared', 'harvey', 'arnold', 'roland', 'mitchell', 16 | 'ron', 'gabriel', 'brad', 'elmer', 'andre', 'franklin', 'duane', 'cecil', 17 | 'chester', 'ben', 'raul', 'milton', 'edgar', 'leslie', 'rafael', 'nathaniel', 18 | 'angel', 'brett', 'ruben', 'reginald', 'marc', 'gene', 'gilbert', 'tyler', 19 | 'charlie', 'ramon', 'brent', 'lester', 'rick', 'sam', 'ricardo', 'shane', 20 | 'hector', 'glen', 'clyde', 'roberto', 'vernon', 'maurice', 'herman', 'corey', 21 | 'zachary', 'lewis', 'dan', 'derrick', 'pedro', 'dustin', 'jorge', 'greg', 22 | 'dean', 'gordon', 'wesley', 'tim', 'alvin', 'leo', 'floyd', 'jerome', 23 | 'darrell', 'warren', 'derek', 'leon', 'tommy', 'lloyd', 'bill', 'ronnie', 24 | 'jon', 'alex', 'calvin', 'tom', 'jim', 'jay', 'oscar', 'miguel', 'clifford', 25 | 'theodore', 'micheal', 'marcus', 'francisco', 'leroy', 'mario', 'bernard', 26 | 'alexander', 'barry', 'randall', 'troy', 'ricky', 'eddie', 'don', 'edwin', 27 | 'joel', 'ray', 'frederick', 'herbert', 'jesus', 'bradley', 'francis', 'kyle', 28 | 'alfred', 'melvin', 'lee', 'jacob', 'chad', 'jeff', 'travis', 'jeffery', 29 | 'glenn', 'vincent', 'marvin', 'allen', 'norman', 'curtis', 'rodney', 'manuel', 30 | 'dale', 'nathan', 'leonard', 'stanley', 'mike', 'luis', 'tony', 'bryan', 31 | 'danny', 'antonio', 'jimmy', 'earl', 'johnny', 'chris', 'philip', 'sean', 32 | 'clarence', 'shawn', 'alan', 'craig', 'jesse', 'todd', 'phillip', 'ernest', 33 | 'martin', 'victor', 'bobby', 'russell', 'carlos', 'eugene', 'howard', 'randy', 34 | 'aaron', 'jeremy', 'louis', 'steve', 'billy', 'wayne', 'fred', 'harry', 35 | 'adam', 'brandon', 'bruce', 'benjamin', 'roy', 'nicholas', 'lawrence', 36 | 'ralph', 'willie', 'samuel', 'keith', 'gerald', 'terry', 'justin', 'jonathan', 37 | 'albert', 'jack', 'juan', 'joe', 'roger', 'ryan', 'arthur', 'carl', 38 | 'henry', 'douglas', 'harold', 'peter', 'patrick', 'walter', 'dennis', 39 | 'jerry', 'joshua', 'gregory', 'raymond', 'andrew', 'stephen', 'eric', 40 | 'scott', 'frank', 'jeffrey', 'larry', 'jose', 'timothy', 'gary', 'matthew', 41 | 'jason', 'kevin', 'anthony', 'ronald', 'brian', 'edward', 'steven', 42 | 'kenneth', 'george', 'donald', 'mark', 'paul', 'daniel', 'christopher', 43 | 'thomas', 'joseph', 'charles', 'richard', 'david', 'william', 'michael', 44 | 'robert', 'john', 'james' 45 | ] 46 | POPULAR_FEMALE_NAMES = [ 47 | 'claire', 'katrina', 'erika', 'sherri', 'ramona', 'daisy', 'shelly', 'mae', 48 | 'misty', 'toni', 'kristina', 'violet', 'bobbie', 'becky', 'velma', 'miriam', 49 | 'sonia', 'felicia', 'jenny', 'leona', 'tracey', 'dianne', 'billie', 'olga', 50 | 'brandy', 'carole', 'naomi', 'priscilla', 'kay', 'penny', 'leah', 'cassandra', 51 | 'nina', 'margie', 'nora', 'jennie', 'gwendolyn', 'hilda', 'patsy', 'deanna', 52 | 'christy', 'lena', 'myrtle', 'marsha', 'mabel', 'irma', 'maxine', 'terry', 53 | 'mattie', 'vickie', 'jo', 'dora', 'caroline', 'stella', 'marian', 'courtney', 54 | 'viola', 'lydia', 'glenda', 'heidi', 'marlene', 'minnie', 'nellie', 'tanya', 55 | 'marcia', 'jackie', 'claudia', 'lillie', 'constance', 'georgia', 'joy', 56 | 'tamara', 'allison', 'colleen', 'maureen', 'arlene', 'pearl', 'melinda', 57 | 'delores', 'bessie', 'charlene', 'willie', 'vera', 'agnes', 'natalie', 58 | 'jessie', 'kristin', 'gina', 'wilma', 'stacey', 'ella', 'tonya', 'lucy', 59 | 'gertrude', 'terri', 'eileen', 'rosemary', 'tara', 'carla', 'vicki', 'jeanne', 60 | 'beth', 'elsie', 'sue', 'alma', 'vanessa', 'kristen', 'katie', 'laurie', 61 | 'jeanette', 'yolanda', 'loretta', 'melanie', 'brittany', 'holly', 'roberta', 62 | 'vivian', 'ida', 'renee', 'ana', 'stacy', 'dana', 'marion', 'samantha', 63 | 'june', 'annette', 'yvonne', 'audrey', 'bernice', 'dolores', 'beatrice', 64 | 'erica', 'regina', 'sally', 'lynn', 'lorraine', 'joann', 'cathy', 'lauren', 65 | 'geraldine', 'erin', 'jill', 'veronica', 'darlene', 'bertha', 'gail', 66 | 'michele', 'suzanne', 'alicia', 'megan', 'danielle', 'valerie', 'eleanor', 67 | 'joanne', 'jamie', 'lucille', 'clara', 'leslie', 'april', 'debbie', 'eva', 68 | 'amber', 'hazel', 'rhonda', 'anita', 'juanita', 'emma', 'pauline', 'esther', 69 | 'monica', 'charlotte', 'carrie', 'marjorie', 'elaine', 'ellen', 'ethel', 70 | 'sheila', 'shannon', 'thelma', 'josephine', 'sylvia', 'sherry', 'kim', 71 | 'edith', 'victoria', 'wendy', 'grace', 'cindy', 'rosa', 'carmen', 'tiffany', 72 | 'edna', 'tracy', 'florence', 'connie', 'dawn', 'rita', 'gladys', 'crystal', 73 | 'peggy', 'robin', 'emily', 'lillian', 'annie', 'diana', 'paula', 'norma', 74 | 'phyllis', 'tina', 'lois', 'ruby', 'julia', 'bonnie', 'wanda', 'jacqueline', 75 | 'anne', 'sara', 'louise', 'kathryn', 'andrea', 'marilyn', 'rachel', 'lori', 76 | 'jane', 'irene', 'tammy', 'denise', 'beverly', 'theresa', 'kathy', 77 | 'christina', 'judy', 'nicole', 'kelly', 'janice', 'rose', 'judith', 'ashley', 78 | 'joan', 'katherine', 'mildred', 'cheryl', 'jean', 'evelyn', 'gloria', 'doris', 79 | 'teresa', 'heather', 'julie', 'alice', 'diane', 'joyce', 'ann', 'frances', 80 | 'catherine', 'janet', 'marie', 'christine', 'carolyn', 'stephanie', 'amanda', 81 | 'debra', 'martha', 'pamela', 'kathleen', 'virginia', 'rebecca', 'anna', 'amy', 82 | 'brenda', 'melissa', 'angela', 'cynthia', 'shirley', 'jessica', 'deborah', 83 | 'kimberly', 'sarah', 'laura', 'michelle', 'sharon', 'ruth', 'carol', 'donna', 84 | 'sandra', 'helen', 'betty', 'karen', 'nancy', 'lisa', 'dorothy', 'margaret', 85 | 'susan', 'maria', 'jennifer', 'elizabeth', 'barbara', 'linda', 'patricia', 86 | 'mary' 87 | ] 88 | 89 | 90 | def WriteRules(outfile): 91 | names = ([('m', i.lower()) for i in nltk.corpus.names.read('male.txt')] + 92 | [('f', i.lower()) for i in nltk.corpus.names.read('female.txt')]) 93 | for gender, name in names: 94 | ambiguity = Ambiguity(name, gender) 95 | name = base.LemmaToTerminals(name) 96 | outfile.write('PrpN[NUM=sg,SEX=%s,FRQ=%d] -> %s\n' % 97 | (gender, -ambiguity, name)) 98 | 99 | 100 | def Ambiguity(name, gender): 101 | synsets = nltk.corpus.wordnet.synsets(name) 102 | sum = 0 103 | for synset in synsets: 104 | if synset.pos in (nltk.corpus.wordnet.ADJ, nltk.corpus.wordnet.ADJ_SAT): 105 | sum += 20 106 | elif not (synset.instance_hypernyms() and not synset.hypernyms()): 107 | sum += 1 108 | 109 | if gender == 'm' and name in POPULAR_MALE_NAMES: 110 | sum -= POPULAR_MALE_NAMES.index(name) 111 | elif gender == 'f' and name in POPULAR_FEMALE_NAMES: 112 | sum -= POPULAR_FEMALE_NAMES.index(name) 113 | 114 | return sum 115 | -------------------------------------------------------------------------------- /brainstorming/questions_blackboard.txt: -------------------------------------------------------------------------------- 1 | interrogative determiner 2 | which 3 | what 4 | whose 5 | interrogative pronoun 6 | who 7 | whom 8 | what 9 | which 10 | interrogative pro-adverb 11 | where .. Prep 12 | pro-verb 13 | do 14 | happen? 15 | 16 | ## TENSES: g, i, ip // r, rc, rp, p 17 | ## FORMS: inf, tps, ger, pret, pp 18 | 19 | Subject 20 | What is a dog? 21 | What is smart? 22 | What is fluffier than the cat? 23 | What are the cats? 24 | Who is smart? 25 | *Who am I? 26 | *Who is he? 27 | *Who are they? 28 | ***r:Who/What VP 29 | 30 | What causes that? 31 | What fell? 32 | Who traveled to Ireland? 33 | 34 | Who gives Lara the books? 35 | Who is giving Lara the books? 36 | Who gave Lara the books? 37 | Who has given Lara the books? 38 | ***r:Who/What VP 39 | Direct Object 40 | ->Alice took the book. 41 | ?the book 42 | What does Alice take? 43 | What did Alice take? 44 | What is Alice taking? 45 | What has Alice taken? 46 | 47 | ->The students gave Lara the homeworks. 48 | ?the homewarks 49 | What do the students give Lara? 50 | What did the students give Lara? 51 | What are the students giving Lara? 52 | What have the students given Lara? 53 | ?Lara 54 | Who[m] do the students give the homeworks? 55 | Who[m] did the students give the homeworks? 56 | Who[m] are the students giving the homeworks? 57 | Who[m] have the students given the homeworks? 58 | 59 | ->Alice saw Jack. 60 | ?Jack 61 | Who[m] does Alice see? 62 | Who[m] did Alice see? 63 | Who[m] is Alice seeing? 64 | Who[m] has Alice seen? 65 | 66 | ->Alice introduced Jack to Bob. 67 | ?Jack 68 | Who[m] does Alice introduce to Bob? 69 | Who[m] did Alice introduce to Bob? 70 | Who[m] is Alice introducing to Bob? 71 | Who[m] has Alice introduced to Bob? 72 | ?Bob 73 | Who[m] does Alice introduce Jack to? 74 | Who[m] did Alice introduce Jack to? 75 | Who[m] is Alice introducing Jack to? 76 | Who[m] has Alice introduced Jack to? 77 | ?Bob 78 | To whom does Alice introduce Jack? 79 | To whom did Alice introduce Jack? 80 | To whom is Alice introducing Jack? 81 | To whom has Alice introduced Jack? 82 | 83 | ->Alice sold Mary the pen for a fortune. 84 | S V O1 O2 for O3 85 | ?Mary 86 | Q Aux S V O2 for O3 87 | Whom does Alice sell the pen [for a fortune]? 88 | Whom did Alice sell the pen [for a fortune]? 89 | Whom is Alice selling the pen [for a fortune]? 90 | Whom has Alice sold the pen [for a fortune]? 91 | ?the pen 92 | Q Aux S V O1 for O3 93 | What does Alice sell Mary for a fortune? 94 | What did Alice sell Mary for a fortune? 95 | What is Alice selling Mary for a fortune? 96 | What has Alice sold Mary for a fortune? 97 | Q Aux S V O1 O2 for 98 | What does Alice sell Mary the pen for? 99 | What did Alice sell Mary the pen for? 100 | What is Alice selling Mary the pen for? 101 | What has Alice sold Mary the pen for? 102 | ?a fortune 103 | for Q Aux S V O1 O2 104 | For what does Alice sell Mary the pen? 105 | For what did Alice sell Mary the pen? 106 | For what is Alice selling Mary the pen? 107 | For what has Alice sold Mary the pen? 108 | 109 | VP[NUM=?n,PER=?p,TENS=?t] -> CV[PTRN=45,NUM=?n,PER=?p,TENS=?t] NP1 NP2 "at" NP3 110 | Alice sold Mary the pen for a fortune. 111 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=1,PREP=NULL] -> CV[PTRN=45,NUM=?n,PER=?p,TENS=?t] NP2 "at" NP3 112 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=2,PREP=NULL] -> CV[PTRN=45,NUM=?n,PER=?p,TENS=?t] NP1 "at" NP3 113 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=3,PREP=NULL] -> CV[PTRN=45,NUM=?n,PER=?p,TENS=?t] NP1 NP2 "at" 114 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=3,PREP=at] -> CV[PTRN=45,NUM=?n,PER=?p,TENS=?t] NP1 NP2 115 | 116 | VP[NUM=?n,PER=?p,TENS=?t] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] NP1 "to" NP2 "in" NP3 117 | Jennifer baked the potatoes to a crisp in the oven. 118 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=1,PREP=NULL] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] "to" NP2 "in" NP3 119 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=2,PREP=NULL] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] NP1 "to" "in" NP3 120 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=2,PREP=to] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] NP1 "in" NP3 121 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=3,PREP=NULL] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] NP1 "to" NP2 "in" 122 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=3,PREP=in] -> CV[PTRN=30,NUM=?n,PER=?p,TENS=?t] NP1 "to" NP2 123 | 124 | VP[NUM=?n,PER=?p,TENS=?t] -> CV[PTRN=97,NUM=?n,PER=?p,TENS=?t] Prep[TYP=spatial,+src] NP 125 | She comes from Ireland. 126 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=1,PREP=NULL] -> CV[PTRN=97,NUM=?n,PER=?p,TENS=?t] Prep[TYP=spatial,+src] 127 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=1,PREP=RESTRICT,+src] -> CV[PTRN=97,NUM=?n,PER=?p,TENS=?t] 128 | 129 | VP[NUM=?n,PER=?p,TENS=?t] -> CV[PTRN=5,NUM=?n,PER=?p,TENS=?t] NP "up" 130 | She spruced herself up 131 | QVP[NUM=?n,PER=?p,TENS=?t,TRGT=1,PREP=NULL,+src] -> CV[PTRN=5,NUM=?n,PER=?p,TENS=?t] "up" 132 | 133 | PP 134 | ->Alice took the dog to the woods at the edge of the town. 135 | ?the town 136 | To the woods at the edge of what did Alice take the dog? 137 | ?the woods at the edge of the town 138 | To what did Alice take the dog? 139 | What did Alice take the dog to? 140 | ?to the woods at the edge of the town 141 | Where did Alice take the dog? 142 | ->Alice is in the room. 143 | ?the room 144 | In what is Alice? 145 | What is Alice in? 146 | ?in the room 147 | Where is Alice? 148 | 149 | 150 | YN 151 | Alice is smart? 152 | The dogs were gnawing on the bones? 153 | ***S[dcl] ? 154 | 155 | Is Alice smart? 156 | Is Alice being smart? 157 | Was Alice smart? 158 | Has Alice been smart? 159 | Is Alice not smart? 160 | Is Alice smarter than Mary? 161 | Is Alice in the room? 162 | Are they hungry? 163 | ***r:CV[tens=r,sem=pos,v=be,num,per] NP[num,per]-sbj {not} Predicate 164 | ***rc:CV[tens=r,sem=pos,v=be,num,per] NP[num,per]-sbj being {not} Predicate 165 | ***rp:CV[tens=r,sem=pos,v=have,num,per] NP[num,per]-sbj been {not} Predicate 166 | ***p:CV[tens=p,sem=pos,v=be,num,per] NP[num,per]-sbj {not} Predicate 167 | 168 | Does Alice dance? 169 | Is Alice dancing? 170 | Did Alice dance? 171 | Has Alice danced? 172 | Does Alice not dance? 173 | Do they give Jack the letters? 174 | Are they giving Jack the letters? 175 | Did they give Jack the letters? 176 | Have they given Jack the letters? 177 | Am I dancing? 178 | ***r:CV[tens=r,sem=pos,v=do,num,per] NP[num,per]-sbj VP[tens=i] 179 | ***rc:CV[tens=r,sem=pos,v=be,num,per] NP[num,per]-sbj VP[tens=g] 180 | ***rp:CV[tens=r,sem=pos,v=have,num,per] NP[num,per]-sbj VP[tens=ip] 181 | ***p:CV[tens=p,sem=pos,v=do,num,per] NP[num,per]-sbj VP[tens=i] 182 | 183 | 184 | 185 | Statement 186 | (S[PTRN=?pt, RUL=1, TYP='dcl'] 187 | (NP[NUM='sg', PER=3, RUL=310] 188 | (PN[NUM='sg', RUL=602, SEX='f'] 189 | (PrpN[AMBG=-299, NUM='sg', SEX='f'] mary))) 190 | (VP[NUM=?n, PER=?p, TENS='p'] 191 | (CV[PTRN=134, SEM='pos', TENS='p'] 192 | (Verb[CLS='give-13.1', FORM='pret', FRQ=179, PTRN=134, SNS='give.v.01'] 193 | gave)) 194 | (NP[NUM='sg', PER=3, RUL=310] 195 | (PN[NUM='sg', RUL=602, SEX='f'] 196 | (PrpN[AMBG=0, NUM='sg', SEX='f'] lara))) 197 | (NP[NUM='sg', PER=3, RUL=309] 198 | (DT[NUM='sg', RUL=401, -definite, -poss] 199 | (Art[NUM='sg', -definite] a)) 200 | (Noun[FRQ=0, NUM='sg', SEX='n', SNS='candelabrum.n.01'] 201 | candelabra)))) 202 | [s_Mary, s_Lara, e3, s4 | give.v.01(e3), _Agent(e3, s_Mary), _Recipient(e3, s_Lara), candelabrum.n.01(s4), _Theme(e3, s4)] 203 | Question(NP1) 204 | (S[RUL=12, TYP='whq'] 205 | (Q[RUL=901, -sbj] whom) 206 | (AuxV[SEM='pos', TENS='p', TYP='do'] did) 207 | (NP[NUM='sg', PER=3, RUL=310] 208 | (PN[NUM='sg', RUL=602, SEX='f'] 209 | (PrpN[AMBG=-299, NUM='sg', SEX='f'] mary))) 210 | (VPQ[NUM=?n, PER=?p, PTCL='NONE', TENS='i', TRGT=3] 211 | (CV[PTRN=134, SEM='pos', TENS='i'] 212 | (Verb[CLS='give-13.1', FORM='inf', FRQ=179, PTRN=134, SNS='give.v.01'] 213 | give)) 214 | (NP[NUM='sg', PER=3, RUL=309] 215 | (DT[NUM='sg', RUL=401, -definite, -poss] 216 | (Art[NUM='sg', -definite] a)) 217 | (Noun[FRQ=0, NUM='sg', SEX='n', SNS='candelabrum.n.01'] 218 | candelabra)))) 219 | Question(NP2) 220 | (S[RUL=12, TYP='whq'] 221 | (Q[RUL=901, -sbj] whom) 222 | (AuxV[SEM='pos', TENS='p', TYP='do'] did) 223 | (NP[NUM='sg', PER=3, RUL=310] 224 | (PN[NUM='sg', RUL=602, SEX='f'] 225 | (PrpN[AMBG=-299, NUM='sg', SEX='f'] mary))) 226 | (VPQ[NUM=?n, PER=?p, PTCL='NONE', TENS='i', TRGT=2] 227 | (CV[PTRN=134, SEM='pos', TENS='i'] 228 | (Verb[CLS='give-13.1', FORM='inf', FRQ=179, PTRN=134, SNS='give.v.01'] 229 | give)) 230 | (NP[NUM='sg', PER=3, RUL=310] 231 | (PN[NUM='sg', RUL=602, SEX='f'] 232 | (PrpN[AMBG=0, NUM='sg', SEX='f'] lara))))) 233 | Question(NP2/Prep) 234 | (S[RUL=12, TYP='whq'] 235 | (Q[RUL=901, +sbj] what) 236 | (AuxV[SEM='pos', TENS='p', TYP='do'] did) 237 | (NP[NUM='sg', PER=3, RUL=310] 238 | (PN[NUM='sg', RUL=602, SEX='f'] 239 | (PrpN[AMBG=-299, NUM='sg', SEX='f'] mary))) 240 | (VPQ[NUM=?n, PER=?p, PTCL='NONE', TENS='i', TRGT=2] 241 | (CV[PTRN=37, SEM='pos', TENS='i'] 242 | (Verb[CLS='give-13.1', FORM='inf', FRQ=179, PTRN=37, SNS='give.v.01'] 243 | give)) 244 | to 245 | (NP[NUM='sg', PER=3, RUL=310] 246 | (PN[NUM='sg', RUL=602, SEX='f'] 247 | (PrpN[AMBG=0, NUM='sg', SEX='f'] lara))))) -------------------------------------------------------------------------------- /brainstorming/demo_plan.txt: -------------------------------------------------------------------------------- 1 | What it is NOT 2 | Chatbot 3 | Complete in coverage 4 | Efficient 5 | 6 | Anaphora + Conjunction 7 | Alice and Vincent are waltzing in the hall. 8 | She is happy. 9 | Who is waltzing? 10 | Who is dancing? 11 | Who is happy? 12 | Alice and Vincent are waltzing in the hall. 13 | Found 13 parse trees. 14 | Evaluated 1 interpretation. 15 | Inferred word senses: 16 | waltzing: dance a waltz. 17 | hall: an interior passage or corridor onto which rooms open. 18 | Statement understood and added to context. 19 | She is happy. 20 | Found 5 parse trees. 21 | Evaluated 1 interpretation. 22 | Inferred word senses: 23 | happy: enjoying or showing or marked by joy or pleasure. 24 | Statement understood and added to context. 25 | Who is waltzing? 26 | Found 3 parse trees. 27 | Evaluated 1 interpretation. 28 | Inferred word senses: 29 | waltzing: dance a waltz. 30 | Alice and Vincent. 31 | Who is dancing? 32 | Found 12 parse trees. 33 | Evaluated 4 interpretations. 34 | Inferred word senses: 35 | dancing: move in a pattern; usually to musical accompaniment; do or perform a dance. 36 | Alice and Vincent. 37 | Who is happy? 38 | Found 15 parse trees. 39 | Evaluated 1 interpretation. 40 | Inferred word senses: 41 | happy: enjoying or showing or marked by joy or pleasure. 42 | Alice. 43 | Inference 44 | Socrates is a man. 45 | Is Socrates mortal? 46 | Every man is mortal. 47 | Is Socrates mortal? 48 | Socrates is a man. 49 | Found 20 parse trees. 50 | Evaluated 1 interpretation. 51 | Inferred word senses: 52 | man: an adult person who is male (as opposed to a woman). 53 | Statement understood and added to context. 54 | Is Socrates mortal? 55 | Found 8 parse trees. 56 | Evaluated 8 interpretations. 57 | Inferred word senses: 58 | mortal: subject to death. 59 | That is unknown. 60 | Every man is mortal. 61 | Found 44 parse trees. 62 | Evaluated 1 interpretation. 63 | Inferred word senses: 64 | man: an adult person who is male (as opposed to a woman). 65 | mortal: subject to death. 66 | Statement understood and added to context. 67 | Is Socrates mortal? 68 | Found 8 parse trees. 69 | Evaluated 1 interpretation. 70 | Inferred word senses: 71 | mortal: subject to death. 72 | Yes. 73 | Donkey Sentences 74 | Ahmad is a farmer and has a mule. 75 | Whom does Ahmad beat? 76 | If a farmer owns a mule, he beats it. 77 | Whom does Ahmad beat? 78 | Ahmad is a farmer and has a mule. 79 | Found 2 parse trees. 80 | Evaluated 1 interpretation. 81 | Inferred word senses: 82 | farmer: a person who operates a farm. 83 | has: have ownership or possession of. 84 | mule: hybrid offspring of a male donkey and a female horse; usually sterile. 85 | Statement understood and added to context. 86 | Whom does Ahmad beat? 87 | Found 15 parse trees. 88 | Evaluated 15 interpretations. 89 | Inferred word senses: 90 | beat: give a beating to; subject to a beating, either as a punishment or as an act of aggression. 91 | No known entities match the query. 92 | If a farmer owns a mule, he beats it. 93 | Found 120 parse trees. 94 | Evaluated 1 interpretation. 95 | Inferred word senses: 96 | farmer: a person who operates a farm. 97 | owns: have ownership or possession of. 98 | mule: hybrid offspring of a male donkey and a female horse; usually sterile. 99 | beats: give a beating to; subject to a beating, either as a punishment or as an act of aggression. 100 | Statement understood and added to context. 101 | Whom does Ahmad beat? 102 | Found 15 parse trees. 103 | Evaluated 2 interpretations. 104 | Inferred word senses: 105 | beat: give a beating to; subject to a beating, either as a punishment or as an act of aggression. 106 | Ahmad's mule. 107 | POS Disambiguation 108 | Many soldiers desert the desert base. 109 | What do the men desert? 110 | Many soldiers desert the desert base. 111 | Found 38 parse trees. 112 | Evaluated 1 interpretation. 113 | Inferred word senses: 114 | soldiers: an enlisted man or woman who serves in an army. 115 | desert: leave someone who needs or counts on you; leave in the lurch. 116 | desert: arid land with little or no vegetation. 117 | base: installation from which a military force initiates operations. 118 | Statement understood and added to context. 119 | What do the men desert? 120 | Found 11 parse trees. 121 | Evaluated 1 interpretation. 122 | Inferred word senses: 123 | men: someone who serves in the armed forces; a member of a military force. 124 | desert: leave someone who needs or counts on you; leave in the lurch. 125 | The desert base. 126 | Meaning Disambiguation + Multi-word Lemmas 127 | Mia is sitting on a grassy bank. 128 | The bank denied John's loan. 129 | The blood bank needs donations. 130 | The west bank is occupied. 131 | Mia is sitting on a grassy bank. 132 | Found 90 parse trees. 133 | Evaluated 1 interpretation. 134 | Inferred word senses: 135 | sitting: be seated. 136 | grassy: abounding in grass. 137 | bank: sloping land (especially the slope beside a body of water). 138 | Statement understood and added to context. 139 | The bank denied John's loan. 140 | Found 88 parse trees. 141 | Evaluated 1 interpretation. 142 | Inferred word senses: 143 | bank: a financial institution that accepts deposits and channels the money into lending activities. 144 | denied: refuse to recognize or acknowledge. 145 | loan: the temporary provision of money (usually at interest). 146 | Statement understood and added to context. 147 | The blood bank needs donations. 148 | Found 896 parse trees. 149 | Evaluated 1 interpretation. 150 | Inferred word senses: 151 | blood bank: a place for storing whole blood or blood plasma. 152 | needs: require as useful, just, or proper. 153 | donations: a voluntary gift (as of money or service or ideas) made to some worthwhile cause. 154 | Statement understood and added to context. 155 | The west bank is occupied. 156 | Found 180 parse trees. 157 | Evaluated 1 interpretation. 158 | Inferred word senses: 159 | west bank: an area between Israel and Jordan on the west bank of the Jordan river; populated largely by Palestinians. 160 | occupied: held or filled or in use. 161 | Statement understood and added to context. 162 | Presupposition Resolution 163 | A cat is chasing a mouse. 164 | The rodent is scared. 165 | What does the cat chase? 166 | A cat is chasing a mouse. 167 | Found 56 parse trees. 168 | Evaluated 1 interpretation. 169 | Inferred word senses: 170 | cat: feline mammal usually having thick soft fur and no ability to roar: domestic cats; wildcats. 171 | chasing: go after with the intent to catch. 172 | mouse: any of numerous small rodents typically resembling diminutive rats having pointed snouts and small ears on elongated bodies with slender usually hairless tails. 173 | Statement understood and added to context. 174 | The rodent is scared. 175 | Found 1 parse trees. 176 | Evaluated 1 interpretation. 177 | Inferred word senses: 178 | rodent: relatively small placental mammals having a single pair of constantly growing incisor teeth specialized for gnawing. 179 | scared: made afraid. 180 | Statement understood and added to context. 181 | What does the cat chase? 182 | Found 18 parse trees. 183 | Evaluated 1 interpretation. 184 | Inferred word senses: 185 | cat: feline mammal usually having thick soft fur and no ability to roar: domestic cats; wildcats. 186 | chase: go after with the intent to catch. 187 | The frightened mouse. 188 | Possession Unification 189 | An elephant is a large mammal. 190 | It has a snout and tusks. 191 | The ears of the elephant are large. 192 | The animal's hide is grey. 193 | What does the elephant have? 194 | What is gray? 195 | An elephant is a large mammal. 196 | Found 16 parse trees. 197 | Evaluated 1 interpretation. 198 | Inferred word senses: 199 | elephant: five-toed pachyderm. 200 | large: above average in size or number or quantity or magnitude or extent. 201 | mammal: any warm-blooded vertebrate having the skin more or less covered with hair; young are born alive except for the small subclass of monotremes and nourished with milk. 202 | Statement understood and added to context. 203 | It has a snout and tusks. 204 | Found 3 parse trees. 205 | Evaluated 1 interpretation. 206 | Inferred word senses: 207 | has: have ownership or possession of. 208 | snout: a long projecting or anterior elongation of an animal's head; especially the nose. 209 | tusks: a long pointed tooth specialized for fighting or digging; especially in an elephant or walrus or hog. 210 | Statement understood and added to context. 211 | The ears of the elephant are large. 212 | Found 70 parse trees. 213 | Evaluated 1 interpretation. 214 | Inferred word senses: 215 | ears: the sense organ for hearing and equilibrium. 216 | elephant: five-toed pachyderm. 217 | large: above average in size or number or quantity or magnitude or extent. 218 | Statement understood and added to context. 219 | The animal's hide is grey. 220 | Found 16 parse trees. 221 | Evaluated 1 interpretation. 222 | Inferred word senses: 223 | animal: a living organism characterized by voluntary movement. 224 | hide: body covering of a living animal. 225 | grey: of an achromatic color of any lightness intermediate between the extremes of white and black. 226 | Statement understood and added to context. 227 | What does the elephant have? 228 | Found 2 parse trees. 229 | Evaluated 1 interpretation. 230 | Inferred word senses: 231 | elephant: five-toed pachyderm. 232 | have: have ownership or possession of. 233 | The grey hide, the snout, the large ears and the tusks. 234 | -------------------------------------------------------------------------------- /brainstorming/bookmarks.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Bookmarks 7 |

Bookmarks

8 |

9 |

Bookmarks bar

10 |

11 |

NLP

12 |

13 |

NLTK Book 14 |
NLTK Guides 15 |
Discourse Representation Theory (Stanford Encyclopedia of Philosophy) 16 |
Discourse Checking 17 |
Discourse Representation Theory 18 |
Glue Semantics 19 |
Logic & Lambda Calculus 20 |
Logical Inference and Model Building 21 |
Semantics 22 |
From Discourse to Logic 23 |

Compound-Subject

24 |

25 |

svn.ask.it.usyd.edu.au/demo/demo3.cgi?sentence=A+cat+and+a+dog+are+eating+.&printer=graphical&model=a&resolve=yes&submit=Parse+and+Box! 26 |
svn.ask.it.usyd.edu.au/demo/demo3.cgi?sentence=Mary+and+Jack+are+dancing+.&printer=graphical&model=a&resolve=yes&submit=Parse+and+Box! 27 |
svn.ask.it.usyd.edu.au/demo/demo3.cgi?sentence=The+cat+the+dog+are+eating+.&printer=graphical&model=a&resolve=yes&submit=Parse+and+Box! 28 |

29 |

Index of /~julia/jmchapters 30 |
Linda Bryson's List of English Conjunctions 31 |
Conjunctions 32 |
Basic English Sentence Structures - The Predicate 33 |
Basic English Sentence Structures - Interrogative Sentences 34 |
English Grammar - Declarative Sentence Interactive Syntax Worksheet 35 |
Verb Net 36 |
COROLLARY THEOREMS - ENGLISH GRAMMAR: ADVERB 37 |
Adverbs 38 |
NLP Dictionary 39 |
Numbers in English 40 |
VerbNet Reference Page 41 |
Grammar Opt 1 42 |
Grammar Opt 2 43 |
Prover9 Manual 44 |

45 |

46 |

47 | -------------------------------------------------------------------------------- /src/ext/plural.py: -------------------------------------------------------------------------------- 1 | # PLURAL - last updated for NodeBox 1rc7 2 | # Author: Tom De Smedt 3 | # See LICENSE.txt for details. 4 | 5 | # Based on "An Algorithmic Approach to English Pluralization" by Damian Conway: 6 | # http://www.csse.monash.edu.au/~damian/papers/HTML/Plurals.html 7 | 8 | # Prepositions are used to solve things like 9 | # "mother-in-law" or "man at arms" 10 | plural_prepositions = ["about", "above", "across", "after", "among", "around", "at", "athwart", "before", "behind", "below", "beneath", "beside", "besides", "between", "betwixt", "beyond", "but", "by", "during", "except", "for", "from", "in", "into", "near", "of", "off", "on", "onto", "out", "over", "since", "till", "to", "under", "until", "unto", "upon", "with"] 11 | 12 | # Inflection rules that are either general, 13 | # or apply to a certain category of words, 14 | # or apply to a certain category of words only in classical mode, 15 | # or apply only in classical mode. 16 | 17 | # Each rule consists of: 18 | # suffix, inflection, category and classic flag. 19 | 20 | plural_rules = [ 21 | 22 | # 0/ Indefinite articles and demonstratives. 23 | [ 24 | ["^a$|^an$", "some", None, False], 25 | ["^this$", "these", None, False], 26 | ["^that$", "those", None, False], 27 | ["^any$", "all", None, False] 28 | ], 29 | 30 | # 1/ Possessive adjectives. 31 | # Overlaps with 1/ for "his" and "its". 32 | # Overlaps with 2/ for "her". 33 | [ 34 | ["^my$", "our", None, False], 35 | ["^your$|^thy$", "your", None, False], 36 | ["^her$|^his$|^its$|^their$", "their", None, False] 37 | ], 38 | 39 | # 2/ 40 | # Possessive pronouns. 41 | [ 42 | ["^mine$", "ours", None, False], 43 | ["^yours$|^thine$", "yours", None, False], 44 | ["^hers$|^his$|^its$|^theirs$", "theirs", None, False] 45 | ], 46 | 47 | # 3/ 48 | # Personal pronouns. 49 | [ 50 | ["^I$", "we", None, False], 51 | ["^me$", "us", None, False], 52 | ["^myself$", "ourselves", None, False], 53 | ["^you$", "you", None, False], 54 | ["^thou$|^thee$", "ye", None, False], 55 | ["^yourself$|^thyself$", "yourself", None, False], 56 | ["^she$|^he$|^it$|^they$", "they", None, False], 57 | ["^her$|^him$|^it$|^them$", "them", None, False], 58 | ["^herself$|^himself$|^itself$|^themself$", "themselves", None, False], 59 | ["^oneself$", "oneselves", None, False] 60 | ], 61 | 62 | # 4/ 63 | # Words that do not inflect. 64 | [ 65 | ["$", "", "uninflected", False], 66 | ["$", "", "uncountable", False], 67 | ["s$", "s", "s-singular", False], 68 | ["fish$", "fish", None, False], 69 | ["([- ])bass$", "\\1bass", None, False], 70 | ["ois$", "ois", None, False], 71 | ["sheep$", "sheep", None, False], 72 | ["deer$", "deer", None, False], 73 | ["pox$", "pox", None, False], 74 | ["([A-Z].*)ese$", "\\1ese", None, False], 75 | ["itis$", "itis", None, False], 76 | ["(fruct|gluc|galact|lact|ket|malt|rib|sacchar|cellul)ose$", "\\1ose", None, False] 77 | ], 78 | 79 | # 5/ 80 | # Irregular plurals. 81 | # (mongoose, oxen). 82 | [ 83 | ["atlas$", "atlantes", None, True], 84 | ["atlas$", "atlases", None, False], 85 | ["beef$", "beeves", None, True], 86 | ["brother$", "brethren", None, True], 87 | ["child$", "children", None, False], 88 | ["corpus$", "corpora", None, True], 89 | ["corpus$", "corpuses", None, False], 90 | ["^cow$", "kine", None, True], 91 | ["ephemeris$", "ephemerides", None, False], 92 | ["ganglion$", "ganglia", None, True], 93 | ["genie$", "genii", None, True], 94 | ["genus$", "genera", None, False], 95 | ["graffito$", "graffiti", None, False], 96 | ["loaf$", "loaves", None, False], 97 | ["money$", "monies", None, True], 98 | ["mongoose$", "mongooses", None, False], 99 | ["mythos$", "mythoi", None, False], 100 | ["octopus$", "octopodes", None, True], 101 | ["opus$", "opera", None, True], 102 | ["opus$", "opuses", None, False], 103 | ["^ox$", "oxen", None, False], 104 | ["penis$", "penes", None, True], 105 | ["penis$", "penises", None, False], 106 | ["soliloquy$", "soliloquies", None, False], 107 | ["testis$", "testes", None, False], 108 | ["trilby$", "trilbys", None, False], 109 | ["turf$", "turves", None, True], 110 | ["numen$", "numena", None, False], 111 | ["occiput$", "occipita", None, True], 112 | ], 113 | 114 | # 6/ 115 | # Irregular inflections for common suffixes 116 | # (synopses, mice, men). 117 | [ 118 | ["man$", "men", None, False], 119 | ["person$", "people", None, False], 120 | ["([lm])ouse$", "\\1ice", None, False], 121 | ["tooth$", "teeth", None, False], 122 | ["goose$", "geese", None, False], 123 | ["foot$", "feet", None, False], 124 | ["zoon$", "zoa", None, False], 125 | ["([csx])is$", "\\1es", None, False] 126 | ], 127 | 128 | # 7/ 129 | # Fully assimilated classical inflections 130 | # (vertebrae, codices). 131 | [ 132 | ["ex$", "ices", "ex-ices", False], 133 | ["ex$", "ices", "ex-ices-classical", True], 134 | ["um$", "a", "um-a", False], 135 | ["um$", "a", "um-a-classical", True], 136 | ["on$", "a", "on-a", False], 137 | ["a$", "ae", "a-ae", False], 138 | ["a$", "ae", "a-ae-classical", True] 139 | ], 140 | 141 | # 8/ 142 | # Classical variants of modern inflections 143 | # (stigmata, soprani). 144 | [ 145 | ["trix$", "trices", None, True], 146 | ["eau$", "eaux", None, True], 147 | ["ieu$", "ieu", None, True], 148 | ["([iay])nx$", "\\1nges", None, True], 149 | ["en$", "ina", "en-ina-classical", True], 150 | ["a$", "ata", "a-ata-classical", True], 151 | ["is$", "ides", "is-ides-classical", True], 152 | ["us$", "i", "us-i-classical", True], 153 | ["us$", "us", "us-us-classical", True], 154 | ["o$", "i", "o-i-classical", True], 155 | ["$", "i", "-i-classical", True], 156 | ["$", "im", "-im-classical", True] 157 | ], 158 | 159 | # 9/ 160 | # -ch, -sh and -ss take -es in the plural 161 | # (churches, classes). 162 | [ 163 | ["([cs])h$", "\\1hes", None, False], 164 | ["ss$", "sses", None, False], 165 | ["x$", "xes", None, False] 166 | ], 167 | 168 | # 10/ 169 | # Certain words ending in -f or -fe take -ves in the plural 170 | # (lives, wolves). 171 | [ 172 | ["([aeo]l)f$", "\\1ves", None, False], 173 | ["([^d]ea)f$", "\\1ves", None, False], 174 | ["arf$", "arves", None, False], 175 | ["([nlw]i)fe$", "\\1ves", None, False], 176 | ], 177 | 178 | # 11/ 179 | # -y takes -ys if preceded by a vowel, 180 | # or when a proper noun, 181 | # but -ies if preceded by a consonant 182 | # (storeys, Marys, stories). 183 | [ 184 | ["([aeiou])y$", "\\1ys", None, False], 185 | ["([A-Z].*)y$", "\\1ys", None, False], 186 | ["y$", "ies", None, False] 187 | ], 188 | 189 | # 12/ 190 | # Some words ending in -o take -os, 191 | # the rest take -oes. 192 | # Words in which the -o is preceded by a vowel always take -os 193 | # (lassos, potatoes, bamboos). 194 | [ 195 | ["o$", "os", "o-os", False], 196 | ["([aeiou])o$", "\\1os", None, False], 197 | ["o$", "oes", None, False] 198 | ], 199 | 200 | # 13/ 201 | # Miltary stuff (Major Generals). 202 | [ 203 | ["l$", "ls", "general-generals", False] 204 | ], 205 | 206 | # 14/ 207 | # Otherwise, assume that the plural just adds -s 208 | # (cats, programmes). 209 | [ 210 | ["$", "s", None, False] 211 | ], 212 | ] 213 | 214 | # Suffix categories 215 | 216 | plural_categories = { 217 | 218 | "uninflected" : ["bison", "bream", "breeches", "britches", "carp", "chassis", "clippers", "cod", "contretemps", "corps", "debris", "diabetes", "djinn", "eland", "elk", "flounder", "gallows", "graffiti", "headquarters", "herpes", "high-jinks", "homework", "innings", "jackanapes", "mackerel", "measles", "mews", "mumps", "news", "pincers", "pliers", "proceedings", "rabies", "salmon", "scissors", "series", "shears", "species", "swine", "trout", "tuna", "whiting", "wildebeest"], 219 | "uncountable" : ["advice", "bread", "butter", "cheese", "electricity", "equipment", "fruit", "furniture", "garbage", "gravel", "happiness", "information", "ketchup", "knowledge", "love", "luggage", "mathematics", "mayonnaise", "meat", "mustard", "news", "progress", "research", "rice", "sand", "software", "understanding", "water"], 220 | "s-singular" : ["acropolis", "aegis", "alias", "asbestos", "bathos", "bias", "caddis", "cannabis", "canvas", "chaos", "cosmos", "dais", "digitalis", "epidermis", "ethos", "gas", "glottis", "glottis", "ibis", "lens", "mantis", "marquis", "metropolis", "pathos", "pelvis", "polis", "rhinoceros", "sassafras", "trellis"], 221 | 222 | "ex-ices" : ["codex", "murex", "silex"], 223 | "ex-ices-classical" : ["apex", "cortex", "index", "latex", "pontifex", "simplex", "vertex", "vortex"], 224 | "um-a" : ["agendum", "bacterium", "candelabrum", "datum", "desideratum", "erratum", "extremum", "ovum", "stratum"], 225 | "um-a-classical" : ["aquarium", "compendium", "consortium", "cranium", "curriculum", "dictum", "emporium", "enconium", "gymnasium", "honorarium", "interregnum", "lustrum", "maximum", "medium", "memorandum", "millenium", "minimum", "momentum", "optimum", "phylum", "quantum", "rostrum", "spectrum", "speculum", "stadium", "trapezium", "ultimatum", "vacuum", "velum"], 226 | "on-a" : ["aphelion", "asyndeton", "criterion", "hyperbaton", "noumenon", "organon", "perihelion", "phenomenon", "prolegomenon"], 227 | "a-ae" : ["alga", "alumna", "vertebra"], 228 | "a-ae-classical" : ["abscissa", "amoeba", "antenna", "aurora", "formula", "hydra", "hyperbola", "lacuna", "medusa", "nebula", "nova", "parabola"], 229 | 230 | "en-ina-classical" : ["foramen", "lumen", "stamen"], 231 | "a-ata-classical" : ["anathema", "bema", "carcinoma", "charisma", "diploma", "dogma", "drama", "edema", "enema", "enigma", "gumma", "lemma", "lymphoma", "magma", "melisma", "miasma", "oedema", "sarcoma", "schema", "soma", "stigma", "stoma", "trauma"], 232 | "is-ides-classical" : ["clitoris", "iris"], 233 | "us-i-classical" : ["focus", "fungus", "genius", "incubus", "nimbus", "nucleolus", "radius", "stylus", "succubus", "torus", "umbilicus", "uterus"], 234 | "us-us-classical" : ["apparatus", "cantus", "coitus", "hiatus", "impetus", "nexus", "plexus", "prospectus", "sinus", "status"], 235 | "o-i-classical" : ["alto", "basso", "canto", "contralto", "crescendo", "solo", "soprano", "tempo"], 236 | "-i-classical" : ["afreet", "afrit", "efreet"], 237 | "-im-classical" : ["cherub", "goy", "seraph"], 238 | 239 | "o-os" : ["albino", "archipelago", "armadillo", "commando", "ditto", "dynamo", "embryo", "fiasco", "generalissimo", "ghetto", "guano", "inferno", "jumbo", "lingo", "lumbago", "magneto", "manifesto", "medico", "octavo", "photo", "pro", "quarto", "rhino", "stylo"], 240 | 241 | "general-generals" : ["Adjutant", "Brigadier", "Lieutenant", "Major", "Quartermaster", 242 | "adjutant", "brigadier", "lieutenant", "major", "quartermaster"], 243 | 244 | } 245 | 246 | NOUN = "noun" 247 | ADJECTIVE = "adjective" 248 | 249 | def plural(word, pos=NOUN, classical=True, custom={}): 250 | 251 | """ Returns the plural of a given word. 252 | 253 | For example: child -> children. 254 | Handles nouns and adjectives, using classical inflection by default 255 | (e.g. where "matrix" pluralizes to "matrices" instead of "matrixes". 256 | The custom dictionary is for user-defined replacements. 257 | 258 | """ 259 | 260 | if word in custom.keys(): 261 | return custom[word] 262 | 263 | # Recursion of genitives 264 | # remove the apostrophe and any trailing -s, 265 | # form the plural of the resultant noun, and then append an apostrophe. 266 | # (dog's -> dogs') 267 | if (len(word) > 0 and word[-1] == ",") or \ 268 | (len(word) > 1 and word[-2:] == "'s"): 269 | owner = word.rstrip("'s") 270 | owners = plural(owner, classical, custom) 271 | if owners[-1] == "s": 272 | return owners + "'" 273 | else: 274 | return owners + "'s" 275 | 276 | # Recursion of compound words 277 | # (Postmasters General, mothers-in-law, Roman deities). 278 | words = word.replace("-", " ").split(" ") 279 | if len(words) > 1: 280 | if words[1] == "general" or words[1] == "General" and \ 281 | words[0] not in categories["general-generals"]: 282 | return word.replace(words[0], plural(words[0], classical, custom)) 283 | elif words[1] in plural_prepositions: 284 | return word.replace(words[0], plural(words[0], classical, custom)) 285 | else: 286 | return word.replace(words[-1], plural(words[-1], classical, custom)) 287 | 288 | # Only a very few number of adjectives inflect. 289 | n = range(len(plural_rules)) 290 | if pos == ADJECTIVE: 291 | n = [0, 1] 292 | 293 | import re 294 | for i in n: 295 | ruleset = plural_rules[i] 296 | for rule in ruleset: 297 | suffix, inflection, category, classic = rule 298 | 299 | # A general rule, 300 | # or a classic rule in classical mode. 301 | if category == None: 302 | if not classic or (classic and classical): 303 | if re.search(suffix, word) is not None: 304 | return re.sub(suffix, inflection, word) 305 | 306 | # A rule relating to a specific category of words 307 | if category != None: 308 | if word in plural_categories[category] and (not classic or (classic and classical)): 309 | if re.search(suffix, word) is not None: 310 | return re.sub(suffix, inflection, word) 311 | 312 | return word 313 | 314 | #print plural("part-of-speech") 315 | #print plural("child") 316 | #print plural("dog's") 317 | #print plural("wolf") 318 | #print plural("bear") 319 | #print plural("kitchen knife") 320 | #print plural("octopus", classical=True) 321 | #print plural("matrix", classical=True) 322 | #print plural("matrix", classical=False) 323 | #print plural("my", pos=ADJECTIVE) 324 | 325 | def noun_plural(word, classical=True, custom={}): 326 | return plural(word, NOUN, classical, custom) 327 | 328 | def adjective_plural(word, classical=True, custom={}): 329 | return plural(word, ADJECTIVE, classical, custom) -------------------------------------------------------------------------------- /src/grammar/base_rules.fcfg: -------------------------------------------------------------------------------- 1 | % start S 2 | 3 | ################################################################################ 4 | # Declarative Sentences # 5 | ################################################################################ 6 | 7 | # Jack dances 8 | S[TYP=dcl,RUL=1] -> NP[CASE=sbj,NUM=?n,PER=?p] VP[NUM=?n,PER=?p,TENS=r] 9 | # S[TYP=dcl,RUL=1] -> NP[CASE=sbj,NUM=?n,PER=?p] VP[NUM=?n,PER=?p,TENS=rc] 10 | # S[TYP=dcl,RUL=1] -> NP[CASE=sbj,NUM=?n,PER=?p] VP[NUM=?n,PER=?p,TENS=rp] 11 | # S[TYP=dcl,RUL=1] -> NP[CASE=sbj,NUM=?n,PER=?p] VP[NUM=?n,PER=?p,TENS=p] 12 | # [Jack dances] . 13 | S[TYP=dcl,RUL=2,+sealed] -> S[TYP=dcl,-sealed] Pnct[TYP=end] 14 | 15 | # If [Jack is happy] , [he dances] 16 | S[TYP=dcl,RUL=3] -> Cond S[TYP=dcl] Pnct[TYP=com] S[TYP=dcl] 17 | # If [Jack is tired] then [he should sleep] 18 | S[TYP=dcl,RUL=3] -> Cond S[TYP=dcl] 'then' S[TYP=dcl] 19 | # [I will go] if [you go] 20 | S[TYP=dcl,RUL=4] -> S[TYP=dcl] Cond S[TYP=dcl] 21 | 22 | # [John ran] and [Jack chased] 23 | S[TYP=dcl,RUL=5] -> S[TYP=dcl,-sealed] Cnj[-compound,+s] S[TYP=dcl,-sealed] 24 | # either [John ran] or [Jack chased] 25 | S[TYP=dcl,RUL=6] -> Cnj[GRP=?g,+compound,+init] S[TYP=dcl,-sealed] Cnj[GRP=?g,+compound,-init] S[TYP=dcl,-sealed] 26 | 27 | ################################################################################ 28 | # Yes/No Questions # 29 | ################################################################################ 30 | 31 | # [Jack dances] ? 32 | S[RUL=7,+sealed] -> S[-sealed] Pnct[TYP=qst] 33 | # Is Jack [in the room] 34 | S[TYP=ynq,RUL=8] -> AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] PRED 35 | # S[TYP=ynq,RUL=8] -> AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] PRED 36 | # Is Jack not [in the room] 37 | S[TYP=ynq,RUL=9] -> AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] 'not' PRED 38 | # S[TYP=ynq,RUL=9] -> AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] 'not' PRED 39 | # Does Jack dance salsa 40 | S[TYP=ynq,RUL=10] -> AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VP[TENS=i] 41 | # S[TYP=ynq,RUL=10] -> AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] VP[TENS=g] 42 | # S[TYP=ynq,RUL=10] -> AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=have] NP[CASE=sbj,NUM=?n,PER=?p] VP[TENS=ip] 43 | # S[TYP=ynq,RUL=10] -> AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VP[TENS=i] 44 | 45 | ################################################################################ 46 | # Subject Questions # 47 | ################################################################################ 48 | 49 | # Who [gave Lara the books] 50 | S[TYP=whq,RUL=11] -> Q[+sbj] VP[NUM=sg,PER=3] 51 | # Who [are they] 52 | S[TYP=whq,RUL=11] -> Q[+sbj] VP[+be] 53 | 54 | ################################################################################ 55 | # Object Questions # 56 | ################################################################################ 57 | 58 | # What does Alice [give Lara] 59 | S[TYP=whq,RUL=12] -> Q AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=NONE] 60 | # S[TYP=whq,RUL=12] -> Q AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=g,PTCL=NONE] 61 | # S[TYP=whq,RUL=12] -> Q AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=have] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=ip,PTCL=NONE] 62 | # S[TYP=whq,RUL=12] -> Q AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=NONE] 63 | 64 | # [Regarding what] does Alice [call James] 65 | S[TYP=whq,RUL=13] -> QM[PTCL=?pc] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=?pc] 66 | # S[TYP=whq,RUL=13] -> QM[PTCL=?pc] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=g,PTCL=?pc] 67 | # S[TYP=whq,RUL=13] -> QM[PTCL=?pc] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=have] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=ip,PTCL=?pc] 68 | # S[TYP=whq,RUL=13] -> QM[PTCL=?pc] AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=?pc] 69 | 70 | # [To whom] does Alice [give the book] 71 | S[TYP=whq,RUL=13] -> QM[PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] 72 | # S[TYP=whq,RUL=13] -> QM[PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=g,PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] 73 | # S[TYP=whq,RUL=13] -> QM[PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=have] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=ip,PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] 74 | # S[TYP=whq,RUL=13] -> QM[PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=do] NP[CASE=sbj,NUM=?n,PER=?p] VPQ[TENS=i,PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] 75 | 76 | ################################################################################ 77 | # Prepositional Phrase Questions # 78 | ################################################################################ 79 | 80 | # Where is Laura 81 | # S[TYP=whq,RUL=14] -> 'where' AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] 82 | # S[TYP=whq,RUL=14] -> 'where' AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] 'being' 83 | # S[TYP=whq,RUL=14] -> 'where' AuxV[SEM=pos,TENS=r,NUM=?n,PER=?p,TYP=have] NP[CASE=sbj,NUM=?n,PER=?p] 'been' 84 | # S[TYP=whq,RUL=14] -> 'where' AuxV[SEM=pos,TENS=p,NUM=?n,PER=?p,TYP=be] NP[CASE=sbj,NUM=?n,PER=?p] 85 | 86 | ################################################################################ 87 | # Verb Phrases # 88 | ################################################################################ 89 | 90 | # [a pretty girl] 91 | PRED -> NP[CASE=obj] 92 | # pretty 93 | PRED -> Adj[DEG=pos] 94 | # prettier than Alice 95 | PRED -> Adj[DEG=cmp] 'than' NP[CASE=obj] 96 | # in the theater 97 | PRED -> PP 98 | 99 | # is [a pretty girl] 100 | VP[NUM=?n,PER=?p,TENS=?t,+be] -> CV[PTRN=-1,NUM=?n,PER=?p,TENS=?t] PRED 101 | 102 | # [arrived at the station] and [didn't go away] 103 | VP[TENS=?t,PER=?p,NUM=?n,RUL=801] -> VP[TENS=?t,PER=?p,NUM=?n] Cnj[-compound,+vp] VP[TENS=?t,PER=?p,NUM=?n] 104 | # both [insulted him] and [kicked his dog] 105 | VP[TENS=?t,PER=?p,NUM=?n,RUL=802] -> Cnj[GRP=?g,+compound,+init,+vp] VP[TENS=?t,PER=?p,NUM=?n] Cnj[GRP=?g,+compound,-init,+vp] VP[TENS=?t,PER=?p,NUM=?n] 106 | 107 | ################################################################################ 108 | # Prepositional Phrases # 109 | ################################################################################ 110 | 111 | # in [the grand hall] 112 | PP[TYP=?t,RUL=201] -> Prep[TYP=?t,+generic] NP[CASE=obj] 113 | # in [the grand hall] 114 | PP[TYP=?t,RUL=202,+negated] -> 'not' PP[TYP=?t,-negated] 115 | # [in the house] or [in the yard] 116 | PP[TYP=?t,RUL=203] -> PP[TYP=?t] Cnj[-compound,+pp] PP[TYP=?t] 117 | # both [in the room] and [in the yard] 118 | PP[TYP=?t,RUL=204] -> Cnj[GRP=?g,+compound,+init,+pp] PP[TYP=?t] Cnj[GRP=?g,+compound,-init,+pp] PP[TYP=?t] 119 | 120 | ################################################################################ 121 | # Noun Phrases # 122 | ################################################################################ 123 | 124 | # Eventually should support: 125 | # NP -> (DT) (Cardinal) (Ordinal) (Quantifier) (AdjPhrase) Nom 126 | 127 | # he 128 | NP[NUM=?n,CASE=sbj,PER=?p,RUL=301] -> Pro[NUM=?n,CASE=sbj,PER=?p] 129 | # him 130 | NP[NUM=?n,CASE=obj,PER=?p,RUL=302] -> Pro[NUM=?n,CASE=obj,PER=?p] 131 | # himself 132 | NP[NUM=?n,PER=3,RUL=303] -> Pro[NUM=?n,CASE=rflx] 133 | # ours 134 | NP[NUM=?n,CASE=obj,PER=?p,RUL=304] -> Pro[NUM=?n,CASE=poss_pred,PER=?p] 135 | # roads 136 | NP[NUM=pl,PER=3,RUL=305] -> Noun[NUM=pl] 137 | # busy roads 138 | NP[NUM=ms,PER=3,RUL=306] -> AJP Noun[NUM=pl] 139 | # water 140 | NP[NUM=ms,PER=3,RUL=307] -> Noun[NUM=ms] 141 | # cold water 142 | NP[NUM=ms,PER=3,RUL=308] -> AJP Noun[NUM=ms] 143 | # this road 144 | NP[NUM=?n,PER=3,RUL=309] -> DT[NUM=?n] Noun[NUM=?n] 145 | # Mary 146 | NP[NUM=?n,PER=3,RUL=310] -> PN[NUM=?n] 147 | # a [beautiful golden] locket 148 | NP[NUM=?n,PER=3,RUL=311] -> DT[NUM=?n] AJP Noun[NUM=?n] 149 | # the great Caesar 150 | NP[NUM=sg,PER=3,RUL=312] -> DT[NUM=sg,+definite] AJP PN[NUM=sg] 151 | # the Colosseum 152 | NP[NUM=sg,PER=3,RUL=313] -> DT[NUM=sg,+definite] PN[NUM=sg,SEX=n] 153 | # the best 154 | NP[PER=3,RUL=314] -> Art[+definite] Adj[DEG=sup] 155 | 156 | # [the dog] and [a cat] 157 | NP[NUM=pl,PER=3,CASE=?c,RUL=315] -> NP[CASE=?c] Cnj[-compound,+np] NP[CASE=?c] 158 | # neither [the dog] nor [the cat] 159 | NP[NUM=pl,PER=3,CASE=?c,RUL=316] -> Cnj[GRP=?g,+compound,+init,+np] NP[CASE=?c] Cnj[GRP=?g,+compound,-init,+np] NP[CASE=?c] 160 | 161 | # [the cat] [in the hat] 162 | NP[NUM=?n,CASE=?c,PER=?p,RUL=317] -> NP[NUM=?n,CASE=?c,PER=?p] PP 163 | 164 | # brain damage 165 | Noun[NUM=?n,FRQ=-5,RUL=318] -> Noun Noun[NUM=?n] 166 | 167 | 168 | ################################################################################ 169 | # Proper Nouns # 170 | ################################################################################ 171 | 172 | # Mr Murphy 173 | PN[NUM=?n,SEX=?s,RUL=601] -> Ttl[NUM=?n,SEX=?s] PrpN[NUM=?n,SEX=?s] 174 | # Mary 175 | PN[NUM=?n,SEX=?s,RUL=602] -> PrpN[NUM=?n,SEX=?s] 176 | 177 | ################################################################################ 178 | # Determiners # 179 | ################################################################################ 180 | 181 | # the 182 | DT[NUM=?n,RUL=401,definite=?d,-poss] -> Art[NUM=?n,definite=?d] 183 | # this 184 | DT[NUM=?n,RUL=402,-poss] -> Det[NUM=?n,DETTYP=dem] 185 | # some 186 | DT[NUM=?n,RUL=403,-poss] -> Det[NUM=?n,DETTYP=exst] 187 | # another 188 | DT[NUM=?n,RUL=404,-poss] -> Det[NUM=?n,DETTYP=alt] 189 | # most 190 | DT[NUM=?n,RUL=405,-poss] -> Det[NUM=?n,DETTYP=deg] 191 | # every 192 | DT[NUM=?n,RUL=406,-poss] -> Det[NUM=?n,DETTYP=unvrs] 193 | # no 194 | DT[NUM=?n,RUL=407,-poss] -> Det[NUM=?n,DETTYP=neg] 195 | # my 196 | DT[NUM=sg,RUL=408,+poss] -> Pro[CASE=poss_det] 197 | DT[NUM=pl,RUL=408,+poss] -> Pro[CASE=poss_det] 198 | DT[NUM=ms,RUL=408,+poss] -> Pro[CASE=poss_det] 199 | # [the man]'s 200 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=sg] "'s" 201 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=sg] "'" 202 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=ms] "'s" 203 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=ms] "'" 204 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=pl] "'s" 205 | DT[NUM=sg,RUL=409,+poss] -> NP[NUM=pl] "'" 206 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=sg] "'s" 207 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=sg] "'" 208 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=ms] "'s" 209 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=ms] "'" 210 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=pl] "'s" 211 | DT[NUM=pl,RUL=409,+poss] -> NP[NUM=pl] "'" 212 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=sg] "'s" 213 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=sg] "'" 214 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=ms] "'s" 215 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=ms] "'" 216 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=pl] "'s" 217 | DT[NUM=ms,RUL=409,+poss] -> NP[NUM=pl] "'" 218 | 219 | # [his] and [Mary's] 220 | DT[NUM=?n,RUL=410,+poss] -> DT[NUM=?n,+poss] Cnj[-compound,+dt] DT[NUM=?n,+poss] 221 | # neither [Jack's] nor [her] 222 | DT[NUM=?n,RUL=411,+poss] -> Cnj[GRP=?g,+compound,+init,+dt] DT[NUM=?n,+poss] Cnj[GRP=?g,+compound,-init,+dt] DT[NUM=?n,+poss] 223 | 224 | ################################################################################ 225 | # Adjective Phrases # 226 | ################################################################################ 227 | 228 | # great [black leather-bound] 229 | AJP[RUL=501] -> Adj AJP 230 | # great 231 | AJP[RUL=502] -> Adj 232 | 233 | # [thick blue] and [thin red] 234 | AJP[RUL=503] -> AJP Cnj[-compound,+ajp] AJP 235 | # Both [thick blue] and [thin red] 236 | AJP[RUL=504] -> Cnj[GRP=?g,+compound,+init,+ajp] AJP Cnj[GRP=?g,+compound,-init,+ajp] AJP 237 | 238 | # [sad] but [lively] 239 | Adj[DEG=?d,RUL=505] -> Adj[DEG=?d] Cnj[-compound,+adj] Adj[DEG=?d] 240 | # either [green] or [red] 241 | Adj[DEG=?d,RUL=506] -> Cnj[GRP=?g,+compound,+init,+adj] Adj[DEG=?d] Cnj[GRP=?g,+compound,-init,+adj] Adj[DEG=?d] 242 | 243 | # more intricate 244 | Adj[DEG=cmp,SNS=?s] -> 'more' Adj[DEG=pos,SNS=?s,+std] 245 | # most excellent 246 | Adj[DEG=sup,SNS=?s] -> 'most' Adj[DEG=pos,SNS=?s,+std] 247 | 248 | ################################################################################ 249 | # Verb Conjugation # 250 | ################################################################################ 251 | 252 | # Infinitive 253 | CV[SEM=pos,TENS=i,PTRN=?t] -> Verb[FORM=inf,PTRN=?t] 254 | CV[SEM=neg,TENS=i,PTRN=?t] -> "not" Verb[FORM=inf,PTRN=?t] 255 | 256 | # Gerundive 257 | CV[SEM=pos,TENS=g,PTRN=?t] -> Verb[FORM=ger,PTRN=?t] 258 | CV[SEM=neg,TENS=g,PTRN=?t] -> "not" Verb[FORM=ger,PTRN=?t] 259 | 260 | # Participle 261 | CV[SEM=pos,TENS=ip,PTRN=?t] -> Verb[FORM=pp,PTRN=?t] 262 | CV[SEM=neg,TENS=ip,PTRN=?t] -> "not" Verb[FORM=pp,PTRN=?t] 263 | 264 | # Present 265 | CV[SEM=pos,TENS=r,PTRN=?t] -> Verb[FORM=inf,PTRN=?t] 266 | CV[SEM=pos,TENS=r,PER=3,NUM=sg,PTRN=?t] -> Verb[FORM=tps,PTRN=?t] 267 | CV[SEM=pos,TENS=r,PER=3,NUM=ms,PTRN=?t] -> Verb[FORM=tps,PTRN=?t] 268 | CV[SEM=neg,TENS=r,PER=?p,NUM=?n,PTRN=?t] -> AuxV[SEM=neg,TENS=r,PER=?p,NUM=?n,TYP=do] Verb[FORM=inf,PTRN=?t] 269 | # TODO: Take care of the 991/-1 confusion. 270 | CV[SEM=?s,TENS=r,PER=?p,NUM=?n,PTRN=991] -> AuxV[SEM=?s,TENS=r,PER=?p,NUM=?n,TYP=be] 271 | 272 | # Present Continuous 273 | CV[SEM=?s,TENS=rc,PER=?p,NUM=?n,PTRN=?t] -> AuxV[SEM=?s,TENS=r,PER=?p,NUM=?n,TYP=be] Verb[FORM=ger,PTRN=?t] 274 | 275 | # Present Perfect 276 | CV[SEM=?s,TENS=rp,PER=?p,NUM=?n,PTRN=?t] -> AuxV[SEM=?s,TENS=r,PER=?p,NUM=?n,TYP=have] Verb[FORM=pp,PTRN=?t] 277 | 278 | # Past 279 | CV[SEM=pos,TENS=p,PTRN=?t] -> Verb[FORM=pret,PTRN=?t] 280 | CV[SEM=neg,TENS=p,PTRN=?t] -> AuxV[SEM=neg,TENS=p,TYP=do] Verb[FORM=inf,PTRN=?t] 281 | # TODO: Take care of the 991/-1 confusion. 282 | CV[SEM=?s,TENS=p,PER=?p,NUM=?n,PTRN=991] -> AuxV[SEM=?s,TENS=p,PER=?p,NUM=?n,TYP=be] 283 | 284 | # Conjuncted 285 | # [danced] but [didn't laugh] 286 | CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt,FRQ=1,RUL=701] -> CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt] Cnj[-compound,+cv] CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt] 287 | # both [insulted] and [assaulted] 288 | CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt,FRQ=1,RUL=702] -> Cnj[GRP=?g,+compound,+init,+cv] CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt] Cnj[GRP=?g,+compound,-init,+cv] CV[TENS=?t,PER=?p,NUM=?n,PTRN=?pt] 289 | 290 | ################################################################################ 291 | # Question Pro-forms # 292 | ################################################################################ 293 | 294 | # what 295 | Q[+sbj,RUL=901] -> 'what' 296 | Q[+sbj,RUL=901] -> 'who' 297 | Q[-sbj,RUL=901] -> 'whom' 298 | # which book 299 | Q[+sbj,RUL=902] -> 'what' Noun 300 | Q[+sbj,RUL=902] -> 'which' Noun 301 | # which blue book 302 | Q[+sbj,RUL=903] -> 'what' AJP Noun 303 | Q[+sbj,RUL=903] -> 'which' AJP Noun 304 | # whose book 305 | Q[+sbj,RUL=904] -> 'whose' Noun 306 | # whose blue book 307 | Q[+sbj,RUL=905] -> 'whose' AJP Noun 308 | 309 | # concerning what 310 | QM[PTCL=?p] -> Particle[PTCL=?p] Q 311 | # in what 312 | QM[PTCL=PREP,path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] -> Prep[path=?x1,dest=?x2,dest_conf=?x3,dir=?x4,src=?x5,loc=?x6] Q 313 | -------------------------------------------------------------------------------- /src/drt/drs.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import copy 3 | import re 4 | 5 | 6 | class FormulationError(Exception): pass 7 | 8 | 9 | VERB_TYPE = 'e' 10 | SINGULAR_TYPE = 's' 11 | PLURAL_TYPE = 'p' 12 | MASS_TYPE = 'm' 13 | 14 | 15 | class Referent(object): 16 | ref_index = 1 17 | 18 | def __init__(self, type=SINGULAR_TYPE): 19 | # Prover9 treats u-z as vars, not consts as we want them. 20 | assert type not in ('u', 'v', 'w', 'x', 'y', 'z') 21 | self.type = type 22 | self.index = self.__class__.ref_index 23 | self.__class__.ref_index += 1 24 | 25 | def __repr__(self): 26 | return self.id 27 | 28 | @property 29 | def id(self): 30 | return '%s%d' % (self.type, self.index) 31 | 32 | 33 | class NamedReferent(Referent): 34 | 35 | def __init__(self, name): 36 | self.type = SINGULAR_TYPE 37 | self.name = name 38 | 39 | def __eq__(self, other): 40 | return self.id == other.id 41 | 42 | def __ne__(self, other): 43 | return self.id != other.id 44 | 45 | def __hash__(self): 46 | return hash((NamedReferent, self.id)) 47 | 48 | def Pretty(self): 49 | return self.id[2:].replace('_', ' ') 50 | 51 | @property 52 | def id(self): 53 | return self.type + '_' + self.name 54 | 55 | 56 | class Condition(object): 57 | def __ne__(self, other): 58 | return not (self == other) 59 | 60 | @property 61 | def summary(self): 62 | return repr(self) 63 | 64 | def Copy(self): 65 | return copy.copy(self) 66 | 67 | def GetChildDRSs(self): 68 | return () 69 | 70 | def GetAccessibleReferents(self, _=None): 71 | return self.parent.GetAccessibleReferents() 72 | 73 | 74 | class PredicateCondition(Condition): 75 | def __init__(self, predicate, *args, **kwds): 76 | self.predicate = predicate 77 | self.args = args 78 | self.parent = None 79 | self.informative = kwds.get('informative', True) 80 | 81 | def __repr__(self): 82 | args = ', '.join(str(i) for i in self.args) 83 | return '%s(%s)' % (self.predicate, args) 84 | 85 | def __eq__(self, other): 86 | return (isinstance(other, self.__class__) and 87 | self.predicate == other.predicate and 88 | self.args == other.args) 89 | 90 | def __hash__(self): 91 | return hash((PredicateCondition, self.predicate, self.args)) 92 | 93 | def Formulate(self): 94 | return re.sub('[\'"/-]', '__', repr(self).replace('.', '_')) 95 | 96 | def ReplaceReferent(self, old, new, add_new): 97 | new_args = [] 98 | for arg in self.args: 99 | new_args.append(new if arg == old else arg) 100 | self.args = tuple(new_args) 101 | return add_new 102 | 103 | 104 | class EqualityCondition(Condition): 105 | def __init__(self, referent1, referent2, informative=True): 106 | self.ref1 = referent1 107 | self.ref2 = referent2 108 | self.parent = None 109 | self.informative = informative 110 | 111 | def __repr__(self): 112 | return '(%s = %s)' % (self.ref1, self.ref2) 113 | 114 | def __eq__(self, other): 115 | return (isinstance(other, self.__class__) and 116 | ((self.ref1 == other.ref1 and self.ref2 == other.ref2) or 117 | (self.ref1 == other.ref2 and self.ref2 == other.ref1))) 118 | 119 | def __hash__(self): 120 | return hash((EqualityCondition, self.ref1, self.ref2)) 121 | 122 | def Formulate(self): 123 | return str(self) 124 | 125 | def ReplaceReferent(self, old, new, add_new): 126 | if self.ref1 == old: self.ref1 = new 127 | if self.ref2 == old: self.ref2 = new 128 | return add_new 129 | 130 | 131 | class NegationCondition(Condition): 132 | def __init__(self, drs_or_condition, informative=True): 133 | if isinstance(drs_or_condition, Condition): 134 | drs_or_condition = DRS([], [drs_or_condition]) 135 | self.drs = drs_or_condition 136 | drs_or_condition.parent = self 137 | self.parent = None 138 | self.informative = informative 139 | 140 | def __repr__(self): 141 | return '-%s' % self.drs 142 | 143 | def __eq__(self, other): 144 | return (isinstance(other, self.__class__) and 145 | self.drs == other.drs) 146 | 147 | def __hash__(self): 148 | return hash((NegationCondition, self.drs)) 149 | 150 | @property 151 | def summary(self): 152 | return '-%s' % self.drs.summary 153 | 154 | def Formulate(self): 155 | return '-(%s)' % self.drs.Formulate() 156 | 157 | def GetChildDRSs(self): 158 | return (self.drs,) 159 | 160 | def ReplaceReferent(self, old, new, add_new): 161 | return self.drs.ReplaceReferent(old, new, add_new) 162 | 163 | def Copy(self): 164 | return NegationCondition(self.drs.Copy(), informative=self.informative) 165 | 166 | 167 | class AlternationCondition(Condition): 168 | def __init__(self, drs_or_condition1, drs_or_condition2, informative=True): 169 | if isinstance(drs_or_condition1, Condition): 170 | drs_or_condition1 = DRS([], [drs_or_condition1]) 171 | if isinstance(drs_or_condition2, Condition): 172 | drs_or_condition2 = DRS([], [drs_or_condition2]) 173 | self.drs1 = drs_or_condition1 174 | self.drs2 = drs_or_condition2 175 | self.drs1.parent = self 176 | self.drs2.parent = self 177 | self.parent = None 178 | self.informative = informative 179 | 180 | def __repr__(self): 181 | return '(%s or %s)' % (self.drs1, self.drs2) 182 | 183 | def __eq__(self, other): 184 | return (isinstance(other, self.__class__) and 185 | ((self.drs1 == other.drs1 and self.drs2 == other.drs2) or 186 | (self.drs1 == other.drs2 and self.drs2 == other.drs1))) 187 | 188 | def __hash__(self): 189 | return hash((AlternationCondition, self.drs1, self.drs2)) 190 | 191 | @property 192 | def summary(self): 193 | return '(%s or %s)' % (self.drs1.summary, self.drs2.summary) 194 | 195 | def Formulate(self): 196 | return '((%s) | (%s))' % (self.drs1.Formulate(), 197 | self.drs2.Formulate()) 198 | 199 | def GetChildDRSs(self): 200 | return (self.drs1, self.drs2) 201 | 202 | def ReplaceReferent(self, old, new, add_new): 203 | add_new = self.drs1.ReplaceReferent(old, new, add_new) 204 | add_new = self.drs2.ReplaceReferent(old, new, add_new) 205 | return add_new 206 | 207 | def Copy(self): 208 | return AlternationCondition(self.drs1.Copy(), self.drs2.Copy(), 209 | informative=self.informative) 210 | 211 | 212 | class ImplicationCondition(Condition): 213 | def __init__(self, drs_or_condition1, drs_or_condition2, informative=True): 214 | if isinstance(drs_or_condition1, Condition): 215 | drs_or_condition1 = DRS([], [drs_or_condition1]) 216 | if isinstance(drs_or_condition2, Condition): 217 | drs_or_condition2 = DRS([], [drs_or_condition2]) 218 | self.drs1 = drs_or_condition1 219 | self.drs2 = drs_or_condition2 220 | self.drs1.parent = self 221 | self.drs2.parent = self 222 | self.parent = None 223 | self.informative = informative 224 | 225 | def __repr__(self): 226 | return '(%s -> %s)' % (self.drs1, self.drs2) 227 | 228 | def __eq__(self, other): 229 | return (isinstance(other, self.__class__) and 230 | self.drs1 == other.drs1 and 231 | self.drs2 == other.drs2) 232 | 233 | def __hash__(self): 234 | return hash((ImplicationCondition, self.drs1, self.drs2)) 235 | 236 | @property 237 | def summary(self): 238 | return '(%s -> %s)' % (self.drs1.summary, self.drs2.summary) 239 | 240 | def Formulate(self): 241 | return '(%s ((%s) -> (%s)))' % (self.drs1.FormulateDomain(forall=True), 242 | self.drs1.FormulateConditions(), 243 | self.drs2.Formulate()) 244 | 245 | def GetChildDRSs(self): 246 | return (self.drs1, self.drs2) 247 | 248 | def ReplaceReferent(self, old, new, add_new): 249 | add_new = self.drs1.ReplaceReferent(old, new, add_new) 250 | add_new = self.drs2.ReplaceReferent(old, new, add_new) 251 | return add_new 252 | 253 | def Copy(self): 254 | return ImplicationCondition(self.drs1.Copy(), self.drs2.Copy(), 255 | informative=self.informative) 256 | 257 | def GetAccessibleReferents(self, which): 258 | if which == self.drs2: 259 | return self.drs1.GetAccessibleReferents() 260 | else: 261 | return self.parent.GetAccessibleReferents() 262 | 263 | 264 | class ResolutionCondition(Condition): 265 | def __init__(self, referent, requirements, type): 266 | self.ref = referent 267 | self.requirements = requirements 268 | requirements.parent = self 269 | self.type = type 270 | self.parent = None 271 | self.informative = True 272 | 273 | def __repr__(self): 274 | drs = str(self.requirements) 275 | if drs.startswith('['): 276 | drs = drs[1:-1] 277 | return '%s ? {{%s}}' % (self.ref, drs) 278 | 279 | def __eq__(self, other): 280 | return isinstance(other, self.__class__) and self.ref == other.ref 281 | 282 | def __hash__(self): 283 | return hash((ResolutionCondition, self.ref, self.requirements)) 284 | 285 | @property 286 | def summary(self): 287 | drs_summary = self.requirements.summary 288 | if drs_summary.startswith('['): 289 | drs_summary = drs_summary[1:-1] 290 | return '%s ? {{%s}}' % (self.ref, drs_summary) 291 | 292 | def Copy(self): 293 | return ResolutionCondition(self.ref, self.requirements.Copy(), self.type) 294 | 295 | def Formulate(self): 296 | raise FormulationError('Cannot formulate unresolved condition.') 297 | 298 | def GetChildDRSs(self): 299 | return (self.requirements,) 300 | 301 | def ReplaceReferent(self, old, new, add_new): 302 | if self.ref == old: 303 | raise FormulationError('Cannot replace unresolved referents.') 304 | else: 305 | add_new = self.requirements.ReplaceReferent(old, new, add_new) 306 | return add_new 307 | 308 | 309 | class DRS(object): 310 | def __init__(self, referents=(), conditions=(), parent=None): 311 | if isinstance(referents, DRS): 312 | DRS.__init__(self) 313 | self += referents 314 | else: 315 | self._conditions = [] 316 | for cond in conditions: 317 | self.AddCondition(cond) 318 | self.referents = set(referents) 319 | self.parent = parent 320 | 321 | def __nonzero__(self): 322 | return bool(self.referents or self._conditions) 323 | 324 | def __add__(self, other): 325 | base = self.Copy() 326 | return base.__iadd__(other) 327 | 328 | def __iadd__(self, other): 329 | self.referents.update(other.referents) 330 | for cond in other._conditions: 331 | self.AddCondition(cond.Copy()) 332 | if isinstance(other, SubjectQuestionDRS): 333 | self.__class__ = SubjectQuestionDRS 334 | self.target = other.target 335 | return self 336 | 337 | def __repr__(self): 338 | refs = ', '.join(str(i) for i in self.referents) 339 | conds = ', '.join(str(i) for i in self._conditions) 340 | if refs: 341 | result = '[%s | %s]' % (refs, conds) 342 | else: 343 | result = conds if len(self._conditions) == 1 else '[%s]' % conds 344 | return result 345 | 346 | def __eq__(self, other): 347 | return (isinstance(other, self.__class__) and 348 | self.referents == other.referents and 349 | self._conditions == other._conditions) 350 | 351 | def __ne__(self, other): 352 | return not (self == other) 353 | 354 | def __hash__(self): 355 | return hash((DRS, 356 | frozenset(self.referents), 357 | frozenset(self._conditions))) 358 | 359 | @property 360 | def summary(self): 361 | refs = ', '.join(str(i) for i in self.referents) 362 | informative_conds = [i for i in self._conditions if i.informative] 363 | conds = ', '.join(i.summary for i in informative_conds) 364 | if refs: 365 | result = '[%s | %s]' % (refs, conds) 366 | else: 367 | result = conds if len(self._conditions) == 1 else '[%s]' % conds 368 | result = conds if len(informative_conds) == 1 else '[%s]' % conds 369 | return result 370 | 371 | @property 372 | def conditions(self): 373 | return tuple(self._conditions) 374 | 375 | def AddCondition(self, cond): 376 | assert isinstance(cond, Condition) 377 | if cond in self._conditions: 378 | if cond.informative: 379 | self._conditions.remove(cond) 380 | self._conditions.append(cond) 381 | else: 382 | cond.parent = self 383 | self._conditions.append(cond) 384 | 385 | def RemoveCondition(self, cond): 386 | if cond in self._conditions: 387 | self._conditions.remove(cond) 388 | 389 | def Copy(self): 390 | return self.__class__(self.referents, 391 | (i.Copy() for i in self._conditions), 392 | self.parent) 393 | 394 | def GetChildDRSs(self): 395 | return sum((i.GetChildDRSs() for i in self._conditions), ()) 396 | 397 | def Walk(self): 398 | yield self 399 | for cond in self._conditions: 400 | for drs in cond.GetChildDRSs(): 401 | for drs2 in drs.Walk(): 402 | yield drs2 403 | 404 | def Formulate(self, enforce_unique=True): 405 | return '%s (%s)' % (self.FormulateDomain(), 406 | self.FormulateConditions(enforce_unique=enforce_unique)) 407 | 408 | def FormulateDomain(self, forall=False): 409 | scope = 'all' if forall else 'exists' 410 | return ' '.join('%s %s' % (scope, i) for i in self.referents) 411 | 412 | def FormulateConditions(self, enforce_unique=True): 413 | conds = [i.Formulate() for i in self._conditions] 414 | uniqueness = [] 415 | if enforce_unique: 416 | referents = list(self.referents) 417 | for i, r in enumerate(referents): 418 | for s in referents[i+1:]: 419 | uniqueness.append('%s != %s' % (r, s)) 420 | joined = '(%s)' % ' & '.join(conds + uniqueness) 421 | if joined == '()': 422 | joined = '1=1' 423 | return joined 424 | 425 | def ReplaceReferent(self, old, new, add_new=False): 426 | assert not (isinstance(old, NamedReferent) and 427 | not isinstance(new, NamedReferent)) 428 | if new in self.referents and not add_new: 429 | self.referents.remove(new) 430 | 431 | if old in self.referents: 432 | if old in self.referents: self.referents.remove(old) 433 | if add_new: 434 | self.referents.add(new) 435 | add_new = False 436 | 437 | add_new = all([cond.ReplaceReferent(old, new, add_new) 438 | for cond in self._conditions]) 439 | return add_new 440 | 441 | def GetAccessibleReferents(self): 442 | refs = collections.OrderedDict((i, self) for i in self.referents) 443 | if self.parent: 444 | ancestor_refs = self.parent.GetAccessibleReferents(self) 445 | ancestor_refs.update(refs) 446 | refs = ancestor_refs 447 | return refs 448 | 449 | def Simplify(self): 450 | boxes_to_resolve = [self] 451 | resolved_referents = {} 452 | while boxes_to_resolve: 453 | drs = boxes_to_resolve.pop() 454 | for cond in drs.conditions: 455 | if isinstance(cond, EqualityCondition): 456 | if cond.ref1 in resolved_referents: 457 | cond.ref1 = resolved_referents[cond.ref1] 458 | if cond.ref2 in resolved_referents: 459 | cond.ref2 = resolved_referents[cond.ref2] 460 | if cond.ref1 != cond.ref2: 461 | if isinstance(cond.ref1, NamedReferent): 462 | self.ReplaceReferent(cond.ref2, cond.ref1, add_new=True) 463 | else: 464 | self.ReplaceReferent(cond.ref1, cond.ref2, add_new=True) 465 | resolved_referents[cond.ref1] = cond.ref2 466 | drs.RemoveCondition(cond) 467 | if not isinstance(cond, NegationCondition): 468 | boxes_to_resolve += cond.GetChildDRSs() 469 | conditions = self._conditions 470 | self._conditions = [] 471 | for cond in conditions: 472 | self.AddCondition(cond) 473 | 474 | def RaiseNamedRefs(self): 475 | named_refs = set() 476 | 477 | for drs in self.Walk(): 478 | refs_to_keep = set() 479 | for ref in drs.referents: 480 | if isinstance(ref, NamedReferent): 481 | named_refs.add(ref) 482 | else: 483 | refs_to_keep.add(ref) 484 | drs.referents = refs_to_keep 485 | 486 | self.referents.update(named_refs) 487 | 488 | def EliminateResolutions(self): 489 | for drs in self.Walk(): 490 | for cond in drs.conditions: 491 | if isinstance(cond, ResolutionCondition): 492 | drs.referents.add(cond.ref) 493 | drs.RemoveCondition(cond) 494 | 495 | 496 | class QuestionDRS(DRS): 497 | pass 498 | 499 | 500 | class BooleanQuestionDRS(QuestionDRS): 501 | def __repr__(self): 502 | return 'Yes/No Question: ' + DRS.__repr__(self) 503 | 504 | @property 505 | def summary(self): 506 | return 'Yes/No Question: ' + DRS.summary.fget(self) 507 | 508 | 509 | class SubjectQuestionDRS(QuestionDRS): 510 | def __init__(self, drs, target): 511 | self.target = target 512 | DRS.__init__(self, drs) 513 | 514 | def __repr__(self): 515 | return 'Question(%s): %s' % (self.target, DRS.__repr__(self)) 516 | 517 | @property 518 | def summary(self): 519 | return 'Question(%s): %s' % (self.target, DRS.summary.fget(self)) 520 | 521 | def Copy(self): 522 | return SubjectQuestionDRS(self, self.target) 523 | 524 | def ReplaceReferent(self, old, new, add_new=False): 525 | if self.target == old: 526 | self.target = new 527 | DRS.ReplaceReferent(self, old, new, add_new) 528 | -------------------------------------------------------------------------------- /src/grammar/base_lexicon.fcfg: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Honorifics # 3 | ################################################################################ 4 | 5 | Ttl[NUM=?n,SEX=?s,-abbr] -> Ttl[NUM=?n,SEX=?s,+abbr] '.' 6 | Ttl[NUM=sg,SEX=m,+abbr] -> 'mr' 7 | Ttl[NUM=sg,SEX=m] -> 'mister' 8 | Ttl[NUM=sg,SEX=m] -> 'master' 9 | Ttl[NUM=sg,SEX=m] -> 'sir' 10 | Ttl[NUM=sg,SEX=f,+abbr] -> 'mrs' 11 | Ttl[NUM=sg,SEX=f] -> 'miss' 12 | Ttl[NUM=sg,SEX=f,+abbr] -> 'ms' 13 | Ttl[NUM=sg,SEX=m] -> 'coach' 14 | Ttl[NUM=sg,SEX=f] -> 'coach' 15 | Ttl[NUM=sg,SEX=m,+abbr] -> 'dr' 16 | Ttl[NUM=sg,SEX=f,+abbr] -> 'dr' 17 | Ttl[NUM=sg,SEX=m] -> 'doctor' 18 | Ttl[NUM=sg,SEX=f] -> 'doctor' 19 | Ttl[NUM=sg,SEX=m,+abbr] -> 'prof' 20 | Ttl[NUM=sg,SEX=f,+abbr] -> 'prof' 21 | Ttl[NUM=sg,SEX=m] -> 'professor' 22 | Ttl[NUM=sg,SEX=f] -> 'professor' 23 | Ttl[NUM=sg,SEX=m,+abbr] -> 'rev' 24 | Ttl[NUM=sg,SEX=m] -> 'reverend' 25 | 26 | Ttl[NUM=sg,SEX=m,+abbr] -> 'hon' 27 | Ttl[NUM=sg,SEX=f,+abbr] -> 'hon' 28 | Ttl[NUM=sg,SEX=m] -> 'honorable' 29 | Ttl[NUM=sg,SEX=f] -> 'honorable' 30 | Ttl[NUM=sg,SEX=m] -> 'judge' 31 | Ttl[NUM=sg,SEX=f] -> 'judge' 32 | Ttl[NUM=sg,SEX=m,+abbr] -> 'gov' 33 | Ttl[NUM=sg,SEX=f,+abbr] -> 'gov' 34 | Ttl[NUM=sg,SEX=m] -> 'governor' 35 | Ttl[NUM=sg,SEX=f] -> 'governor' 36 | Ttl[NUM=sg,SEX=m,+abbr] -> 'rep' 37 | Ttl[NUM=sg,SEX=f,+abbr] -> 'rep' 38 | Ttl[NUM=sg,SEX=m] -> 'representative' 39 | Ttl[NUM=sg,SEX=f] -> 'representative' 40 | Ttl[NUM=sg,SEX=m,+abbr] -> 'sen' 41 | Ttl[NUM=sg,SEX=f,+abbr] -> 'sen' 42 | Ttl[NUM=sg,SEX=m] -> 'senator' 43 | Ttl[NUM=sg,SEX=f] -> 'senator' 44 | Ttl[NUM=sg,SEX=m] -> 'ambassador' 45 | Ttl[NUM=sg,SEX=f] -> 'ambassador' 46 | Ttl[NUM=sg,SEX=m,+abbr] -> 'sec' 47 | Ttl[NUM=sg,SEX=f,+abbr] -> 'sec' 48 | Ttl[NUM=sg,SEX=m] -> 'secretary' 49 | Ttl[NUM=sg,SEX=f] -> 'secretary' 50 | Ttl[NUM=sg,SEX=m,+abbr] -> 'pres' 51 | Ttl[NUM=sg,SEX=f,+abbr] -> 'pres' 52 | Ttl[NUM=sg,SEX=m] -> 'president' 53 | Ttl[NUM=sg,SEX=f] -> 'president' 54 | 55 | Ttl[NUM=sg,SEX=m,+abbr] -> 'ofc' 56 | Ttl[NUM=sg,SEX=f,+abbr] -> 'ofc' 57 | Ttl[NUM=sg,SEX=m] -> 'officer' 58 | Ttl[NUM=sg,SEX=f] -> 'officer' 59 | Ttl[NUM=sg,SEX=m,+abbr] -> 'pvt' 60 | Ttl[NUM=sg,SEX=f,+abbr] -> 'pvt' 61 | Ttl[NUM=sg,SEX=m] -> 'private' 62 | Ttl[NUM=sg,SEX=f] -> 'private' 63 | Ttl[NUM=sg,SEX=m,+abbr] -> 'cpl' 64 | Ttl[NUM=sg,SEX=f,+abbr] -> 'cpl' 65 | Ttl[NUM=sg,SEX=m] -> 'corporal' 66 | Ttl[NUM=sg,SEX=f] -> 'corporal' 67 | Ttl[NUM=sg,SEX=m,+abbr] -> 'sgt' 68 | Ttl[NUM=sg,SEX=f,+abbr] -> 'sgt' 69 | Ttl[NUM=sg,SEX=m] -> 'sargent' 70 | Ttl[NUM=sg,SEX=f] -> 'sargent' 71 | Ttl[NUM=sg,SEX=m,+abbr] -> 'maj' 72 | Ttl[NUM=sg,SEX=f,+abbr] -> 'maj' 73 | Ttl[NUM=sg,SEX=m] -> 'major' 74 | Ttl[NUM=sg,SEX=f] -> 'major' 75 | Ttl[NUM=sg,SEX=m,+abbr] -> 'capt' 76 | Ttl[NUM=sg,SEX=f,+abbr] -> 'capt' 77 | Ttl[NUM=sg,SEX=m] -> 'captain' 78 | Ttl[NUM=sg,SEX=f] -> 'captain' 79 | Ttl[NUM=sg,SEX=m,+abbr] -> 'cmdr' 80 | Ttl[NUM=sg,SEX=f,+abbr] -> 'cmdr' 81 | Ttl[NUM=sg,SEX=m] -> 'commander' 82 | Ttl[NUM=sg,SEX=f] -> 'commander' 83 | Ttl[NUM=sg,SEX=m,+abbr] -> 'lt' 84 | Ttl[NUM=sg,SEX=f,+abbr] -> 'lt' 85 | Ttl[NUM=sg,SEX=m] -> 'lieutenant' 86 | Ttl[NUM=sg,SEX=f] -> 'lieutenant' 87 | Ttl[NUM=sg,SEX=m,+abbr] -> 'lt' 'col' 88 | Ttl[NUM=sg,SEX=f,+abbr] -> 'lt' 'col' 89 | Ttl[NUM=sg,SEX=m] -> 'lieutenant' 'colonel' 90 | Ttl[NUM=sg,SEX=f] -> 'lieutenant' 'colonel' 91 | Ttl[NUM=sg,SEX=m,+abbr] -> 'col' 92 | Ttl[NUM=sg,SEX=f,+abbr] -> 'col' 93 | Ttl[NUM=sg,SEX=m] -> 'colonel' 94 | Ttl[NUM=sg,SEX=f] -> 'colonel' 95 | Ttl[NUM=sg,SEX=m,+abbr] -> 'gen' 96 | Ttl[NUM=sg,SEX=f,+abbr] -> 'gen' 97 | Ttl[NUM=sg,SEX=m] -> 'general' 98 | Ttl[NUM=sg,SEX=f] -> 'general' 99 | 100 | ################################################################################ 101 | # Verb Particles # 102 | ################################################################################ 103 | 104 | Particle[PTCL=_s] -> "'s" 105 | Particle[PTCL=about] -> "about" 106 | Particle[PTCL=after] -> "after" 107 | Particle[PTCL=against] -> "against" 108 | Particle[PTCL=among] -> "among" 109 | Particle[PTCL=apart] -> "apart" 110 | Particle[PTCL=as] -> "as" 111 | Particle[PTCL=at] -> "at" 112 | Particle[PTCL=away] -> "away" 113 | Particle[PTCL=be] -> "be" 114 | Particle[PTCL=before] -> "before" 115 | Particle[PTCL=between] -> "between" 116 | Particle[PTCL=by] -> "by" 117 | Particle[PTCL=concerning] -> "concerning" 118 | Particle[PTCL=down] -> "down" 119 | Particle[PTCL=for] -> "for" 120 | Particle[PTCL=from] -> "from" 121 | Particle[PTCL=in] -> "in" 122 | Particle[PTCL=in_between] -> "in" "between" 123 | Particle[PTCL=into] -> "into" 124 | Particle[PTCL=like] -> "like" 125 | Particle[PTCL=of] -> "of" 126 | Particle[PTCL=off] -> "off" 127 | Particle[PTCL=on] -> "on" 128 | Particle[PTCL=onto] -> "onto" 129 | Particle[PTCL=out] -> "out" 130 | Particle[PTCL=out_of] -> "out" "of" 131 | Particle[PTCL=over] -> "over" 132 | Particle[PTCL=regarding] -> "regarding" 133 | Particle[PTCL=respecting] -> "respecting" 134 | Particle[PTCL=through] -> "through" 135 | Particle[PTCL=to] -> "to" 136 | Particle[PTCL=together] -> "together" 137 | Particle[PTCL=towards] -> "towards" 138 | Particle[PTCL=under] -> "under" 139 | Particle[PTCL=until] -> "until" 140 | Particle[PTCL=up] -> "up" 141 | Particle[PTCL=upon] -> "upon" 142 | Particle[PTCL=way] -> "way" 143 | Particle[PTCL=with] -> "with" 144 | 145 | ################################################################################ 146 | # Prepositions # 147 | ################################################################################ 148 | 149 | Prep[TYP=special] -> 'of' 150 | Prep[TYP=conjunctive] -> 'with' 151 | Prep[TYP=conjunctive] -> 'without' 152 | Prep[TYP=temporal] -> 'after' 153 | Prep[TYP=temporal] -> 'before' 154 | Prep[TYP=temporal] -> 'during' 155 | Prep[TYP=temporal] -> 'circa' 156 | Prep[TYP=temporal] -> 'prior' 'to' 157 | Prep[TYP=temporal] -> 'till' 158 | Prep[TYP=temporal] -> 'until' 159 | Prep[TYP=spatial,+loc] -> 'about' 160 | Prep[TYP=spatial,+loc] -> 'above' 161 | Prep[TYP=spatial,+loc] -> 'against' 162 | Prep[TYP=spatial,+loc] -> 'along' 163 | Prep[TYP=spatial,+loc] -> 'alongside' 164 | Prep[TYP=spatial,+loc] -> 'amid' 165 | Prep[TYP=spatial,+loc] -> 'among' 166 | Prep[TYP=spatial,+loc] -> 'amongst' 167 | Prep[TYP=spatial,+loc] -> 'around' 168 | Prep[TYP=spatial,+loc] -> 'astride' 169 | Prep[TYP=spatial,+loc] -> 'aboard' 170 | Prep[TYP=spatial,+loc] -> 'at' 171 | Prep[TYP=spatial,+loc] -> 'athwart' 172 | Prep[TYP=spatial,+loc] -> 'atop' 173 | Prep[TYP=spatial,+loc] -> 'before' 174 | Prep[TYP=spatial,+loc] -> 'behind' 175 | Prep[TYP=spatial,+loc] -> 'below' 176 | Prep[TYP=spatial,+loc] -> 'beneath' 177 | Prep[TYP=spatial,+loc] -> 'beside' 178 | Prep[TYP=spatial,+loc] -> 'between' 179 | Prep[TYP=spatial,+loc] -> 'beyond' 180 | Prep[TYP=spatial,+loc] -> 'by' 181 | Prep[TYP=spatial,+loc] -> 'from' 182 | Prep[TYP=spatial,+loc] -> 'in' 183 | Prep[TYP=spatial,+loc] -> 'in' 'front' 'of' 184 | Prep[TYP=spatial,+loc] -> 'inside' 185 | Prep[TYP=spatial,+loc] -> 'near' 186 | Prep[TYP=spatial,+loc] -> 'next' 'to' 187 | Prep[TYP=spatial,+loc] -> 'off' 188 | Prep[TYP=spatial,+loc] -> 'on' 189 | Prep[TYP=spatial,+loc] -> 'opposite' 190 | Prep[TYP=spatial,+loc] -> 'out' 'of' 191 | Prep[TYP=spatial,+loc] -> 'outside' 192 | Prep[TYP=spatial,+loc] -> 'over' 193 | Prep[TYP=spatial,+loc] -> 'round' 194 | Prep[TYP=spatial,+loc] -> 'throughout' 195 | Prep[TYP=spatial,+loc] -> 'under' 196 | Prep[TYP=spatial,+loc] -> 'underneath' 197 | Prep[TYP=spatial,+loc] -> 'upon' 198 | Prep[TYP=spatial,+loc] -> 'within' 199 | Prep[TYP=spatial,+path,+src] -> 'from' 200 | Prep[TYP=spatial,+path,+src] -> 'out' 201 | Prep[TYP=spatial,+path,+src] -> 'out' 'of' 202 | Prep[TYP=spatial,+path,+src] -> 'off' 203 | Prep[TYP=spatial,+path,+src] -> 'off' 'of' 204 | Prep[TYP=spatial,+path,+dir] -> 'across' 205 | Prep[TYP=spatial,+path,+dir] -> 'along' 206 | Prep[TYP=spatial,+path,+dir] -> 'around' 207 | Prep[TYP=spatial,+path,+dir] -> 'down' 208 | Prep[TYP=spatial,+path,+dir] -> 'over' 209 | Prep[TYP=spatial,+path,+dir] -> 'past' 210 | Prep[TYP=spatial,+path,+dir] -> 'round' 211 | Prep[TYP=spatial,+path,+dir] -> 'through' 212 | Prep[TYP=spatial,+path,+dir] -> 'towards' 213 | Prep[TYP=spatial,+path,+dir] -> 'up' 214 | Prep[TYP=spatial,+path,+dest,+dest_dir] -> 'for' 215 | Prep[TYP=spatial,+path,+dest,+dest_dir] -> 'at' 216 | Prep[TYP=spatial,+path,+dest,+dest_dir] -> 'to' 217 | Prep[TYP=spatial,+path,+dest,+dest_dir] -> 'towards' 218 | Prep[TYP=spatial,+path,+dest,+dest_conf] -> 'into' 219 | Prep[TYP=spatial,+path,+dest,+dest_conf] -> 'onto' 220 | 221 | ################################################################################ 222 | # Puctuation # 223 | ################################################################################ 224 | 225 | Pnct[TYP=end] -> '.' | '...' | '!' 226 | Pnct[TYP=qst] -> '?' | '?!' 227 | Pnct[TYP=com] -> ',' | ';' 228 | 229 | ################################################################################ 230 | # Conditionals # 231 | ################################################################################ 232 | 233 | Cond -> 'if' 234 | Cond -> 'when' 235 | Cond -> 'whenever' 236 | Cond -> 'given' 237 | Cond -> 'given' 'that' 238 | Cond -> 'as' 'long' 'as' 239 | Cond -> 'assuming' 240 | Cond -> 'provided' 241 | Cond -> 'since' 242 | Cond -> 'supposing' 243 | 244 | ################################################################################ 245 | # Articles # 246 | ################################################################################ 247 | 248 | Art[NUM=sg,-definite] -> 'a' 249 | Art[NUM=sg,-definite] -> 'an' 250 | Art[NUM=sg,+definite] -> 'the' 251 | Art[NUM=ms,+definite] -> 'the' 252 | Art[NUM=pl,+definite] -> 'the' 253 | 254 | ################################################################################ 255 | # Determiners # 256 | ################################################################################ 257 | 258 | Det[NUM=sg,DETTYP=dem] -> 'this' 259 | Det[NUM=sg,DETTYP=dem] -> 'that' 260 | Det[NUM=pl,DETTYP=dem] -> 'these' 261 | Det[NUM=pl,DETTYP=dem] -> 'those' 262 | Det[DETTYP=exst] -> 'some' 263 | Det[NUM=pl,DETTYP=exst] -> 'certain' 264 | Det[NUM=pl,DETTYP=exst] -> 'several' 265 | Det[DETTYP=alt] -> 'another' 266 | Det[NUM=pl,DETTYP=deg,SEM=pos] -> 'most' 267 | Det[NUM=pl,DETTYP=deg,SEM=pos] -> 'a' 'lot' 'of' 268 | Det[NUM=pl,DETTYP=deg,SEM=pos] -> 'many' 269 | Det[NUM=pl,DETTYP=deg,SEM=neg] -> 'few' 270 | Det[NUM=pl,DETTYP=deg,SEM=zero] -> 'several' 271 | Det[NUM=pl,DETTYP=deg,SEM=zero] -> 'a' 'few' 272 | Det[NUM=ms,DETTYP=deg,SEM=zero] -> 'a' 'little' 273 | Det[NUM=ms,DETTYP=deg,SEM=pos] -> 'a' 'lot' 'of' 274 | Det[NUM=ms,DETTYP=deg,SEM=pos] -> 'most' 275 | Det[NUM=ms,DETTYP=deg,SEM=pos] -> 'much' 276 | Det[NUM=ms,DETTYP=deg,SEM=neg] -> 'little' 277 | Det[NUM=sg,DETTYP=unvrs] -> 'any' 278 | Det[NUM=ms,DETTYP=unvrs] -> 'any' 279 | Det[NUM=pl,DETTYP=unvrs] -> 'all' 280 | Det[NUM=ms,DETTYP=unvrs] -> 'all' 281 | Det[NUM=sg,DETTYP=unvrs] -> 'every' 282 | Det[NUM=sg,DETTYP=unvrs] -> 'each' 283 | Det[DETTYP=neg] -> 'no' 284 | Det[NUM=pl,DETTYP=neg] -> 'none' 'of' 'the' 285 | 286 | ################################################################################ 287 | # Pronouns # 288 | ################################################################################ 289 | 290 | Pro[PER=1,NUM=sg,CASE=sbj] -> 'i' 291 | Pro[PER=1,NUM=sg,CASE=obj] -> 'me' 292 | Pro[PER=1,NUM=sg,CASE=poss_det] -> 'my' 293 | Pro[PER=1,NUM=sg,CASE=poss_pred] -> 'mine' 294 | Pro[PER=1,NUM=sg,CASE=rflx] -> 'myself' 295 | 296 | Pro[PER=1,NUM=pl,CASE=sbj] -> 'we' 297 | Pro[PER=1,NUM=pl,CASE=obj] -> 'us' 298 | Pro[PER=1,NUM=pl,CASE=poss_det] -> 'our' 299 | Pro[PER=1,NUM=pl,CASE=poss_pred] -> 'ours' 300 | Pro[PER=1,NUM=pl,CASE=rflx] -> 'ourself' 301 | 302 | Pro[PER=2,CASE=sbj] -> 'you' 303 | Pro[PER=2,CASE=obj] -> 'you' 304 | Pro[PER=2,CASE=poss_det] -> 'your' 305 | Pro[PER=2,CASE=poss_pred] -> 'yours' 306 | Pro[PER=2,CASE=rflx] -> 'yourself' 307 | 308 | Pro[PER=3,NUM=sg,CASE=sbj,SEX=m] -> 'he' 309 | Pro[PER=3,NUM=sg,CASE=obj,SEX=m] -> 'him' 310 | Pro[PER=3,NUM=sg,CASE=poss_det,SEX=m] -> 'his' 311 | Pro[PER=3,NUM=sg,CASE=poss_pred,SEX=m] -> 'his' 312 | Pro[PER=3,NUM=sg,CASE=rflx,SEX=m] -> 'himself' 313 | 314 | Pro[PER=3,NUM=sg,CASE=sbj,SEX=f] -> 'she' 315 | Pro[PER=3,NUM=sg,CASE=obj,SEX=f] -> 'her' 316 | Pro[PER=3,NUM=sg,CASE=poss_det,SEX=f] -> 'her' 317 | Pro[PER=3,NUM=sg,CASE=poss_pred,SEX=f] -> 'hers' 318 | Pro[PER=3,NUM=sg,CASE=rflx,SEX=f] -> 'herself' 319 | 320 | Pro[PER=3,NUM=sg,CASE=poss_det] -> 'one' "'s" 321 | Pro[PER=3,NUM=sg,CASE=rflx] -> 'oneself' 322 | 323 | Pro[PER=3,NUM=sg,CASE=sbj,SEX=n] -> 'it' 324 | Pro[PER=3,NUM=sg,CASE=obj,SEX=n] -> 'it' 325 | Pro[PER=3,NUM=sg,CASE=poss_det,SEX=n] -> 'its' 326 | Pro[PER=3,NUM=sg,CASE=poss_pred,SEX=n] -> 'its' 327 | Pro[PER=3,NUM=sg,CASE=rflx,SEX=n] -> 'itself' 328 | 329 | Pro[PER=3,NUM=pl,CASE=sbj] -> 'they' 330 | Pro[PER=3,NUM=pl,CASE=obj] -> 'them' 331 | Pro[PER=3,NUM=pl,CASE=poss_det] -> 'their' 332 | Pro[PER=3,NUM=pl,CASE=poss_pred] -> 'their' 333 | Pro[PER=3,NUM=pl,CASE=rflx] -> 'themselves' 334 | 335 | ################################################################################ 336 | # Verbs # 337 | ################################################################################ 338 | 339 | # Be: forms 340 | Verb[FORM=inf,PTRN=-1,FRQ=100] -> "be" 341 | Verb[FORM=tps,PTRN=-1,FRQ=100] -> "is" 342 | Verb[FORM=ger,PTRN=-1,FRQ=100] -> "being" 343 | Verb[FORM=pret,PTRN=-1,FRQ=100] -> "was" 344 | Verb[FORM=pp,PTRN=-1,FRQ=100] -> "been" 345 | 346 | # Be: present 347 | AuxV[SEM=pos,TENS=r,PER=1,NUM=sg,TYP=be] -> "am" 348 | AuxV[SEM=pos,TENS=r,PER=1,NUM=ms,TYP=be] -> "am" 349 | AuxV[SEM=pos,TENS=r,PER=1,NUM=sg,TYP=be] -> "'m" 350 | AuxV[SEM=pos,TENS=r,PER=1,NUM=ms,TYP=be] -> "'m" 351 | AuxV[SEM=neg,TENS=r,PER=1,NUM=sg,TYP=be] -> "am" "not" 352 | AuxV[SEM=neg,TENS=r,PER=1,NUM=ms,TYP=be] -> "am" "not" 353 | AuxV[SEM=pos,TENS=r,PER=2,NUM=sg,TYP=be] -> "are" 354 | AuxV[SEM=pos,TENS=r,PER=2,NUM=sg,TYP=be] -> "'re" 355 | AuxV[SEM=neg,TENS=r,PER=2,NUM=sg,TYP=be] -> "are" "not" 356 | AuxV[SEM=neg,TENS=r,PER=2,NUM=sg,TYP=be] -> "aren" "'t" 357 | AuxV[SEM=pos,TENS=r,PER=3,NUM=sg,TYP=be] -> "is" 358 | AuxV[SEM=pos,TENS=r,PER=3,NUM=ms,TYP=be] -> "is" 359 | AuxV[SEM=pos,TENS=r,PER=3,NUM=sg,TYP=be] -> "'s" 360 | AuxV[SEM=pos,TENS=r,PER=3,NUM=ms,TYP=be] -> "'s" 361 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=be] -> "is" "not" 362 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=be] -> "is" "not" 363 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=be] -> "isn" "'t" 364 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=be] -> "isn" "'t" 365 | AuxV[SEM=pos,TENS=r,NUM=pl,TYP=be] -> "are" 366 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=be] -> "are" "not" 367 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=be] -> "aren" "'t" 368 | 369 | # Be: past 370 | AuxV[SEM=pos,TENS=p,NUM=sg,TYP=be] -> "was" 371 | AuxV[SEM=pos,TENS=p,NUM=ms,TYP=be] -> "was" 372 | AuxV[SEM=neg,TENS=p,NUM=sg,TYP=be] -> "was" "not" 373 | AuxV[SEM=neg,TENS=p,NUM=ms,TYP=be] -> "was" "not" 374 | AuxV[SEM=neg,TENS=p,NUM=sg,TYP=be] -> "wasn" "'t" 375 | AuxV[SEM=neg,TENS=p,NUM=ms,TYP=be] -> "wasn" "'t" 376 | AuxV[SEM=pos,TENS=p,NUM=pl,TYP=be] -> "were" 377 | AuxV[SEM=neg,TENS=p,NUM=pl,TYP=be] -> "were" "not" 378 | AuxV[SEM=neg,TENS=p,NUM=pl,TYP=be] -> "weren" "'t" 379 | 380 | # Do: forms 381 | Verb[FORM=inf,PTRN=-2,FRQ=100] -> "do" 382 | Verb[FORM=tps,PTRN=-2,FRQ=100] -> "does" 383 | Verb[FORM=ger,PTRN=-2,FRQ=100] -> "doing" 384 | Verb[FORM=pret,PTRN=-2,FRQ=100] -> "did" 385 | Verb[FORM=pp,PTRN=-2,FRQ=100] -> "done" 386 | 387 | # Do: present 388 | AuxV[SEM=pos,TENS=r,PER=3,NUM=sg,TYP=do] -> "does" 389 | AuxV[SEM=pos,TENS=r,PER=3,NUM=ms,TYP=do] -> "does" 390 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=do] -> "does" "not" 391 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=do] -> "does" "not" 392 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=do] -> "doesn" "'t" 393 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=do] -> "doesn" "'t" 394 | AuxV[SEM=pos,TENS=r,NUM=sg,TYP=do] -> "do" 395 | AuxV[SEM=pos,TENS=r,NUM=ms,TYP=do] -> "do" 396 | AuxV[SEM=pos,TENS=r,NUM=pl,TYP=do] -> "do" 397 | AuxV[SEM=neg,TENS=r,NUM=sg,TYP=do] -> "do" "not" 398 | AuxV[SEM=neg,TENS=r,NUM=ms,TYP=do] -> "do" "not" 399 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=do] -> "do" "not" 400 | AuxV[SEM=neg,TENS=r,NUM=sg,TYP=do] -> "don" "'t" 401 | AuxV[SEM=neg,TENS=r,NUM=ms,TYP=do] -> "don" "'t" 402 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=do] -> "don" "'t" 403 | 404 | # Do: past 405 | AuxV[SEM=pos,TENS=p,TYP=do] -> "did" 406 | AuxV[SEM=neg,TENS=p,TYP=do] -> "did" "not" 407 | AuxV[SEM=neg,TENS=p,TYP=do] -> "didn" "'t" 408 | 409 | # Have: forms 410 | Verb[FORM=inf,PTRN=-3,FRQ=100] -> "have" 411 | Verb[FORM=tps,PTRN=-3,FRQ=100] -> "has" 412 | Verb[FORM=ger,PTRN=-3,FRQ=100] -> "having" 413 | Verb[FORM=pret,PTRN=-3,FRQ=100] -> "had" 414 | Verb[FORM=pp,PTRN=-3,FRQ=100] -> "had" 415 | 416 | # Have: present 417 | AuxV[SEM=pos,TENS=r,PER=3,NUM=sg,TYP=have] -> "has" 418 | AuxV[SEM=pos,TENS=r,PER=3,NUM=ms,TYP=have] -> "has" 419 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=have] -> "has" "not" 420 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=have] -> "has" "not" 421 | AuxV[SEM=neg,TENS=r,PER=3,NUM=sg,TYP=have] -> "hasn" "'t" 422 | AuxV[SEM=neg,TENS=r,PER=3,NUM=ms,TYP=have] -> "hasn" "'t" 423 | AuxV[SEM=pos,TENS=r,NUM=sg,TYP=have] -> "have" 424 | AuxV[SEM=pos,TENS=r,NUM=ms,TYP=have] -> "have" 425 | AuxV[SEM=pos,TENS=r,NUM=pl,TYP=have] -> "have" 426 | AuxV[SEM=neg,TENS=r,NUM=sg,TYP=have] -> "have" "not" 427 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=have] -> "have" "not" 428 | AuxV[SEM=neg,TENS=r,NUM=ms,TYP=have] -> "have" "not" 429 | AuxV[SEM=neg,TENS=r,NUM=sg,TYP=have] -> "haven" "'t" 430 | AuxV[SEM=neg,TENS=r,NUM=ms,TYP=have] -> "haven" "'t" 431 | AuxV[SEM=neg,TENS=r,NUM=pl,TYP=have] -> "haven" "'t" 432 | 433 | # Have: past 434 | AuxV[SEM=pos,TENS=p,TYP=have] -> "had" 435 | AuxV[SEM=neg,TENS=p,TYP=have] -> "had" "not" 436 | AuxV[SEM=neg,TENS=p,TYP=have] -> "hadn" "'t" 437 | -------------------------------------------------------------------------------- /src/ext/LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------