~bal2277/nlgen2/main

« back to all changes in this revision

Viewing changes to src/java/relex/ParsedSentence.java

  • Committer: Blake Lemoine
  • Date: 2009-09-03 20:31:46 UTC
  • Revision ID: bal2277@louisiana.edu-20090903203146-ih1hcpngkp2a49gj
New commit with driver file and ant build added.  New executable script is nlgen2.sh

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2008 Novamente LLC
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
package relex;
 
18
 
 
19
import java.io.Serializable;
 
20
import java.util.ArrayList;
 
21
 
 
22
import relex.feature.Atom;
 
23
import relex.feature.FeatureForeach;
 
24
import relex.feature.FeatureNode;
 
25
import relex.feature.FeatureNodeCallback;
 
26
import relex.feature.LinkableView;
 
27
import relex.feature.RelationCallback;
 
28
import relex.feature.RelationForeach;
 
29
import relex.stats.SimpleTruthValue;
 
30
import relex.tree.PhraseTree;
 
31
 
 
32
/**
 
33
 * A ParsedSentence object stores all of the syntactic and semantic
 
34
 * information about a sentence parse. The data in the Object is
 
35
 * gradually built up by RelationExtractor.
 
36
 *
 
37
 * ParsedSentence contains:
 
38
 * 1. A FeatureNode with metaData about the parse (i.e., the number
 
39
 *    of conjunctions)
 
40
 * 2. An ArrayList of FeatureNodes (leafConstituents) representing each
 
41
 *    word in the sentence. -- the parse data can be found by checking
 
42
 *    the links in these words.
 
43
 * 3. Strings representing the original sentence, and representations
 
44
 *    of its parses
 
45
 * 4. Sets of relations, with the semantic data from the sentence.
 
46
 * 5. A TruthValue (inherited from Atom) that ranks the relative
 
47
 *    likelihood of this parse of being a correct (meaningful) parse
 
48
 *    of the sentence.
 
49
 */
 
50
public class ParsedSentence extends Atom implements Serializable
 
51
{
 
52
        private static final long serialVersionUID = -5518792541801263127L;
 
53
 
 
54
        // Unique ID string identifying this parse.
 
55
        private String idString;
 
56
 
 
57
        // Back-pointer to collection of other parses for this sentence
 
58
        private Sentence sentence;
 
59
 
 
60
        // String containing the original sentence
 
61
        private String original;
 
62
 
 
63
        // String containing the ascii-art tree output by the link grammar parser.
 
64
        private String linkString;
 
65
 
 
66
        // A string containing the Penn tree-bank style markup,
 
67
        // aka "phrase structure" markup, for example
 
68
        // (S (NP I) (VP am (NP a big robot)) .)
 
69
        private String phraseString;
 
70
 
 
71
        private String errorString;
 
72
 
 
73
        // Metadata about the sentence; primarily, this consists of diagnostic
 
74
        // info returned by the link grammar parser.
 
75
        private FeatureNode metaData;
 
76
 
 
77
        // An ArrayList of FeatureNodes, each one representing a word in the
 
78
        // sentence.  If there are no "link islands", each can be reached by
 
79
        // following arcs from the others.
 
80
        private ArrayList<FeatureNode> leafConstituents;
 
81
 
 
82
        /* -------------------------------------------------------------------- */
 
83
        /* Constructors, and setters/getters for private members. */
 
84
        // Constructor.
 
85
        public ParsedSentence(String originalString)
 
86
        {
 
87
                original = originalString;
 
88
                linkString = null;
 
89
                errorString = "";
 
90
                phraseString = null;
 
91
                leafConstituents = new ArrayList<FeatureNode>();
 
92
        }
 
93
 
 
94
        public void setMetaData(FeatureNode f) {
 
95
                metaData = f;
 
96
        }
 
97
 
 
98
        public FeatureNode getMetaData() {
 
99
                return metaData;
 
100
        }
 
101
 
 
102
        public String getOriginalSentence() {
 
103
                return original;
 
104
        }
 
105
 
 
106
        public String getIDString() {
 
107
                return idString;
 
108
        }
 
109
 
 
110
        public Sentence getSentence() {
 
111
                return sentence;
 
112
        }
 
113
 
 
114
        public void setSentence(Sentence s) {
 
115
                sentence = s;
 
116
        }
 
117
 
 
118
        public void setIDString(String str) {
 
119
                idString = str;
 
120
        }
 
121
 
 
122
        public String getLinkString() {
 
123
                return linkString;
 
124
        }
 
125
 
 
126
        public void setLinkString(String str) {
 
127
                linkString = str;
 
128
        }
 
129
 
 
130
        public String getPhraseString() {
 
131
                return phraseString;
 
132
        }
 
133
 
 
134
        public void setPhraseString(String str) {
 
135
                phraseString = str;
 
136
        }
 
137
 
 
138
        public void setErrorString(String eString) {
 
139
                errorString = eString;
 
140
        }
 
141
 
 
142
        public String getErrorString() {
 
143
                return errorString;
 
144
        }
 
145
 
 
146
        /* -------------------------------------------------------------------- */
 
147
        public int getNumWords()
 
148
        {
 
149
                return leafConstituents.size();
 
150
        }
 
151
 
 
152
        /**
 
153
         * Return the i'th word in the sentence, as a feature node
 
154
         */
 
155
        public FeatureNode getWordAsNode(int i)
 
156
        {
 
157
                return leafConstituents.get(i);
 
158
        }
 
159
 
 
160
        /**
 
161
         * Return the i'th lemmatized word in the sentence, as a string.
 
162
         * This is the "root form" of the word, and not the original word.
 
163
         */
 
164
        public String getWord(int i)
 
165
        {
 
166
                return LinkableView.getWordString(getWordAsNode(i));
 
167
        }
 
168
 
 
169
        /**
 
170
         * Return the i'th word in the sentence, as a string
 
171
         * This is the original form of the word, and not its lemma.
 
172
         */
 
173
        public String getOrigWord(int i)
 
174
        {
 
175
                return LinkableView.getOrigWordString(getWordAsNode(i));
 
176
        }
 
177
 
 
178
        /**
 
179
         * Return the part-of-speech of the i'th word in the sentence
 
180
         */
 
181
        public String getPOS(int i)
 
182
        {
 
183
                return LinkableView.getPOS(getWordAsNode(i));
 
184
        }
 
185
 
 
186
        /**
 
187
         * Return the offset, in the original sentence, to the first
 
188
         * character of the i'th word in the sentence.
 
189
         */
 
190
        public int getStartChar(int i)
 
191
        {
 
192
                return LinkableView.getStartChar(getWordAsNode(i));
 
193
        }
 
194
 
 
195
        public void addWord(FeatureNode w)
 
196
        {
 
197
                leafConstituents.add(w);
 
198
        }
 
199
 
 
200
        /**
 
201
         * Return feature node for the indicated word. Return null
 
202
         * if the word cannot be found in the sentence.  The input
 
203
         * word may be either the word as it appears in the sentence,
 
204
         * or its morphological root.
 
205
         *
 
206
         * If there are multiple occurances of a word in a sentence,
 
207
         * this will return only the left-most such occurance.
 
208
         */
 
209
        public FeatureNode findWord(String word)
 
210
        {
 
211
                class word_cb implements FeatureNodeCallback
 
212
                {
 
213
                        String match_word;
 
214
                        FeatureNode found;
 
215
                        word_cb(String mw)
 
216
                        {
 
217
                                match_word = mw;
 
218
                                found = null;
 
219
                        }
 
220
 
 
221
                        Boolean test(FeatureNode fn, FeatureNode fstr)
 
222
                        {
 
223
                                if (null == fstr) return false;
 
224
                                String w = fstr.getValue();
 
225
                                if (match_word.equals(w))
 
226
                                {
 
227
                                        found = fn;
 
228
                                        return true;
 
229
                                }
 
230
                                return false;
 
231
                        }
 
232
                        public Boolean FNCallback(FeatureNode fn)
 
233
                        {
 
234
                                Boolean rc = test(fn, fn.get("orig_str"));
 
235
                                if (rc) return rc;
 
236
                                rc = test(fn, fn.get("str"));
 
237
                                if (rc) return rc;
 
238
                                return false;
 
239
                        }
 
240
                }
 
241
                word_cb cb = new word_cb(word);
 
242
                FeatureForeach.foreachWord(getLeft(), cb);
 
243
                return cb.found;
 
244
        }
 
245
 
 
246
        /* -------------------------------------------------------------------- */
 
247
        /* Various different views of the parsed sentence */
 
248
 
 
249
        /**
 
250
         * Shows the full feature structure of the parse as it can be found by
 
251
         * tracing links from the left-most word. Islands will be missed.
 
252
         */
 
253
        public String fullParseString()
 
254
        {
 
255
                if (getLeft() != null)
 
256
                        return getLeft().toString();
 
257
                return "";
 
258
        }
 
259
 
 
260
        /**
 
261
         * Returns a list of the words in the sentence, marked up according to
 
262
         * which "part of speech" they are.  Thus, for example:
 
263
         * "The big red baloon floated away." becomes
 
264
         * LEFT-WALL The.det big.adj red.adj balloon.noun float.verb away.prep .
 
265
         */
 
266
        public String printPartsOfSpeech()
 
267
        {
 
268
                StringBuffer sb = new StringBuffer();
 
269
                for (int i = 0; i < leafConstituents.size(); i++) {
 
270
                        sb.append(getWord(i));
 
271
                        LinkableView w = new LinkableView(getWordAsNode(i));
 
272
                        String pos = w.getPOS();
 
273
                        if (pos != null && !pos.equals("WORD"))
 
274
                                sb.append("." + pos);
 
275
                        String tense = w.getTenseVal();  // ??? tense is not working ...
 
276
                        if (tense != null && tense.length() > 0)
 
277
                                sb.append(tense);
 
278
                        if (i < leafConstituents.size() - 1)
 
279
                                sb.append(" ");
 
280
                        // else
 
281
                        // sb.append(".");
 
282
                }
 
283
                return sb.toString();
 
284
        }
 
285
 
 
286
        public String toString()
 
287
        {
 
288
                return original;
 
289
        }
 
290
 
 
291
        /* ---------------------------------------------------------------- */
 
292
        /**
 
293
         * Call the callback on each relation in the sentence
 
294
         */
 
295
        public Boolean foreach(RelationCallback cb)
 
296
        {
 
297
                return RelationForeach.foreach(getLeft(), cb);
 
298
        }
 
299
        
 
300
        public Boolean foreach(FeatureNodeCallback cb)
 
301
        {
 
302
                return RelationForeach.foreach(getLeft(), cb);
 
303
        }
 
304
 
 
305
        /* ---------------------------------------------------------------- */
 
306
        /**
 
307
         * @return the FeatureNode representing the left-most word in the sentence.
 
308
         */
 
309
        public FeatureNode getLeft()
 
310
        {
 
311
                return leafConstituents.get(0);
 
312
        }
 
313
 
 
314
        /**
 
315
         * @return the phrase tree associated with this parse
 
316
         */
 
317
        public PhraseTree getPhraseTree()
 
318
        {
 
319
                return new PhraseTree(getLeft());
 
320
        }
 
321
 
 
322
        /* ---------------------------------------------------------------- */
 
323
        /* Return unpacked meta information about parse, and ranking too */
 
324
 
 
325
        public int getAndCost()
 
326
        {
 
327
                return getMeta("and_cost");
 
328
        }
 
329
 
 
330
        public int getDisjunctCost()
 
331
        {
 
332
                return getMeta("disjunct_cost");
 
333
        }
 
334
 
 
335
        public int getLinkCost()
 
336
        {
 
337
                return getMeta("link_cost");
 
338
        }
 
339
 
 
340
        public int getNumSkippedWords()
 
341
        {
 
342
                return getMeta("num_skipped_words");
 
343
        }
 
344
 
 
345
        private int getMeta(String str)
 
346
        {
 
347
                FeatureNode fn = metaData.get(str);
 
348
                if (fn == null) return -1;
 
349
                String val = fn.getValue();
 
350
                return Integer.parseInt(val);
 
351
        }
 
352
 
 
353
        /**
 
354
         * Perform a crude parse-ranking based on Link-grammar output.
 
355
         * The ranking will be stored as the "confidence" of the 
 
356
         * TruthValue associated with this parse.
 
357
         *
 
358
         * @returns the score that was assigned.
 
359
         *
 
360
         * A classic example of competing parses for a sentence is:
 
361
         * (S (NP I) (VP saw (NP the man) (PP with (NP the binoculars))) .)
 
362
         * (S (NP I) (VP saw (NP (NP the man) (PP with (NP the binoculars)))) .)
 
363
         * The ranker below gives both about equal scores.
 
364
         *
 
365
         */
 
366
        public double simpleRankParse()
 
367
        {
 
368
                SimpleTruthValue stv = new SimpleTruthValue();
 
369
                truth_value = stv;
 
370
                stv.setMean(1.0);  // 1.0 == true -- this is a parse.
 
371
 
 
372
                // The weights used here are rather ad-hoc; but the
 
373
                // basic idea is that we want to penalize skipped words
 
374
                // strongly, but disjunct costs not as much. Low link
 
375
                // costs are the tiebreaker.
 
376
                double weight = 0.4 * getNumSkippedWords();
 
377
                weight += 0.2 * getDisjunctCost();
 
378
                weight += 0.06 * getAndCost();
 
379
                weight += 0.012 * getLinkCost();
 
380
 
 
381
                weight = Math.exp(-weight);
 
382
 
 
383
                stv.setConfidence(weight);
 
384
                return weight;
 
385
        }
 
386
        
 
387
        /**
 
388
         * Take the current parse confidence, and rescale it by the 
 
389
         * indicated amount.  The method simpleRankParse() must have
 
390
         * been previously called to perform the initial ranking.
 
391
         */
 
392
        public void rescaleRank(double weight)
 
393
        {
 
394
                SimpleTruthValue stv = (SimpleTruthValue) truth_value;
 
395
                double confidence = stv.getConfidence();
 
396
                confidence *= weight;
 
397
                stv.setConfidence(confidence);
 
398
        }
 
399
 
 
400
        public double getRank()
 
401
        {
 
402
                SimpleTruthValue stv = (SimpleTruthValue) truth_value;
 
403
                return stv.getConfidence();
 
404
        }
 
405
 
 
406
        public int hashCode()
 
407
        {
 
408
                if (original == null)
 
409
                        return 0;
 
410
                return original.hashCode() | leafConstituents.size();
 
411
        }
 
412
 
 
413
        public boolean equals(Object x)
 
414
        {
 
415
                if (! (x instanceof ParsedSentence))
 
416
                        return false;
 
417
                ParsedSentence p = (ParsedSentence)x;
 
418
                if (original == null)
 
419
                        return p.original == null;
 
420
                else
 
421
                        return original.equals(p.original) && this.leafConstituents.equals(p.leafConstituents);
 
422
        }
 
423
        
 
424
} // end ParsedSentence