glaemscribe 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +19 -0
- data/bin/glaemscribe +307 -0
- data/glaemresources/charsets/cirth_ds.cst +205 -0
- data/glaemresources/charsets/sarati_eldamar.cst +256 -0
- data/glaemresources/charsets/tengwar_ds.cst +318 -0
- data/glaemresources/charsets/unicode_gothic.cst +64 -0
- data/glaemresources/charsets/unicode_runes.cst +120 -0
- data/glaemresources/modes/adunaic.glaem +251 -0
- data/glaemresources/modes/blackspeech-annatar.glaem +318 -0
- data/glaemresources/modes/blackspeech.glaem +260 -0
- data/glaemresources/modes/gothic.glaem +78 -0
- data/glaemresources/modes/khuzdul.glaem +141 -0
- data/glaemresources/modes/mercian.glaem +419 -0
- data/glaemresources/modes/oldnorse-medieval.glaem +127 -0
- data/glaemresources/modes/quenya-sarati.glaem +320 -0
- data/glaemresources/modes/quenya.glaem +307 -0
- data/glaemresources/modes/sindarin-beleriand.glaem +285 -0
- data/glaemresources/modes/sindarin-classical.glaem +276 -0
- data/glaemresources/modes/sindarin-daeron.glaem +182 -0
- data/glaemresources/modes/telerin.glaem +302 -0
- data/glaemresources/modes/valarin-sarati.glaem +210 -0
- data/glaemresources/modes/westron.glaem +340 -0
- data/glaemresources/modes/westsaxon.glaem +342 -0
- data/lib/api/charset.rb +84 -0
- data/lib/api/charset_parser.rb +55 -0
- data/lib/api/constants.rb +29 -0
- data/lib/api/debug.rb +36 -0
- data/lib/api/eval.rb +268 -0
- data/lib/api/fragment.rb +113 -0
- data/lib/api/glaeml.rb +200 -0
- data/lib/api/if_tree.rb +96 -0
- data/lib/api/mode.rb +112 -0
- data/lib/api/mode_parser.rb +314 -0
- data/lib/api/option.rb +64 -0
- data/lib/api/post_processor/reverse.rb +36 -0
- data/lib/api/pre_processor/downcase.rb +35 -0
- data/lib/api/pre_processor/elvish_numbers.rb +47 -0
- data/lib/api/pre_processor/rxsubstitute.rb +40 -0
- data/lib/api/pre_processor/substitute.rb +38 -0
- data/lib/api/pre_processor/up_down_tehta_split.rb +138 -0
- data/lib/api/resource_manager.rb +130 -0
- data/lib/api/rule.rb +99 -0
- data/lib/api/rule_group.rb +159 -0
- data/lib/api/sheaf.rb +70 -0
- data/lib/api/sheaf_chain.rb +86 -0
- data/lib/api/sheaf_chain_iterator.rb +108 -0
- data/lib/api/sub_rule.rb +40 -0
- data/lib/api/transcription_pre_post_processor.rb +118 -0
- data/lib/api/transcription_processor.rb +137 -0
- data/lib/api/transcription_tree_node.rb +91 -0
- data/lib/glaemscribe.rb +70 -0
- metadata +112 -0
data/lib/api/rule.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Glǽmscribe (also written Glaemscribe) is a software dedicated to
|
4
|
+
# the transcription of texts between writing systems, and more
|
5
|
+
# specifically dedicated to the transcription of J.R.R. Tolkien's
|
6
|
+
# invented languages to some of his devised writing systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2015 Benjamin Babut (Talagan).
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU Affero General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU Affero General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU Affero General Public License
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
|
23
|
+
module Glaemscribe
|
24
|
+
module API
|
25
|
+
class Rule
|
26
|
+
|
27
|
+
attr_accessor :line
|
28
|
+
attr_accessor :src_sheaf_chain, :dst_sheaf_chain
|
29
|
+
attr_reader :sub_rules
|
30
|
+
attr_reader :mode
|
31
|
+
attr_reader :errors
|
32
|
+
|
33
|
+
def initialize(line, rule_group)
|
34
|
+
@line = line
|
35
|
+
@rule_group = rule_group
|
36
|
+
@mode = @rule_group.mode
|
37
|
+
@sub_rules = []
|
38
|
+
@errors = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def finalize(cross_schema)
|
42
|
+
|
43
|
+
if(@errors.any?)
|
44
|
+
@errors.each { |e|
|
45
|
+
@mode.errors << Glaeml::Error.new(@line, e)
|
46
|
+
}
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
srccounter = SheafChainIterator.new(@src_sheaf_chain)
|
51
|
+
dstcounter = SheafChainIterator.new(@dst_sheaf_chain, cross_schema)
|
52
|
+
|
53
|
+
if(srccounter.errors.any?)
|
54
|
+
srccounter.errors.each{ |e| @mode.errors << Glaeml::Error.new(@line, e) }
|
55
|
+
return
|
56
|
+
end
|
57
|
+
|
58
|
+
if(dstcounter.errors.any?)
|
59
|
+
dstcounter.errors.each{ |e| @mode.errors << Glaeml::Error.new(@line, e) }
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
srcp = srccounter.prototype
|
64
|
+
dstp = dstcounter.prototype
|
65
|
+
|
66
|
+
if srcp != dstp
|
67
|
+
@mode.errors << Glaeml::Error.new(@line, "Source and destination are not compatible (#{srcp} vs #{dstp})")
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
|
73
|
+
# All equivalent combinations ...
|
74
|
+
src_combinations = srccounter.combinations
|
75
|
+
|
76
|
+
# ... should be sent to one destination
|
77
|
+
dst_combination = dstcounter.combinations.first
|
78
|
+
|
79
|
+
src_combinations.each{ |src_combination|
|
80
|
+
@sub_rules << SubRule.new(self, src_combination, dst_combination)
|
81
|
+
}
|
82
|
+
|
83
|
+
dstcounter.iterate()
|
84
|
+
end while srccounter.iterate()
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
def p
|
89
|
+
ret = ("=" * 30) + "\n"
|
90
|
+
@sub_rules.each{ |sr|
|
91
|
+
ret += sr.p
|
92
|
+
}
|
93
|
+
ret
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Glǽmscribe (also written Glaemscribe) is a software dedicated to
|
4
|
+
# the transcription of texts between writing systems, and more
|
5
|
+
# specifically dedicated to the transcription of J.R.R. Tolkien's
|
6
|
+
# invented languages to some of his devised writing systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2015 Benjamin Babut (Talagan).
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU Affero General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU Affero General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU Affero General Public License
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
|
23
|
+
module Glaemscribe
|
24
|
+
module API
|
25
|
+
class RuleGroup
|
26
|
+
|
27
|
+
VAR_NAME_REGEXP = /{([0-9A-Z_]+)}/
|
28
|
+
VAR_DECL_REGEXP = /^\s*{([0-9A-Z_]+)}\s+===\s+(.+?)\s*$/
|
29
|
+
RULE_REGEXP = /^\s*(.*?)\s+-->\s+(.+?)\s*$/
|
30
|
+
CROSS_RULE_REGEXP = /^\s*(.*?)\s+-->\s+([\s0-9,]+)\s+-->\s+(.+?)\s*$/
|
31
|
+
|
32
|
+
attr_reader :root_code_block, :name, :mode, :in_charset, :rules
|
33
|
+
|
34
|
+
def initialize(mode,name)
|
35
|
+
@name = name
|
36
|
+
@mode = mode
|
37
|
+
@root_code_block = IfTree::CodeBlock.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_var(var_name, value)
|
41
|
+
@vars[var_name] = value
|
42
|
+
end
|
43
|
+
|
44
|
+
# Replace all vars in expression
|
45
|
+
def apply_vars(line, string)
|
46
|
+
ret = string.gsub(VAR_NAME_REGEXP) { |cap_var|
|
47
|
+
rep = @vars[$1]
|
48
|
+
if !rep
|
49
|
+
@mode.errors << Glaeml::Error.new(line, "In expression: #{string}: failed to evaluate variable: #{cap_var}.")
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
rep
|
53
|
+
}
|
54
|
+
ret
|
55
|
+
end
|
56
|
+
|
57
|
+
def descend_if_tree(code_block, trans_options)
|
58
|
+
code_block.terms.each{ |term|
|
59
|
+
if(term.is_code_lines?)
|
60
|
+
term.code_lines.each{ |cl|
|
61
|
+
finalize_code_line(cl)
|
62
|
+
}
|
63
|
+
else
|
64
|
+
term.if_conds.each{ |if_cond|
|
65
|
+
|
66
|
+
if_eval = Eval::Parser.new()
|
67
|
+
|
68
|
+
begin
|
69
|
+
if(if_eval.parse(if_cond.expression,trans_options) == true)
|
70
|
+
descend_if_tree(if_cond.child_code_block, trans_options)
|
71
|
+
break
|
72
|
+
end
|
73
|
+
rescue IfEvalError => e
|
74
|
+
@mode.errors << Glaeml::Error.new(if_cond.line, "Failed to evaluate condition '#{if_cond.expression}' (#{e})")
|
75
|
+
end
|
76
|
+
|
77
|
+
}
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def finalize_rule(line, match_exp, replacement_exp, cross_schema = nil)
|
83
|
+
|
84
|
+
match = apply_vars(line, match_exp)
|
85
|
+
replacement = apply_vars(line, replacement_exp)
|
86
|
+
|
87
|
+
return if !match || !replacement # Failed
|
88
|
+
|
89
|
+
rule = Rule.new(line, self)
|
90
|
+
rule.src_sheaf_chain = SheafChain.new(rule,match,true)
|
91
|
+
rule.dst_sheaf_chain = SheafChain.new(rule,replacement,false)
|
92
|
+
|
93
|
+
rule.finalize(cross_schema)
|
94
|
+
|
95
|
+
self.rules << rule
|
96
|
+
end
|
97
|
+
|
98
|
+
def finalize_code_line(code_line)
|
99
|
+
begin
|
100
|
+
|
101
|
+
if code_line.expression =~ VAR_DECL_REGEXP
|
102
|
+
|
103
|
+
var_name = $1
|
104
|
+
var_value_ex = $2
|
105
|
+
var_value = apply_vars(code_line.line, var_value_ex)
|
106
|
+
|
107
|
+
if !var_value
|
108
|
+
@mode.errors << Glaeml::Error.new(code_line.line, "Thus, variable {#{var_name}} could not be declared.")
|
109
|
+
return
|
110
|
+
end
|
111
|
+
|
112
|
+
add_var(var_name,var_value)
|
113
|
+
|
114
|
+
elsif code_line.expression =~ CROSS_RULE_REGEXP
|
115
|
+
|
116
|
+
match = $1
|
117
|
+
cross = $2
|
118
|
+
replacement = $3
|
119
|
+
|
120
|
+
finalize_rule(code_line.line, match, replacement, cross)
|
121
|
+
|
122
|
+
elsif code_line.expression =~ RULE_REGEXP
|
123
|
+
|
124
|
+
match = $1
|
125
|
+
replacement = $2
|
126
|
+
|
127
|
+
finalize_rule(code_line.line, match, replacement)
|
128
|
+
|
129
|
+
elsif code_line.expression.empty?
|
130
|
+
# puts "Empty"
|
131
|
+
else
|
132
|
+
@mode.errors << Glaeml::Error.new(code_line.line,"Cannot understand: #{code_line.expression}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def finalize(trans_options)
|
138
|
+
@vars = {}
|
139
|
+
@in_charset = {}
|
140
|
+
@rules = []
|
141
|
+
|
142
|
+
add_var("NULL","")
|
143
|
+
|
144
|
+
descend_if_tree(@root_code_block, trans_options)
|
145
|
+
|
146
|
+
# Now that we have selected our rules, create the in_charset of the rule_group
|
147
|
+
rules.each{ |r|
|
148
|
+
r.sub_rules.each { |sr|
|
149
|
+
sr.src_combination.join("").split(//).each{ |inchar|
|
150
|
+
# Add the character to the map of input characters
|
151
|
+
# Ignore '_' (bounds of word) and '|' (word breaker)
|
152
|
+
@in_charset[inchar] = self if inchar != WORD_BREAKER && inchar != WORD_BOUNDARY
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/api/sheaf.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Glǽmscribe (also written Glaemscribe) is a software dedicated to
|
4
|
+
# the transcription of texts between writing systems, and more
|
5
|
+
# specifically dedicated to the transcription of J.R.R. Tolkien's
|
6
|
+
# invented languages to some of his devised writing systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2015 Benjamin Babut (Talagan).
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU Affero General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU Affero General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU Affero General Public License
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
#
|
23
|
+
# A Sheaf is a bundle of Fragments. They are used to factorize the writing process of rules, and thus represent parallel rules.
|
24
|
+
# For exemple [(a|ä),b,c] => [1,2,3] means that we send one sheaf to another, defining 4 rules:
|
25
|
+
# a => 1
|
26
|
+
# ä => 1
|
27
|
+
# b => 2
|
28
|
+
# c => 3
|
29
|
+
|
30
|
+
module Glaemscribe
|
31
|
+
module API
|
32
|
+
class Sheaf
|
33
|
+
|
34
|
+
attr_reader :fragments
|
35
|
+
attr_reader :sheaf_chain
|
36
|
+
attr_reader :mode
|
37
|
+
attr_reader :rule
|
38
|
+
|
39
|
+
SHEAF_SEPARATOR = "*"
|
40
|
+
|
41
|
+
def src?; @sheaf_chain.src?; end
|
42
|
+
def dst?; @sheaf_chain.dst?; end
|
43
|
+
|
44
|
+
# Should pass a sheaf expression, e.g. : "h, s, t"
|
45
|
+
def initialize(sheaf_chain, expression)
|
46
|
+
|
47
|
+
@sheaf_chain = sheaf_chain
|
48
|
+
@mode = sheaf_chain.mode
|
49
|
+
@rule = sheaf_chain.rule
|
50
|
+
@expression = expression
|
51
|
+
|
52
|
+
# Split members using "*" separator, KEEP NULL MEMBERS (this is legal)
|
53
|
+
fragment_exps = expression.split(SHEAF_SEPARATOR,-1).map{|fragment_exp| fragment_exp.strip }
|
54
|
+
fragment_exps = [""] if fragment_exps.empty? # For NULL
|
55
|
+
|
56
|
+
# Build the fragments inside
|
57
|
+
@fragments = fragment_exps.map{ |fragment_exp| Fragment.new(self, fragment_exp) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def p
|
61
|
+
ret = "-- " + @expression + "\n"
|
62
|
+
@fragments.each{ |l|
|
63
|
+
ret += l.p
|
64
|
+
}
|
65
|
+
ret
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Glǽmscribe (also written Glaemscribe) is a software dedicated to
|
4
|
+
# the transcription of texts between writing systems, and more
|
5
|
+
# specifically dedicated to the transcription of J.R.R. Tolkien's
|
6
|
+
# invented languages to some of his devised writing systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2015 Benjamin Babut (Talagan).
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU Affero General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU Affero General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU Affero General Public License
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
#
|
23
|
+
# A sheaf chain is a sequence of sheaves. e.g. :
|
24
|
+
#
|
25
|
+
# With a global rule of : src => res
|
26
|
+
# Where src = "[a,b,c][d,e,f]"
|
27
|
+
# and res = "[x,y,z][1,2,3]"
|
28
|
+
#
|
29
|
+
# The generated rules is a list of 9 parallel rules:
|
30
|
+
# ad => x1, ae => x2, af => res => x3
|
31
|
+
# bd => y1, be => y2, etc...
|
32
|
+
#
|
33
|
+
# Or, more complicated: "[m,(b|p)](h|y)[a,e]"
|
34
|
+
# Will generate the following equivalences:
|
35
|
+
# mha = mya
|
36
|
+
# mhe = mye
|
37
|
+
# bha = pha = bya = pya
|
38
|
+
# bhe = phe = bye = phe
|
39
|
+
|
40
|
+
module Glaemscribe
|
41
|
+
module API
|
42
|
+
class SheafChain
|
43
|
+
|
44
|
+
SHEAF_REGEXP_IN = /\[(.*?)\]/
|
45
|
+
SHEAF_REGEXP_OUT = /(\[.*?\])/
|
46
|
+
|
47
|
+
attr_reader :is_src
|
48
|
+
attr_reader :sheaves
|
49
|
+
attr_reader :mode
|
50
|
+
attr_reader :rule
|
51
|
+
|
52
|
+
def src? ; is_src ; end
|
53
|
+
def dst? ; !is_src ; end
|
54
|
+
|
55
|
+
# Pass in the whole member of a rule src => dst (src or dst)
|
56
|
+
def initialize(rule, expression, is_src)
|
57
|
+
@rule = rule
|
58
|
+
@mode = rule.mode
|
59
|
+
@is_src = is_src
|
60
|
+
@expression = expression
|
61
|
+
|
62
|
+
# Split expression with '[...]' patterns. e.g. 'b[a*c*d]e' => [b, a*c*d, e]
|
63
|
+
sheaf_exps = expression.split(SHEAF_REGEXP_OUT).map{ |elt| elt.strip }.reject{ |elt| elt.empty? }
|
64
|
+
sheaf_exps = sheaf_exps.map { |sheaf_exp|
|
65
|
+
sheaf_exp =~ SHEAF_REGEXP_IN
|
66
|
+
sheaf_exp = $1 if $1 # Take the interior of the brackets it was a [...] expression
|
67
|
+
sheaf_exp.strip
|
68
|
+
}
|
69
|
+
|
70
|
+
@sheaves = sheaf_exps.map{ |sheaf_exp| Sheaf.new(self,sheaf_exp) }
|
71
|
+
@sheaves = [Sheaf.new(self,"")] if @sheaves.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
def p
|
75
|
+
ret = ("*" * 30)
|
76
|
+
ret += "\n"
|
77
|
+
ret += @expression + "\n"
|
78
|
+
@sheaves.each{ |s|
|
79
|
+
ret += s.p
|
80
|
+
}
|
81
|
+
ret
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Glǽmscribe (also written Glaemscribe) is a software dedicated to
|
4
|
+
# the transcription of texts between writing systems, and more
|
5
|
+
# specifically dedicated to the transcription of J.R.R. Tolkien's
|
6
|
+
# invented languages to some of his devised writing systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2015 Benjamin Babut (Talagan).
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU Affero General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
13
|
+
# any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU Affero General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU Affero General Public License
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
|
23
|
+
module Glaemscribe
|
24
|
+
module API
|
25
|
+
class SheafChainIterator
|
26
|
+
|
27
|
+
attr_accessor :sheaf_chain
|
28
|
+
attr_accessor :cross_map
|
29
|
+
attr_accessor :errors
|
30
|
+
|
31
|
+
# If a cross schema is passed, the prototype of the chain will be permutated
|
32
|
+
def initialize(sheaf_chain, cross_schema = nil)
|
33
|
+
@sheaf_chain = sheaf_chain
|
34
|
+
# Sizes contains the number of fragments/sheaf
|
35
|
+
@sizes = sheaf_chain.sheaves.map { |sheaf| sheaf.fragments.count }
|
36
|
+
# An array of counters, one for each sheaf, to increment on fragments
|
37
|
+
@iterators = Array.new(@sizes.count,0)
|
38
|
+
|
39
|
+
@errors = []
|
40
|
+
|
41
|
+
# Construct the identity array
|
42
|
+
identity_cross_array = []
|
43
|
+
sheaf_count = sheaf_chain.sheaves.count
|
44
|
+
sheaf_count.times{|i| identity_cross_array << i+1}
|
45
|
+
|
46
|
+
# Construct the cross array
|
47
|
+
if cross_schema
|
48
|
+
@cross_array = cross_schema.split(",").map{ |i| i.to_i }
|
49
|
+
ca_count = @cross_array.count
|
50
|
+
@errors << "#{sheaf_count} sheafs found in right predicate, but #{ca_count} elements in cross rule." if ca_count != sheaf_count
|
51
|
+
@errors << "Cross rule should contain each element of #{identity_cross_array} once and only once." if identity_cross_array != @cross_array.sort
|
52
|
+
else
|
53
|
+
@cross_array = identity_cross_array
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Calculate the prototype of the chain
|
58
|
+
def prototype
|
59
|
+
res = @sizes.clone
|
60
|
+
res2 = @sizes.clone
|
61
|
+
|
62
|
+
res.count.times{ |i| res2[i] = res[@cross_array[i]-1] }
|
63
|
+
res = res2
|
64
|
+
|
65
|
+
# Remove all sheaves of size 1 (which are constant)
|
66
|
+
res.delete(1)
|
67
|
+
|
68
|
+
# Create a prototype string
|
69
|
+
res = res.join("x")
|
70
|
+
res = "1" if res.empty?
|
71
|
+
res
|
72
|
+
end
|
73
|
+
|
74
|
+
def iterate
|
75
|
+
pos = 0
|
76
|
+
while pos < @sizes.count do
|
77
|
+
realpos = @cross_array[pos]-1
|
78
|
+
@iterators[realpos] += 1
|
79
|
+
if @iterators[realpos] >= @sizes[realpos]
|
80
|
+
@iterators[realpos] = 0
|
81
|
+
pos += 1
|
82
|
+
else
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# Wrapped!
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
|
90
|
+
# Calculate all cominations for the chain
|
91
|
+
def combinations
|
92
|
+
resolved = []
|
93
|
+
@iterators.each_with_index{ |counter, index|
|
94
|
+
sheaf = sheaf_chain.sheaves[index]
|
95
|
+
fragment = sheaf.fragments[counter]
|
96
|
+
|
97
|
+
resolved << fragment.combinations
|
98
|
+
}
|
99
|
+
res = resolved[0]
|
100
|
+
(resolved.count-1).times { |i|
|
101
|
+
res = res.product(resolved[i+1]).map{|e1,e2| e1+e2}
|
102
|
+
}
|
103
|
+
res
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|