shalmaneser 0.0.1.alpha → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +2 -2
  3. data/CHANGELOG.md +4 -0
  4. data/LICENSE.md +4 -0
  5. data/README.md +49 -0
  6. data/bin/fred +18 -0
  7. data/bin/frprep +34 -0
  8. data/bin/rosy +17 -0
  9. data/lib/common/AbstractSynInterface.rb +35 -33
  10. data/lib/common/Mallet.rb +236 -0
  11. data/lib/common/Maxent.rb +26 -12
  12. data/lib/common/Parser.rb +5 -5
  13. data/lib/common/SynInterfaces.rb +13 -6
  14. data/lib/common/TabFormat.rb +7 -6
  15. data/lib/common/Tiger.rb +4 -4
  16. data/lib/common/Timbl.rb +144 -0
  17. data/lib/common/{FrprepHelper.rb → frprep_helper.rb} +14 -8
  18. data/lib/common/headz.rb +1 -1
  19. data/lib/common/ruby_class_extensions.rb +3 -3
  20. data/lib/fred/FredBOWContext.rb +14 -2
  21. data/lib/fred/FredDetermineTargets.rb +4 -9
  22. data/lib/fred/FredEval.rb +1 -1
  23. data/lib/fred/FredFeatureExtractors.rb +4 -3
  24. data/lib/fred/FredFeaturize.rb +1 -1
  25. data/lib/frprep/CollinsInterface.rb +6 -6
  26. data/lib/frprep/MiniparInterface.rb +5 -5
  27. data/lib/frprep/SleepyInterface.rb +7 -7
  28. data/lib/frprep/TntInterface.rb +1 -1
  29. data/lib/frprep/TreetaggerInterface.rb +29 -5
  30. data/lib/frprep/do_parses.rb +1 -0
  31. data/lib/frprep/frprep.rb +36 -32
  32. data/lib/{common/BerkeleyInterface.rb → frprep/interfaces/berkeley_interface.rb} +69 -95
  33. data/lib/frprep/interfaces/stanford_interface.rb +353 -0
  34. data/lib/frprep/interpreters/berkeley_interpreter.rb +22 -0
  35. data/lib/frprep/interpreters/stanford_interpreter.rb +22 -0
  36. data/lib/frprep/opt_parser.rb +2 -2
  37. data/lib/rosy/AbstractFeatureAndExternal.rb +5 -3
  38. data/lib/rosy/RosyIterator.rb +11 -10
  39. data/lib/rosy/rosy.rb +1 -0
  40. data/lib/shalmaneser/version.rb +1 -1
  41. data/test/functional/sample_experiment_files/fred_test.salsa.erb +1 -1
  42. data/test/functional/sample_experiment_files/fred_train.salsa.erb +1 -1
  43. data/test/functional/sample_experiment_files/prp_test.salsa.erb +2 -2
  44. data/test/functional/sample_experiment_files/prp_test.salsa.fred.standalone.erb +2 -2
  45. data/test/functional/sample_experiment_files/prp_test.salsa.rosy.standalone.erb +2 -2
  46. data/test/functional/sample_experiment_files/prp_train.salsa.erb +2 -2
  47. data/test/functional/sample_experiment_files/prp_train.salsa.fred.standalone.erb +2 -2
  48. data/test/functional/sample_experiment_files/prp_train.salsa.rosy.standalone.erb +2 -2
  49. data/test/functional/sample_experiment_files/rosy_test.salsa.erb +1 -1
  50. data/test/functional/sample_experiment_files/rosy_train.salsa.erb +7 -7
  51. data/test/functional/test_frprep.rb +3 -3
  52. data/test/functional/test_rosy.rb +20 -0
  53. metadata +215 -224
  54. data/CHANGELOG.rdoc +0 -0
  55. data/LICENSE.rdoc +0 -0
  56. data/README.rdoc +0 -0
  57. data/lib/common/CollinsInterface.rb +0 -1165
  58. data/lib/common/MiniparInterface.rb +0 -1388
  59. data/lib/common/SleepyInterface.rb +0 -384
  60. data/lib/common/TntInterface.rb +0 -44
  61. data/lib/common/TreetaggerInterface.rb +0 -303
  62. data/lib/frprep/AbstractSynInterface.rb +0 -1227
  63. data/lib/frprep/BerkeleyInterface.rb +0 -375
  64. data/lib/frprep/ConfigData.rb +0 -694
  65. data/lib/frprep/FixSynSemMapping.rb +0 -196
  66. data/lib/frprep/FrPrepConfigData.rb +0 -66
  67. data/lib/frprep/FrprepHelper.rb +0 -1324
  68. data/lib/frprep/ISO-8859-1.rb +0 -24
  69. data/lib/frprep/Parser.rb +0 -213
  70. data/lib/frprep/SalsaTigerRegXML.rb +0 -2347
  71. data/lib/frprep/SalsaTigerXMLHelper.rb +0 -99
  72. data/lib/frprep/SynInterfaces.rb +0 -275
  73. data/lib/frprep/TabFormat.rb +0 -720
  74. data/lib/frprep/Tiger.rb +0 -1448
  75. data/lib/frprep/Tree.rb +0 -61
  76. data/lib/frprep/headz.rb +0 -338
@@ -0,0 +1,353 @@
1
+ #-*- coding: utf-8 -*-
2
+ # @author Andrei Beliankou
3
+ # <@date> 2013-12-26
4
+
5
+ ####
6
+ # sp 21 07 05
7
+ #
8
+ # modified ke 30 10 05: adapted to fit into SynInterface
9
+ #
10
+ # represents a file containing Stanford parses
11
+ #
12
+ # underlying data structure for individual sentences: SalsaTigerSentence
13
+ require "tempfile"
14
+
15
+ require "common/SalsaTigerRegXML"
16
+ require "common/SalsaTigerXMLHelper"
17
+ require "common/TabFormat"
18
+ require "common/Counter"
19
+
20
+ require "common/AbstractSynInterface"
21
+ require "common/Tiger.rb"
22
+
23
+ ################################################
24
+ # Interface class
25
+ class StanfordInterface < SynInterfaceSTXML
26
+ STDERR.puts 'Announcing Stanford Interface' if $DEBUG
27
+ StanfordInterface.announce_me
28
+
29
+ def self.system
30
+ 'stanford'
31
+ end
32
+
33
+ def self.service
34
+ 'parser'
35
+ end
36
+
37
+ ###
38
+ # initialize to set values for all subsequent processing
39
+ # @param program_path [String] path to a system
40
+ # @param insuffix [String] suffix of tab files
41
+ # @param outsuffix [String] suffix of parsed files
42
+ # @param stsuffix [String] suffix of Salsa/TigerXML files
43
+ # @param var_hash [Hash] optional arguments
44
+ def initialize(program_path, insuffix, outsuffix, stsuffix, var_hash = {})
45
+ super
46
+
47
+ # @todo This should be checked in the OptionParser.
48
+ unless @program_path =~ /\/$/
49
+ @program_path += '/'
50
+ end
51
+
52
+ # new: evaluate var hash
53
+ @pos_suffix = var_hash["pos_suffix"]
54
+ @lemma_suffix = var_hash["lemma_suffix"]
55
+ @tab_dir = var_hash["tab_dir"]
56
+
57
+ # sanity checks
58
+ # AB: @todo Move this check to the invoker!
59
+ unless @tab_dir
60
+ raise "Need to set tab directory on initialization"
61
+ end
62
+ end
63
+
64
+ ####
65
+ # parse a directory with TabFormat files and write the parse trees to outputdir
66
+ # I assume that the files in inputdir are smaller than
67
+ # the maximum number of sentences that
68
+ # Stanford can parse in one go (i.e. that they are split)
69
+ #
70
+ # @param in_dir [String] input directory name
71
+ # @param out_dir [String] output directory name
72
+ def process_dir(in_dir, out_dir)
73
+
74
+ # We use the old paradigm for now: the parser binary is wrapped
75
+ # into a shell script, we invoke this script.
76
+ #stanford_prog = "#{@program_path}lexparser-german.sh"
77
+
78
+ # Borrowed from <lexparser-german.sh>.
79
+ tlp = 'edu.stanford.nlp.parser.lexparser.NegraPennTreebankParserParams'
80
+
81
+ lang_opts = '-hMarkov 1 -vMarkov 2 -vSelSplitCutOff 300 -uwm 1 -unknownSuffixSize 2 -nodeCleanup 2'
82
+
83
+ grammar1 = 'edu/stanford/nlp/models/lexparser/germanPCFG.ser.gz'
84
+ grammar2 = 'edu/stanford/nlp/models/lexparser/germanFactored.ser.gz'
85
+
86
+ stanford_prog = %Q{
87
+ java -cp "#{@program_path}*:" edu.stanford.nlp.parser.lexparser.LexicalizedParser -maxLength 100 \
88
+ -tLPP #{tlp} #{lang_opts} -tokenized \
89
+ -encoding UTF-8 \
90
+ -outputFormat "oneline" \
91
+ -outputFormatOptions "includePunctuationDependencies" \
92
+ -loadFromSerializedFile #{grammar2} \
93
+ }
94
+
95
+ Dir[in_dir + "*" + @insuffix].each do |inputfilename|
96
+
97
+ STDERR.puts "*** Parsing #{inputfilename} with StanfordParser."
98
+ corpusfilename = File.basename(inputfilename, @insuffix)
99
+ parsefilename = out_dir + corpusfilename + @outsuffix
100
+ tempfile = Tempfile.new(corpusfilename)
101
+
102
+ # we need neither lemmata nor POS tags; stanford can do with the words
103
+ corpusfile = FNTabFormatFile.new(inputfilename, nil, nil)
104
+
105
+ corpusfile.each_sentence do |sentence|
106
+ #puts sentence
107
+ tempfile.puts sentence
108
+ end
109
+
110
+ tempfile.close
111
+
112
+ # Invoke the expternal parser.
113
+ invocation_str = "#{stanford_prog} #{tempfile.path} > #{parsefilename} 2>/dev/null"
114
+ STDERR.puts invocation_str
115
+
116
+ Kernel.system(invocation_str)
117
+
118
+ end
119
+ end
120
+
121
+ ###
122
+ # for a given parsed file:
123
+ # yield each sentence as a pair
124
+ # [SalsaTigerSentence object, FNTabFormatSentence object]
125
+ # of the sentence in SalsaTigerXML and the matching tab format sentence
126
+ #
127
+ # If a parse has failed, returns
128
+ # [failed_sentence (flat SalsaTigerSentence), FNTabFormatSentence]
129
+ # to allow more detailed accounting for failed parses
130
+ # (basically just a flat structure with a failed=true attribute
131
+ # at the sentence node)
132
+ def each_sentence(parsefilename)
133
+
134
+ # get matching tab file for this parser output file
135
+ parsefile = File.new(parsefilename)
136
+ tabfilename = @tab_dir + File.basename(parsefilename, @outsuffix) + @insuffix
137
+ tabfile = FNTabFormatFile.new(tabfilename, @postag_suffix, @lemma_suffix)
138
+
139
+ sentid = 0
140
+ tabfile.each_sentence do |tab_sent| # iterate over corpus sentences
141
+
142
+ # assemble next sentence in Stanford file by reading lines from parsefile
143
+ # for stanford:
144
+ while true
145
+ sentence_str = parsefile.gets
146
+ # Sentence contains a valid or an empty parse.
147
+ # AB: @todo Investigate how does an empty parse look like.
148
+ if sentence_str =~ /\(ROOT|TOP|PSEUDO/ or sentence_str =~ /^\(\(\)/
149
+ sentid +=1
150
+ break
151
+ # There is no parse.
152
+ elsif sentence_str.nil?
153
+ raise "Error: premature end of parser file!"
154
+ end
155
+ end
156
+
157
+ sentence_str.chomp!.gsub!(/\)\)/, ') )').gsub!(/\)\)/, ') )')
158
+
159
+ # VAFIN_HD -> VAFIN-HD
160
+ # for the current german grammar not really usefull
161
+ #sentence_str.gsub!(/(\([A-Z]+)_/, '\1-')
162
+
163
+ if tab_sent.get_sent_id == "--"
164
+ my_sent_id = "#{File.basename(parsefilename, @outsuffix)}_#{sentid}"
165
+ else
166
+ my_sent_id = tab_sent.get_sent_id
167
+ end
168
+
169
+ st_sent = build_salsatiger(" " + sentence_str + " ", 0,
170
+ [], Counter.new(0),
171
+ Counter.new(500),
172
+ SalsaTigerSentence.empty_sentence(my_sent_id.to_s))
173
+
174
+ # AB: When is it possible?
175
+ next unless st_sent
176
+
177
+ yield [st_sent, tab_sent, StanfordInterface.standard_mapping(st_sent, tab_sent)]
178
+ end
179
+
180
+ # All TabFile sentences are consumed.
181
+ # Now we may just encounter comments, garbage, empty lines etc.
182
+ while abline = parsefile.gets
183
+ case abline
184
+ when /^%/, /^\s*$/
185
+ # Found empty lines, comments, end of input indicate end of
186
+ # current parse.
187
+ # AB: TODO Investigate what can StanfordParser output.
188
+ else
189
+ # We found something meaningfull, a parse tree.
190
+ raise "Error: Premature end of tab file! Found line: #{abline}"
191
+ end
192
+ end
193
+
194
+ parsefile.close
195
+ end # each_sentence()
196
+
197
+
198
+ ###
199
+ # write Salsa/TIGER XML output to file
200
+ # @param infilename [String] name of parse file
201
+ # @param outfilename [String] name of output stxml file
202
+ def to_stxml_file(infilename, outfilename)
203
+
204
+ File.open(outfilename, 'w') do |outfile|
205
+ outfile.puts SalsaTigerXMLHelper.get_header
206
+ each_sentence(infilename) do |st_sent, tabsent|
207
+ outfile.puts st_sent.get
208
+ end
209
+ outfile.puts SalsaTigerXMLHelper.get_footer
210
+ end
211
+
212
+ end
213
+
214
+
215
+
216
+ ########################
217
+ private
218
+
219
+ ###
220
+ # Recursive function for parsing a Stanford parse tree and
221
+ # building a SalsaTigerSentence recursively
222
+ #
223
+ # Algorithm: manage stack which contains, for the current constituent,
224
+ # child constituents (if a nonterminal), and the category label.
225
+ # When the end of a constituent is reached, a new SynNode (TigerSalsa node) ist created.
226
+ # All children and the category label are popped from the stack and integrated into the
227
+ # TigerSalsa data structure. The new node is re-pushed onto the
228
+ # stack.
229
+ # @param sentence [String]
230
+ # @param pos [Fixnum] position in string (index)
231
+ # @param stack [Array] stack with incomplete nodes
232
+ # @param termc [Counter] terminal counter
233
+ # @param nontc [Counter] nonterminal counter
234
+ # @param sent_obj [SalsaTigerSentence] SalsaTigerSentence
235
+ def build_salsatiger(sentence, pos, stack, termc, nontc, sent_obj)
236
+
237
+ if sentence =~ /\(\)/
238
+ return nil
239
+ end
240
+
241
+ # main case distinction: match the beginning of our string
242
+ # (i.e. what follows our current position in the string)
243
+ case sentence[pos..-1]
244
+
245
+ when /^ *$/ # nothing -> whole sentence parsed
246
+ if stack.length == 1
247
+ # sleepy always delivers one "top" node; if we don't get just one
248
+ # node, something has gone wrong
249
+ node = stack.pop
250
+ node.del_attribute("gf")
251
+ return sent_obj
252
+ else
253
+ raise "Error: more than one root node (stack length #{stack.length}). Full sentence: \n#{sentence}"
254
+ end
255
+
256
+ when /^\s*\(([^ )]+) /
257
+ # match the beginning of a new constituent
258
+ # (opening bracket + category + space, may not contain closing bracket)
259
+ cat = $1
260
+ if cat.nil? or cat == ""
261
+ raise "Error: found category nil in sentence #{sentence[pos,10]}, full sentence\n#{sentence}"
262
+ end
263
+ # STDERR.puts "new const #{cat}"
264
+ stack.push cat # throw the category label on the stack
265
+ return build_salsatiger(sentence, pos + $&.length, stack, termc, nontc, sent_obj)
266
+
267
+ when /^\s*(\S+)\) /
268
+ # match the end of a terminal constituent (something before a closing bracket + space)
269
+ word = $1
270
+
271
+ comb_cat = stack.pop
272
+ if comb_cat.to_s == ""
273
+ raise "Empty cat at position #{sentence[pos,10]}, full sentence\n#{sentence}"
274
+ end
275
+
276
+ cat, gf = split_cat(comb_cat)
277
+ node = sent_obj.add_syn("t",
278
+ nil, # cat (doesn't matter here)
279
+ SalsaTigerXMLHelper.escape(word), # word
280
+ cat, # pos
281
+ termc.next.to_s)
282
+ node.set_attribute("gf", gf)
283
+ # STDERR.puts "completed terminal #{cat}, #{word}"
284
+ stack.push node
285
+ return build_salsatiger(sentence, pos + $&.length, stack, termc, nontc, sent_obj)
286
+
287
+ when /^\s*\)/ # match the end of a nonterminal (nothing before a closing bracket)
288
+ # now collect children:
289
+ # pop items from the stack until you find the category
290
+ children = []
291
+ while true
292
+ if stack.empty?
293
+ raise "Error: stack empty; cannot find more children"
294
+ end
295
+
296
+ item = stack.pop
297
+
298
+ case item.class.to_s
299
+ when "SynNode" # this is a child
300
+ children.push item
301
+ when "String" # this is the category label
302
+ if item.to_s == ""
303
+ raise "Empty cat at position #{sentence[pos,10]}, full sentence\n#{sentence}"
304
+ end
305
+ cat, gf = split_cat(item)
306
+ break
307
+ else
308
+ raise "Error: unknown item class #{item.class.to_s}"
309
+ end
310
+ end
311
+
312
+ # now add a nonterminal node to the sentence object and
313
+ # register the children nodes
314
+ node = sent_obj.add_syn("nt",
315
+ cat, # cat
316
+ nil, # word (doesn't matter)
317
+ nil, # pos (doesn't matter)
318
+ nontc.next.to_s)
319
+
320
+ children.each do |child|
321
+ child_gf = child.get_attribute("gf")
322
+ child.del_attribute("gf")
323
+ node.add_child(child,child_gf)
324
+ child.add_parent(node, child_gf)
325
+ end
326
+
327
+ node.set_attribute("gf", gf)
328
+ # STDERR.puts "Completed nonterm #{cat}, #{children.length} children."
329
+ stack.push node
330
+
331
+ return build_salsatiger(sentence, pos + $&.length, stack,termc, nontc, sent_obj)
332
+ else
333
+ raise "Error: cannot analyse sentence at pos #{pos}: #{sentence[pos..-1]}. Complete sentence: \n#{sentence}"
334
+ end
335
+ end
336
+
337
+ ###
338
+ # StanfordParser delivers node labels as "phrase type"-"grammatical function",
339
+ # but the GF may not be present.
340
+ # @param cat [String]
341
+ # @return [Array]
342
+ def split_cat(cat)
343
+
344
+ md = cat.match(/^([^-]*)(-([^-]*))?$/)
345
+ raise "Error: Could not identify category in #{cat}!" unless md[1]
346
+
347
+ proper_cat = md[1]
348
+ gf = md[3] ? md[3] : ''
349
+
350
+ [proper_cat, gf]
351
+ end
352
+
353
+ end
@@ -0,0 +1,22 @@
1
+ # AB: 2013-12-25
2
+ class BerkeleyInterpreter < Tiger
3
+ BerkeleyInterpreter.announce_me
4
+
5
+ ###
6
+ # names of the systems interpreted by this class:
7
+ # returns a hash service(string) -> system name (string),
8
+ # e.g.
9
+ # { "parser" => "collins", "lemmatizer" => "treetagger" }
10
+ def self.systems
11
+ {"parser" => "berkeley"}
12
+ end
13
+
14
+ ###
15
+ # names of additional systems that may be interpreted by this class
16
+ # returns a hash service(string) -> system name(string)
17
+ # same as names()
18
+ def self.optional_systems
19
+ {"lemmatizer" => "treetagger", 'pos_tagger' => 'treetagger'}
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ # AB: 2013-12-25
2
+ class StanfordInterpreter < Tiger
3
+ StanfordInterpreter.announce_me
4
+
5
+ ###
6
+ # names of the systems interpreted by this class:
7
+ # returns a hash service(string) -> system name (string),
8
+ # e.g.
9
+ # { "parser" => "collins", "lemmatizer" => "treetagger" }
10
+ def self.systems
11
+ {"parser" => "stanford"}
12
+ end
13
+
14
+ ###
15
+ # names of additional systems that may be interpreted by this class
16
+ # returns a hash service(string) -> system name(string)
17
+ # same as names()
18
+ def self.optional_systems
19
+ {"lemmatizer" => "treetagger", 'pos_tagger' => 'treetagger'}
20
+ end
21
+
22
+ end
@@ -3,8 +3,8 @@
3
3
  # AB, 2010-11-25
4
4
 
5
5
  require 'optparse'
6
- require 'frprep/FrPrepConfigData'
7
- require 'frprep/SynInterfaces'
6
+ require 'common/FrPrepConfigData'
7
+ require 'common/SynInterfaces'
8
8
  module FrPrep
9
9
 
10
10
  # This class parses options for FrPrep.
@@ -112,8 +112,9 @@ class AbstractFeatureExtractor
112
112
  end
113
113
 
114
114
  ###
115
- def initialize(exp, # ConfigData object: experiment file information
116
- interpreter_class)
115
+ # @param exp [ConfigData] Experiment file information
116
+ # @param interpreter_class [Class]
117
+ def initialize(exp, interpreter_class)
117
118
  @exp = exp
118
119
  @@interpreter_class = interpreter_class
119
120
  end
@@ -149,7 +150,8 @@ class AbstractFeatureExtractor
149
150
  protected
150
151
 
151
152
  def AbstractFeatureExtractor.announce_me()
152
- if Module.constants.include? "RosyFeatureInfo"
153
+ # AB: In 1.9 constants are symbols.
154
+ if Module.constants.include?("RosyFeatureInfo") or Module.constants.include?(:RosyFeatureInfo)
153
155
  # yup, we have a class to which we can announce ourselves
154
156
  RosyFeatureInfo.add_feature(eval(self.name()))
155
157
  else
@@ -271,11 +271,11 @@ class RosyIterator
271
271
  # column_name = value, columnb_name != value), which may be omitted
272
272
  #
273
273
  # returns: DBView object
274
- def get_a_view_for_current_group(columns, # array:string, column names to include
275
- # or string: "*" for all columns
276
- value_restrictions = []) # array:ValueRestriction objects
277
- return get_a_view_for_group(@current_group, columns,
278
- value_restrictions)
274
+ # @param columns [Array] array:string, column names to include
275
+ # or string: "*" for all columns
276
+ # @param value_restrictions [Array] array:ValueRestriction objects
277
+ def get_a_view_for_current_group(columns, value_restrictions = [])
278
+ get_a_view_for_group(@current_group, columns, value_restrictions)
279
279
  end
280
280
 
281
281
  ####
@@ -292,11 +292,12 @@ class RosyIterator
292
292
  # column_name = value, columnb_name != value), which may be omitted
293
293
  #
294
294
  # returns: DBView object
295
- def get_a_view_for_group(group, # hash: column(string)->value(object)
296
- # describing the group
297
- columns, # array:string, column names to include
298
- # or string: "*" for all columns
299
- value_restrictions = []) # array:ValueRestriction objects
295
+ # @param group [Hash] column(string)->value(object)
296
+ # describing the group
297
+ # @param columns [Array] array:string, column names to include
298
+ # or string: "*" for all columns
299
+ # @param value_restrictions [Array] of ValueRestriction objects
300
+ def get_a_view_for_group(group, columns, value_restrictions = [])
300
301
 
301
302
  # value_restrictions needs to be an array
302
303
  if value_restrictions.nil?