mgmg 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -1
- data/README.md +31 -212
- data/lib/mgmg/const.rb +2 -1
- data/lib/mgmg/equip.rb +49 -46
- data/lib/mgmg/ir.rb +373 -0
- data/lib/mgmg/optimize.rb +213 -0
- data/lib/mgmg/poly.rb +81 -0
- data/lib/mgmg/search.rb +365 -0
- data/lib/mgmg/utils.rb +54 -2
- data/lib/mgmg/version.rb +1 -1
- data/lib/mgmg.rb +80 -56
- data/reference.md +289 -0
- metadata +11 -7
data/lib/mgmg/search.rb
ADDED
@@ -0,0 +1,365 @@
|
|
1
|
+
class String
|
2
|
+
def smith_search(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
3
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
4
|
+
if smith_min.nil?
|
5
|
+
if min_smith
|
6
|
+
smith_min = self.min_smith.min_smith
|
7
|
+
else
|
8
|
+
smith_min = build(-1, -1, left_associative: left_associative).min_level
|
9
|
+
end
|
10
|
+
end
|
11
|
+
if smith_max < smith_min
|
12
|
+
raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
|
13
|
+
elsif cut_exp < Float::INFINITY
|
14
|
+
begin
|
15
|
+
smith_max = [smith_max, Mgmg.invexp2(cut_exp, comp)].min
|
16
|
+
rescue
|
17
|
+
raise Mgmg::SearchCutException
|
18
|
+
end
|
19
|
+
end
|
20
|
+
if target <= irep.para_call(para, smith_min, comp)
|
21
|
+
return smith_min
|
22
|
+
elsif irep.para_call(para, smith_max, comp) < target
|
23
|
+
raise Mgmg::SearchCutException
|
24
|
+
end
|
25
|
+
while 1 < smith_max - smith_min do
|
26
|
+
smith = (smith_max - smith_min).div(2) + smith_min
|
27
|
+
if irep.para_call(para, smith, comp) < target
|
28
|
+
smith_min = smith
|
29
|
+
else
|
30
|
+
smith_max = smith
|
31
|
+
end
|
32
|
+
end
|
33
|
+
smith_max
|
34
|
+
end
|
35
|
+
def comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true, irep: nil)
|
36
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
37
|
+
comp_min = min_comp(left_associative: left_associative)
|
38
|
+
if comp_max < comp_min
|
39
|
+
raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
|
40
|
+
end
|
41
|
+
if target <= irep.para_call(para, smith, comp_min)
|
42
|
+
return comp_min
|
43
|
+
elsif irep.para_call(para, smith, comp_max) < target
|
44
|
+
raise Mgmg::SearchCutException
|
45
|
+
end
|
46
|
+
while 1 < comp_max - comp_min do
|
47
|
+
comp = (comp_max - comp_min).div(2) + comp_min
|
48
|
+
if irep.para_call(para, smith, comp) < target
|
49
|
+
comp_min = comp
|
50
|
+
else
|
51
|
+
comp_max = comp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
comp_max
|
55
|
+
end
|
56
|
+
def search(para, target, smith_min=nil, comp_min=nil, smith_max=10000, comp_max=10000, left_associative: true, step: 1, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
57
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
58
|
+
if smith_min.nil?
|
59
|
+
if min_smith
|
60
|
+
smith_min = self.min_smith
|
61
|
+
else
|
62
|
+
smith_min = build(-1, -1, left_associative: left_associative).min_level
|
63
|
+
end
|
64
|
+
end
|
65
|
+
comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
|
66
|
+
comp_min = comp_search(para, target, smith_max, comp_min, comp_max, left_associative: left_associative, irep: irep)
|
67
|
+
smith_max = smith_search(para, target, comp_min, smith_min, smith_max, left_associative: left_associative, irep: irep)
|
68
|
+
smith_min = smith_search(para, target, comp_max, smith_min, smith_max, left_associative: left_associative, irep: irep)
|
69
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, comp_min)
|
70
|
+
comp_max = comp_search(para, target, smith_min, comp_min, comp_max, left_associative: left_associative, irep: irep)
|
71
|
+
minex, ret = Mgmg.exp(smith_min, comp_max), [smith_min, comp_max]
|
72
|
+
exp = Mgmg.exp(smith_max, comp_min)
|
73
|
+
minex, ret = exp, [smith_max, comp_min] if exp < minex
|
74
|
+
(comp_min+step).step(comp_max-1, step) do |comp|
|
75
|
+
break if minex < Mgmg.exp(smith_min, comp)
|
76
|
+
smith = smith_search(para, target, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
|
77
|
+
exp = Mgmg.exp(smith, comp)
|
78
|
+
if exp < minex
|
79
|
+
minex, ret = exp, [smith, comp]
|
80
|
+
elsif exp == minex
|
81
|
+
if irep.para_call(para, *ret) < irep.para_call(para, smith, comp)
|
82
|
+
ret = [smith, comp]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
rescue Mgmg::SearchCutException
|
86
|
+
end
|
87
|
+
raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
|
88
|
+
ret
|
89
|
+
end
|
90
|
+
end
|
91
|
+
module Enumerable
|
92
|
+
def smith_search(para, target, armor, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
93
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
94
|
+
if smith_min.nil?
|
95
|
+
if min_smith
|
96
|
+
smith_min = self.min_smith[0]
|
97
|
+
else
|
98
|
+
smith_min = build(-1, -1, -1, left_associative: left_associative).min_level[0]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
if smith_max < smith_min
|
102
|
+
raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
|
103
|
+
elsif cut_exp < Float::INFINITY
|
104
|
+
begin
|
105
|
+
smith_max = [smith_max, Mgmg.invexp3(cut_exp, armor, comp)].min
|
106
|
+
rescue
|
107
|
+
raise Mgmg::SearchCutException
|
108
|
+
end
|
109
|
+
end
|
110
|
+
if irep.para_call(para, smith_max, armor, comp) < target
|
111
|
+
raise Mgmg::SearchCutException
|
112
|
+
elsif target <= irep.para_call(para, smith_min, armor, comp)
|
113
|
+
return smith_min
|
114
|
+
end
|
115
|
+
while 1 < smith_max - smith_min do
|
116
|
+
smith = (smith_max - smith_min).div(2) + smith_min
|
117
|
+
if irep.para_call(para, smith, armor, comp) < target
|
118
|
+
smith_min = smith
|
119
|
+
else
|
120
|
+
smith_max = smith
|
121
|
+
end
|
122
|
+
end
|
123
|
+
smith_max
|
124
|
+
end
|
125
|
+
def armor_search(para, target, smith, comp, armor_min=nil, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
126
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
127
|
+
if armor_min.nil?
|
128
|
+
if min_smith
|
129
|
+
armor_min = self.min_smith[1]
|
130
|
+
else
|
131
|
+
armor_min = build(-1, -1, -1, left_associative: left_associative).min_level[1]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
if armor_max < armor_min
|
135
|
+
raise ArgumentError, "armor_min <= armor_max is needed, (armor_min, armor_max) = (#{armor_min}, #{armor_max}) are given"
|
136
|
+
elsif cut_exp < Float::INFINITY
|
137
|
+
begin
|
138
|
+
armor_max = [armor_max, Mgmg.invexp3(cut_exp, smith, comp)].min
|
139
|
+
rescue
|
140
|
+
raise Mgmg::SearchCutException
|
141
|
+
end
|
142
|
+
end
|
143
|
+
if irep.para_call(para, smith, armor_max, comp) < target
|
144
|
+
raise Mgmg::SearchCutException
|
145
|
+
elsif target <= irep.para_call(para, smith, armor_min, comp)
|
146
|
+
return armor_min
|
147
|
+
end
|
148
|
+
while 1 < armor_max - armor_min do
|
149
|
+
armor = (armor_max - armor_min).div(2) + armor_min
|
150
|
+
if irep.para_call(para, smith, armor, comp) < target
|
151
|
+
armor_min = armor
|
152
|
+
else
|
153
|
+
armor_max = armor
|
154
|
+
end
|
155
|
+
end
|
156
|
+
armor_max
|
157
|
+
end
|
158
|
+
def sa_search(para, target, comp, smith_min=nil, armor_min=nil, smith_max=10000, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
159
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
160
|
+
if min_smith
|
161
|
+
s, a = self.min_smith
|
162
|
+
else
|
163
|
+
s, a = build(-1, -1, -1, left_associative: left_associative).min_level
|
164
|
+
end
|
165
|
+
smith_min = s if smith_min.nil?
|
166
|
+
armor_min = a if armor_min.nil?
|
167
|
+
smith_min = smith_search(para, target, armor_max, comp, smith_min, smith_max, left_associative: true, irep: irep)
|
168
|
+
armor_min = armor_search(para, target, smith_max, comp, armor_min, armor_max, left_associative: true, irep: irep)
|
169
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp)
|
170
|
+
smith_max = smith_search(para, target, armor_min, comp, smith_min, smith_max, left_associative: true, irep: irep)
|
171
|
+
armor_max = armor_search(para, target, smith_min, comp, armor_min, armor_max, left_associative: true, irep: irep)
|
172
|
+
minex, ret = Mgmg.exp(smith_min, armor_max, comp), [smith_min, armor_max]
|
173
|
+
exp = Mgmg.exp(smith_max, armor_min, comp)
|
174
|
+
if exp < minex
|
175
|
+
minex, ret = exp, [smith_max, armor_min]
|
176
|
+
(armor_min+1).upto(armor_max-1) do |armor|
|
177
|
+
break if minex < Mgmg.exp(smith_min, armor, comp)
|
178
|
+
smith = smith_search(para, target, armor, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min, irep: irep)
|
179
|
+
exp = Mgmg.exp(smith, armor, comp)
|
180
|
+
if exp < minex
|
181
|
+
minex, ret = exp, [smith, armor]
|
182
|
+
elsif exp == minex
|
183
|
+
if irep.para_call(para, *ret, comp) < irep.para_call(para, smith, armor, comp)
|
184
|
+
ret = [smith, armor]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
rescue Mgmg::SearchCutException
|
188
|
+
end
|
189
|
+
else
|
190
|
+
(smith_min+1).upto(smith_max-1) do |smith|
|
191
|
+
break if minex < Mgmg.exp(smith, armor_min, comp)
|
192
|
+
armor = armor_search(para, target, smith, comp, armor_min, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min, irep: irep)
|
193
|
+
exp = Mgmg.exp(smith, armor, comp)
|
194
|
+
if exp < minex
|
195
|
+
minex, ret = exp, [smith, armor]
|
196
|
+
elsif exp == minex
|
197
|
+
if irep.para_call(para, *ret, comp) < irep.para_call(para, smith, armor, comp)
|
198
|
+
ret = [smith, armor]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
rescue Mgmg::SearchCutException
|
202
|
+
end
|
203
|
+
end
|
204
|
+
raise Mgmg::SearchCutException if cut_exp < minex
|
205
|
+
ret
|
206
|
+
end
|
207
|
+
def comp_search(para, target, smith, armor, comp_min=nil, comp_max=10000, left_associative: true, irep: nil)
|
208
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
209
|
+
comp_min = min_comp(left_associative: left_associative)
|
210
|
+
if comp_max < comp_min
|
211
|
+
raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
|
212
|
+
end
|
213
|
+
if target <= irep.para_call(para, smith, armor, comp_min)
|
214
|
+
return comp_min
|
215
|
+
elsif irep.para_call(para, smith, armor, comp_max) < target
|
216
|
+
raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
|
217
|
+
end
|
218
|
+
while 1 < comp_max - comp_min do
|
219
|
+
comp = (comp_max - comp_min).div(2) + comp_min
|
220
|
+
if irep.para_call(para, smith, armor, comp) < target
|
221
|
+
comp_min = comp
|
222
|
+
else
|
223
|
+
comp_max = comp
|
224
|
+
end
|
225
|
+
end
|
226
|
+
comp_max
|
227
|
+
end
|
228
|
+
def search(para, target, smith_min=nil, armor_min=nil, comp_min=nil, smith_max=10000, armor_max=10000, comp_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false, irep: nil)
|
229
|
+
irep = ir(left_associative: left_associative) if irep.nil?
|
230
|
+
if min_smith
|
231
|
+
s, a = self.min_smith
|
232
|
+
else
|
233
|
+
s, a = build(-1, -1, -1, left_associative: left_associative).min_level
|
234
|
+
end
|
235
|
+
smith_min = s if smith_min.nil?
|
236
|
+
armor_min = a if armor_min.nil?
|
237
|
+
comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
|
238
|
+
comp_min = comp_search(para, target, smith_max, armor_max, comp_min, comp_max, left_associative: left_associative, irep: irep)
|
239
|
+
smith_max, armor_max = sa_search(para, target, comp_min, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative, irep: irep)
|
240
|
+
smith_min, armor_min = sa_search(para, target, comp_max, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative, irep: irep)
|
241
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp_min)
|
242
|
+
comp_max = comp_search(para, target, smith_min, armor_min, comp_min, comp_max, left_associative: left_associative, irep: irep)
|
243
|
+
minex, ret = Mgmg.exp(smith_min, armor_min, comp_max), [smith_min, armor_min, comp_max]
|
244
|
+
exp = Mgmg.exp(smith_max, armor_max, comp_min)
|
245
|
+
minex, ret = exp, [smith_max, armor_max, comp_min] if exp < minex
|
246
|
+
(comp_min+1).upto(comp_max-1) do |comp|
|
247
|
+
break if minex < Mgmg.exp(smith_min, armor_min, comp)
|
248
|
+
smith, armor = sa_search(para, target, comp, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min, irep: irep)
|
249
|
+
exp = Mgmg.exp(smith, armor, comp)
|
250
|
+
if exp < minex
|
251
|
+
minex, ret = exp, [smith, armor, comp]
|
252
|
+
elsif exp == minex
|
253
|
+
if irep.para_call(para, *ret) < irep.para_call(para, smith, armor, comp)
|
254
|
+
ret = [smith, armor, comp]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
rescue Mgmg::SearchCutException
|
258
|
+
end
|
259
|
+
raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
|
260
|
+
ret
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
module Mgmg
|
265
|
+
module_function def find_lowerbound(a, b, para, start, term, smith_min_a: nil, smith_min_b: nil, armor_min_a: nil, armor_min_b: nil, min_smith: false)
|
266
|
+
if term <= start
|
267
|
+
raise ArgumentError, "start < term is needed, (start, term) = (#{start}, #{term}) are given"
|
268
|
+
end
|
269
|
+
ira, irb = a.ir, b.ir
|
270
|
+
sca, scb = a.search(para, start, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira), b.search(para, start, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
271
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
272
|
+
if eb < ea || ( ea == eb && ira.para_call(para, *sca) < irb.para_call(para, *scb) )
|
273
|
+
a, b, ira, irb, sca, scb, ea, eb = b, a, irb, ira, scb, sca, eb, ea
|
274
|
+
smith_min_a, smith_min_b, armor_min_a, armor_min_b = smith_min_b, smith_min_a, armor_min_b, armor_min_a
|
275
|
+
end
|
276
|
+
tag = ira.para_call(para, *sca) + 1
|
277
|
+
sca, scb = a.search(para, term, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira), b.search(para, term, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
278
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
279
|
+
if ea < eb || ( ea == eb && irb.para_call(para, *scb) < ira.para_call(para, *sca) )
|
280
|
+
raise Mgmg::SearchCutException
|
281
|
+
end
|
282
|
+
while tag < term
|
283
|
+
sca, scb = a.search(para, tag, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira), b.search(para, tag, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
284
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
285
|
+
pa, pb = ira.para_call(para, *sca), irb.para_call(para, *scb)
|
286
|
+
if eb < ea
|
287
|
+
return [tag-1, pb]
|
288
|
+
elsif ea == eb
|
289
|
+
if pa < pb
|
290
|
+
return [tag-1, pa]
|
291
|
+
else
|
292
|
+
tag = pb + 1
|
293
|
+
end
|
294
|
+
else
|
295
|
+
tag = pa + 1
|
296
|
+
end
|
297
|
+
end
|
298
|
+
raise UnexpectedError
|
299
|
+
end
|
300
|
+
|
301
|
+
module_function def find_upperbound(a, b, para, start, term, smith_min_a: nil, smith_min_b: nil, armor_min_a: nil, armor_min_b: nil, min_smith: false)
|
302
|
+
if start <= term
|
303
|
+
raise ArgumentError, "term < start is needed, (start, term) = (#{start}, #{term}) are given"
|
304
|
+
end
|
305
|
+
ira, irb = a.ir, b.ir
|
306
|
+
sca, scb = a.search(para, start, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira), b.search(para, start, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
307
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
308
|
+
if ea < eb || ( ea == eb && irb.para_call(para, *scb) < ira.para_call(para, *sca) )
|
309
|
+
a, b, ira, irb, sca, scb, ea, eb = b, a, irb, ira, scb, sca, eb, ea
|
310
|
+
smith_min_a, smith_min_b, armor_min_a, armor_min_b = smith_min_b, smith_min_a, armor_min_b, armor_min_a
|
311
|
+
end
|
312
|
+
tagu = ira.para_call(para, *sca)
|
313
|
+
sca[-1] -= 2
|
314
|
+
tagl = ira.para_call(para, *sca)
|
315
|
+
sca, scb = a.search(para, term, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira), b.search(para, term, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
316
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
317
|
+
if eb < ea || ( ea == eb && ira.para_call(para, *sca) < irb.para_call(para, *scb) )
|
318
|
+
raise Mgmg::SearchCutException
|
319
|
+
end
|
320
|
+
while term < tagu
|
321
|
+
ret = nil
|
322
|
+
sca = a.search(para, tagl, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira)
|
323
|
+
next_tagu, next_sca = tagl, sca
|
324
|
+
scb = b.search(para, tagl, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
325
|
+
while tagl < tagu
|
326
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
327
|
+
pa, pb = ira.para_call(para, *sca), irb.para_call(para, *scb)
|
328
|
+
if ea < eb
|
329
|
+
ret = tagl
|
330
|
+
sca = a.search(para, pa + 1, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira)
|
331
|
+
tagl = ira.para_call(para, *sca)
|
332
|
+
scb = b.search(para, tagl, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
333
|
+
elsif ea == eb
|
334
|
+
if pb < pa
|
335
|
+
ret = tagl
|
336
|
+
sca = a.search(para, pa + 1, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira)
|
337
|
+
tagl = ira.para_call(para, *sca)
|
338
|
+
scb = b.search(para, tagl, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
339
|
+
else
|
340
|
+
scb = b.search(para, pb + 1, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
341
|
+
tagl = irb.para_call(para, *scb)
|
342
|
+
sca = a.search(para, tagl, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira)
|
343
|
+
end
|
344
|
+
else
|
345
|
+
sca = a.search(para, pa + 1, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira)
|
346
|
+
tagl = ira.para_call(para, *sca)
|
347
|
+
scb = b.search(para, tagl, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
if ret.nil?
|
351
|
+
tagu = next_tagu
|
352
|
+
next_sca[-1] -= 2
|
353
|
+
tagl = ira.para_call(para, *next_sca)
|
354
|
+
if tagl == tagu
|
355
|
+
tagl = term
|
356
|
+
end
|
357
|
+
else
|
358
|
+
pa = ira.para_call(para, *a.search(para, ret+1, smith_min_a, armor_min_a, min_smith: min_smith, irep: ira))
|
359
|
+
pb = irb.para_call(para, *b.search(para, ret+1, smith_min_b, armor_min_b, min_smith: min_smith, irep: irb))
|
360
|
+
return [ret, [pa, pb].min]
|
361
|
+
end
|
362
|
+
end
|
363
|
+
raise UnexpectedError
|
364
|
+
end
|
365
|
+
end
|
data/lib/mgmg/utils.rb
CHANGED
@@ -46,9 +46,49 @@ module Mgmg
|
|
46
46
|
end
|
47
47
|
attr_accessor :equip
|
48
48
|
end
|
49
|
+
class SearchCutException < StandardError; end
|
50
|
+
class UnexpectedError < StandardError
|
51
|
+
def initialize()
|
52
|
+
super("There is a bug in `mgmg' gem. Please report to https://github.com/cycloawaodorin/mgmg/issues .")
|
53
|
+
end
|
54
|
+
end
|
49
55
|
|
50
|
-
module_function def exp(smith, comp)
|
51
|
-
|
56
|
+
module_function def exp(smith, armor, comp=armor.tap{armor=0})
|
57
|
+
if armor <= 0
|
58
|
+
if smith <= 0
|
59
|
+
if comp <= 0
|
60
|
+
0
|
61
|
+
else
|
62
|
+
(2*((comp-1)**2)) + 2
|
63
|
+
end
|
64
|
+
else
|
65
|
+
if comp <= 0
|
66
|
+
((smith-1)**2) + 1
|
67
|
+
else
|
68
|
+
((smith-1)**2) + (2*((comp-1)**2)) + 3
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
if smith <= 0
|
73
|
+
if comp <= 0
|
74
|
+
((armor-1)**2) + 1
|
75
|
+
else
|
76
|
+
((armor-1)**2) + (2*((comp-1)**2)) + 3
|
77
|
+
end
|
78
|
+
else
|
79
|
+
if comp <= 0
|
80
|
+
((smith-1)**2) + ((armor-1)**2) + 2
|
81
|
+
else
|
82
|
+
((smith-1)**2) + ((armor-1)**2) + (2*((comp-1)**2)) + 4
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
module_function def invexp2(exp, comp)
|
88
|
+
Math.sqrt(exp - (2*((comp-1)**2)) - 3).round + 1
|
89
|
+
end
|
90
|
+
module_function def invexp3(exp, sa, comp)
|
91
|
+
Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).round + 1
|
52
92
|
end
|
53
93
|
|
54
94
|
CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/
|
@@ -94,6 +134,15 @@ module Mgmg
|
|
94
134
|
end
|
95
135
|
str
|
96
136
|
end
|
137
|
+
|
138
|
+
module_function def parse_material(str)
|
139
|
+
m = /\A.+?(\d+)\Z/.match(str)
|
140
|
+
mat = MaterialIndex[str.to_sym]
|
141
|
+
if m.nil? || mat.nil?
|
142
|
+
raise InvalidMaterialError.new(str)
|
143
|
+
end
|
144
|
+
[mat, m[1].to_i, mat<90 ? mat.div(10) : 9]
|
145
|
+
end
|
97
146
|
|
98
147
|
class Vec < Array
|
99
148
|
def add!(other)
|
@@ -186,6 +235,9 @@ module Mgmg
|
|
186
235
|
def col_size
|
187
236
|
@body[0].length
|
188
237
|
end
|
238
|
+
def shape
|
239
|
+
[row_size(), col_size()]
|
240
|
+
end
|
189
241
|
def each_with_index
|
190
242
|
@body.each.with_index do |row, i|
|
191
243
|
row.each.with_index do |e, j|
|
data/lib/mgmg/version.rb
CHANGED
data/lib/mgmg.rb
CHANGED
@@ -3,14 +3,17 @@ require_relative './mgmg/utils'
|
|
3
3
|
require_relative './mgmg/const'
|
4
4
|
require_relative './mgmg/equip'
|
5
5
|
require_relative './mgmg/poly'
|
6
|
+
require_relative './mgmg/ir'
|
6
7
|
require_relative './mgmg/system_equip'
|
8
|
+
require_relative './mgmg/search'
|
9
|
+
require_relative './mgmg/optimize'
|
7
10
|
|
8
11
|
class String
|
9
12
|
def min_level(w=1)
|
10
13
|
Mgmg::Equip.min_level(self, w)
|
11
14
|
end
|
12
|
-
def min_levels(left_associative: true)
|
13
|
-
build(-1, -1, left_associative: left_associative).min_levels
|
15
|
+
def min_levels(w=1, left_associative: true)
|
16
|
+
build(-1, -1, left_associative: left_associative).min_levels(w)
|
14
17
|
end
|
15
18
|
def min_smith(left_associative: true)
|
16
19
|
Mgmg::Equip.min_smith(self, left_associative: left_associative)
|
@@ -21,37 +24,45 @@ class String
|
|
21
24
|
def build(smith=-1, comp=smith, left_associative: true)
|
22
25
|
Mgmg::Equip.build(self, smith, comp, left_associative: left_associative)
|
23
26
|
end
|
27
|
+
def ir(left_associative: true)
|
28
|
+
Mgmg::IR.build(self, left_associative: left_associative)
|
29
|
+
end
|
24
30
|
def poly(para=:cost, left_associative: true)
|
31
|
+
la = left_associative
|
25
32
|
case para
|
26
33
|
when :atkstr
|
27
|
-
self.poly(:attack) + self.poly(:str)
|
34
|
+
self.poly(:attack, left_associative: la) + self.poly(:str, left_associative: la)
|
28
35
|
when :atk_sd
|
29
|
-
self.poly(:attack) + self.poly(:str).quo(2) + self.poly(:dex).quo(2)
|
36
|
+
self.poly(:attack, left_associative: la) + self.poly(:str, left_associative: la).quo(2) + self.poly(:dex, left_associative: la).quo(2)
|
30
37
|
when :dex_as
|
31
|
-
self.poly(:dex) + self.poly(:attack).quo(2) + self.poly(:str).quo(2)
|
38
|
+
self.poly(:dex, left_associative: la) + self.poly(:attack, left_associative: la).quo(2) + self.poly(:str, left_associative: la).quo(2)
|
32
39
|
when :mag_das
|
33
|
-
self.poly(:magic) + self.poly(:dex_as).quo(2)
|
40
|
+
self.poly(:magic, left_associative: la) + self.poly(:dex_as, left_associative: la).quo(2)
|
34
41
|
when :magmag
|
35
|
-
self.poly(:magdef) + self.poly(:magic).quo(2)
|
42
|
+
self.poly(:magdef, left_associative: la) + self.poly(:magic, left_associative: la).quo(2)
|
43
|
+
when :pmdef
|
44
|
+
pd = self.poly(:phydef, left_associative: la)
|
45
|
+
md = self.poly(:magmag, left_associative: la)
|
46
|
+
pd <= md ? pd : md
|
36
47
|
when :cost
|
37
48
|
if Mgmg::SystemEquip.keys.include?(self)
|
38
49
|
return Mgmg::TPolynomial.new(Mgmg::Mat.new(1, 1, 0.quo(1)), 28, 0, 12, 12)
|
39
50
|
end
|
40
51
|
built = self.build(-1)
|
41
52
|
const = (built.star**2) * ( /\+/.match(self) ? 5 : ( built.kind < 8 ? 2 : 1 ) )
|
42
|
-
ret = poly(:attack) + poly(:phydef) + poly(:magdef)
|
43
|
-
ret += poly(:hp).quo(4) + poly(:mp).quo(4)
|
44
|
-
ret += poly(:str) + poly(:dex) + poly(:speed) + poly(:magic)
|
53
|
+
ret = poly(:attack, left_associative: la) + poly(:phydef, left_associative: la) + poly(:magdef, left_associative: la)
|
54
|
+
ret += poly(:hp, left_associative: la).quo(4) + poly(:mp, left_associative: la).quo(4)
|
55
|
+
ret += poly(:str, left_associative: la) + poly(:dex, left_associative: la) + poly(:speed, left_associative: la) + poly(:magic, left_associative: la)
|
45
56
|
ret.mat.body[0][0] += const
|
46
57
|
ret
|
47
58
|
else
|
48
|
-
Mgmg::TPolynomial.build(self, para, left_associative:
|
59
|
+
Mgmg::TPolynomial.build(self, para, left_associative: la)
|
49
60
|
end
|
50
61
|
end
|
51
62
|
def eff(para, smith, comp=smith, left_associative: true)
|
52
|
-
a = build(smith, comp, left_associative: left_associative).
|
53
|
-
b = build(smith+1, comp, left_associative: left_associative).
|
54
|
-
c = build(smith, comp+2, left_associative: left_associative).
|
63
|
+
a = build(smith, comp, left_associative: left_associative).para_call(para)
|
64
|
+
b = build(smith+1, comp, left_associative: left_associative).para_call(para)
|
65
|
+
c = build(smith, comp+2, left_associative: left_associative).para_call(para)
|
55
66
|
sden = smith==0 ? 1 : 2*smith-1
|
56
67
|
cden = comp==0 ? 4 : 8*comp
|
57
68
|
[(b-a).quo(sden), (c-a).quo(cden)]
|
@@ -59,55 +70,21 @@ class String
|
|
59
70
|
def peff(para, smith, comp=smith, left_associative: true)
|
60
71
|
poly(para, left_associative: left_associative).eff(smith, comp)
|
61
72
|
end
|
62
|
-
def
|
63
|
-
smith_min = build(-1, -1, left_associative: left_associative).min_level if smith_min.nil?
|
64
|
-
if smith_max < smith_min
|
65
|
-
raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
|
66
|
-
end
|
67
|
-
if target <= build(smith_min, comp, left_associative: left_associative).method(para).call
|
68
|
-
return smith_min
|
69
|
-
elsif build(smith_max, comp, left_associative: left_associative).method(para).call < target
|
70
|
-
raise ArgumentError, "given smith_max=#{smith_max} does not satisfies the target"
|
71
|
-
end
|
72
|
-
while 1 < smith_max - smith_min do
|
73
|
-
smith = (smith_max - smith_min).div(2) + smith_min
|
74
|
-
if build(smith, comp, left_associative: left_associative).method(para).call < target
|
75
|
-
smith_min = smith
|
76
|
-
else
|
77
|
-
smith_max = smith
|
78
|
-
end
|
79
|
-
end
|
80
|
-
smith_max
|
81
|
-
end
|
82
|
-
def comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)
|
83
|
-
comp_min = min_comp(left_associative: left_associative)
|
84
|
-
if comp_max < comp_min
|
85
|
-
raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
|
86
|
-
end
|
87
|
-
if target <= build(smith, comp_min, left_associative: left_associative).method(para).call
|
88
|
-
return comp_min
|
89
|
-
elsif build(smith, comp_max, left_associative: left_associative).method(para).call < target
|
90
|
-
raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
|
91
|
-
end
|
92
|
-
while 1 < comp_max - comp_min do
|
93
|
-
comp = (comp_max - comp_min).div(2) + comp_min
|
94
|
-
if build(smith, comp, left_associative: left_associative).method(para).call < target
|
95
|
-
comp_min = comp
|
96
|
-
else
|
97
|
-
comp_max = comp
|
98
|
-
end
|
99
|
-
end
|
100
|
-
comp_max
|
101
|
-
end
|
102
|
-
def show(smith=-1, comp=smith, left_associative: true)
|
73
|
+
def show(smith=-1, comp=smith, left_associative: true, para: :power)
|
103
74
|
built = self.build(smith, comp, left_associative: left_associative)
|
104
|
-
pstr = '%.3f' % built.
|
75
|
+
pstr = '%.3f' % built.para_call(para)
|
105
76
|
pstr.sub!(/\.?0+\Z/, '')
|
106
77
|
puts "Building"
|
107
78
|
puts " #{self}"
|
108
79
|
puts "with levels (#{smith}, #{comp}) yields (#{pstr}, #{built.total_cost})"
|
109
80
|
puts " #{built}"
|
110
81
|
end
|
82
|
+
def phydef_optimize(smith=nil, comp=smith, left_associative: true, magdef_maximize: true)
|
83
|
+
Mgmg::Optimize.phydef_optimize(self, smith, comp, left_associative: left_associative, magdef_maximize: magdef_maximize)
|
84
|
+
end
|
85
|
+
def buster_optimize(smith=nil, comp=smith, left_associative: true)
|
86
|
+
Mgmg::Optimize.buster_optimize(self, smith, comp, left_associative: left_associative)
|
87
|
+
end
|
111
88
|
end
|
112
89
|
module Enumerable
|
113
90
|
def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
|
@@ -120,4 +97,51 @@ module Enumerable
|
|
120
97
|
end
|
121
98
|
end.sum
|
122
99
|
end
|
100
|
+
def ir(left_associative: true)
|
101
|
+
self.map do |str|
|
102
|
+
str.ir(left_associative: left_associative)
|
103
|
+
end.sum
|
104
|
+
end
|
105
|
+
def show(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true, para: :power)
|
106
|
+
built = self.build(smith, armor, comp, left_associative: left_associative)
|
107
|
+
pstr = '%.3f' % built.para_call(para)
|
108
|
+
pstr.sub!(/\.?0+\Z/, '')
|
109
|
+
puts "Building"
|
110
|
+
puts " #{self.join(', ')}"
|
111
|
+
puts "with levels (#{smith}, #{armor}, #{comp}) yields (#{pstr}, #{built.total_cost})"
|
112
|
+
puts " #{built}"
|
113
|
+
end
|
114
|
+
def min_levels(w=1, left_associative: true)
|
115
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels(w)
|
116
|
+
end
|
117
|
+
def min_level(w=1, left_associative: true)
|
118
|
+
ret = [0, 0]
|
119
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels(w).each do |str, level|
|
120
|
+
m = /\A\[*([^\+]+)/.match(str)
|
121
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
122
|
+
ret[0] = [ret[0], level].max
|
123
|
+
else
|
124
|
+
ret[1] = [ret[1], level].max
|
125
|
+
end
|
126
|
+
end
|
127
|
+
ret
|
128
|
+
end
|
129
|
+
def min_smith(left_associative: true)
|
130
|
+
ret = [0, 0]
|
131
|
+
self.each do |str|
|
132
|
+
s = Mgmg::Equip.min_smith(str, left_associative: left_associative)
|
133
|
+
m = /\A\[*([^\+]+)/.match(str)
|
134
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
135
|
+
ret[0] = [ret[0], s].max
|
136
|
+
else
|
137
|
+
ret[1] = [ret[1], s].max
|
138
|
+
end
|
139
|
+
end
|
140
|
+
ret
|
141
|
+
end
|
142
|
+
def min_comp(left_associative: true)
|
143
|
+
self.map do |str|
|
144
|
+
Mgmg::Equip.min_comp(str, left_associative: left_associative)
|
145
|
+
end.max
|
146
|
+
end
|
123
147
|
end
|