mgmg 1.6.2 → 1.8.0
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 +12 -0
- data/lib/mgmg/ir.rb +126 -12
- data/lib/mgmg/option.rb +8 -6
- data/lib/mgmg/search.rb +288 -129
- data/lib/mgmg/version.rb +1 -1
- data/reference.md +7 -8
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79211ca6cd5422500f7dc957eadfb2c1812459c98fd39b84fc9a3ebf178174ec
|
|
4
|
+
data.tar.gz: efa0254194363114aee22993e78cab9359e9a7c92f454d5fffc12b1d14368e6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 822a754eeeec7b9b9e8d6f1497041c153a56b62d190da8101f798e9b78334cc64406f35167623387c346b9f2453027a7e17a3ebaefc2ec4d38cbfcbe381b01e6
|
|
7
|
+
data.tar.gz: f43028c621ea4025123c1ca338f46c8965d545a8f6a92569cc5bb7f5279d11ea01be0dbe6453c1ffe06c831c55be1cdf439ed66b81fa8e08a4d01ac994348e5f
|
data/CHANGELOG.md
CHANGED
|
@@ -177,3 +177,15 @@
|
|
|
177
177
|
|
|
178
178
|
## 1.6.2 2022/10/31
|
|
179
179
|
- 既製品を含むかどうかのチェックを行った場合,同じレシピについては繰り返しチェックしないようにして高速化した.
|
|
180
|
+
|
|
181
|
+
## 1.7.0 2022/11/12
|
|
182
|
+
- オプション`step`を廃止し,レシピに応じて自動的に無駄な探索を省略するように変更.
|
|
183
|
+
- `String/Enumerable#search/find_max`において,フィボナッチ探索を用いたアルゴリズムに変更.単峰でないため,オプション`comp_ext`を使って追加の探索を行い,取りこぼしを避ける.
|
|
184
|
+
- `Mgmg.#find_upperbound`のアルゴリズムに誤りがあり,大きく間違えた解を返していた問題を修正.
|
|
185
|
+
- `Mgmg::IR#attack`等において,引数が`nil`(製作Lvを指定せず,多項式を返す)の場合に,例外となっていたバグを修正.
|
|
186
|
+
- オブション`smith/armor/comp_max`のデフォルト値を10^9に変更.
|
|
187
|
+
|
|
188
|
+
## 1.8.0 2022/11/14
|
|
189
|
+
- オプション`comp_ext`を`fib_ext`に変更し,追加探索の範囲を修正.
|
|
190
|
+
- オプション`smith/armor/comp_max`の扱い方を修正し,デフォルト値を10^5に変更.
|
|
191
|
+
- `Enumerable#find_max`,`Mgmg.#find_lowerbound`のバグを修正.
|
data/lib/mgmg/ir.rb
CHANGED
|
@@ -67,9 +67,9 @@ module Mgmg
|
|
|
67
67
|
ms
|
|
68
68
|
else
|
|
69
69
|
if ms == '0'
|
|
70
|
-
"[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
|
|
70
|
+
"[[#{ss}[(c+#{@equip9})/2]/100](#{@coef})/#{@den}]"
|
|
71
71
|
else
|
|
72
|
-
"#{ms}+[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
|
|
72
|
+
"#{ms}+[[#{ss}[(c+#{@equip9})/2]/100](#{@coef})/#{@den}]"
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
end
|
|
@@ -136,8 +136,46 @@ module Mgmg
|
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
end
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
class Reined
|
|
140
|
+
def initialize(body, rein)
|
|
141
|
+
@body, @rein = body, rein
|
|
142
|
+
end
|
|
143
|
+
attr_accessor :body, :rein
|
|
144
|
+
def initialize_copy(other)
|
|
145
|
+
@body, @rein = other.body.dup, other.rein.dup
|
|
146
|
+
end
|
|
147
|
+
def evaluate(s, c)
|
|
148
|
+
ret = @body.evaluate(s, c)
|
|
149
|
+
@rein.each do |r|
|
|
150
|
+
if r != 0
|
|
151
|
+
ret *= (100+r).quo(100)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
ret
|
|
155
|
+
end
|
|
156
|
+
def evaluate3(s, a, c)
|
|
157
|
+
ret = @body.evaluate3(s, a, c)
|
|
158
|
+
@rein.each do |r|
|
|
159
|
+
if r != 0
|
|
160
|
+
ret *= (100+r).quo(100)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
ret
|
|
164
|
+
end
|
|
165
|
+
def to_s
|
|
166
|
+
ret = @body.to_s
|
|
167
|
+
buff = ''
|
|
168
|
+
@rein.each do |r|
|
|
169
|
+
if r != 0
|
|
170
|
+
buff += "(#{100+r}/100)"
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
ret = '('+ret+')'+buff unless buff.empty?
|
|
174
|
+
ret
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
def initialize(kind, star, main_m, sub_m, para, eo, rein=[])
|
|
178
|
+
@kind, @star, @main, @sub, @para, @eo = kind, star, main_m, sub_m, para, eo
|
|
141
179
|
add_reinforcement(rein)
|
|
142
180
|
end
|
|
143
181
|
def add_reinforcement(rein)
|
|
@@ -150,13 +188,14 @@ module Mgmg
|
|
|
150
188
|
end
|
|
151
189
|
self
|
|
152
190
|
end
|
|
153
|
-
attr_accessor :kind, :star, :main, :sub, :para, :rein
|
|
191
|
+
attr_accessor :kind, :star, :main, :sub, :para, :eo, :rein
|
|
154
192
|
def initialize_copy(other)
|
|
155
193
|
@kind = other.kind
|
|
156
194
|
@star = other.star.dup
|
|
157
195
|
@main = other.main
|
|
158
196
|
@sub = other.sub
|
|
159
197
|
@para = other.para.dup
|
|
198
|
+
@eo = other.eo.dup
|
|
160
199
|
@rein = other.rein.dup
|
|
161
200
|
end
|
|
162
201
|
|
|
@@ -182,11 +221,41 @@ module Mgmg
|
|
|
182
221
|
end
|
|
183
222
|
end
|
|
184
223
|
|
|
224
|
+
def eo_para(para)
|
|
225
|
+
case para
|
|
226
|
+
when :atkstr
|
|
227
|
+
self.class.eo_add(eo_para(:attack), eo_para(:str))
|
|
228
|
+
when :atk_sd
|
|
229
|
+
self.class.eo_add(self.class.eo_add(eo_para(:attack), eo_para(:str)), eo_para(:dex))
|
|
230
|
+
when :dex_as
|
|
231
|
+
self.class.eo_add(self.class.eo_add(eo_para(:dex), eo_para(:attack)), eo_para(:str))
|
|
232
|
+
when :mag_das
|
|
233
|
+
self.class.eo_add(eo_para(:magic), eo_para(:dex_as))
|
|
234
|
+
when :magic2
|
|
235
|
+
eo_para(:magic)
|
|
236
|
+
when :magmag
|
|
237
|
+
self.class.eo_add(eo_para(:magdef), eo_para(:magic))
|
|
238
|
+
when :pmdef
|
|
239
|
+
self.class.eo_add(eo_para(:phydef), eo_para(:magmag))
|
|
240
|
+
when :hs
|
|
241
|
+
self.class.eo_add(eo_para(:hp), eo_para(:str))
|
|
242
|
+
when :cost
|
|
243
|
+
ret = nil
|
|
244
|
+
@eo.each do |foo|
|
|
245
|
+
ret = self.class.eo_add(ret, foo)
|
|
246
|
+
end
|
|
247
|
+
ret
|
|
248
|
+
else
|
|
249
|
+
@eo[%i|attack phydef magdef hp mp str dex speed magic|.index(para)]
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
185
253
|
%i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |sym, i|
|
|
186
254
|
define_method(sym) do |s=nil, ac=s, x=nil|
|
|
187
|
-
|
|
188
|
-
@para[i]
|
|
189
|
-
|
|
255
|
+
if s.nil?
|
|
256
|
+
return Reined.new(@para[i], @rein.map{|r| r.vec[i]})
|
|
257
|
+
end
|
|
258
|
+
ret = if x.nil?
|
|
190
259
|
@para[i].evaluate(s, ac)
|
|
191
260
|
else
|
|
192
261
|
@para[i].evaluate3(s, ac, x)
|
|
@@ -312,12 +381,15 @@ module Mgmg
|
|
|
312
381
|
@para = Array.new(9) do |i|
|
|
313
382
|
Multi.sum(self.para[i], other.para[i])
|
|
314
383
|
end
|
|
384
|
+
@eo.map!.with_index do |seo, i|
|
|
385
|
+
self.class.eo_add(seo, other.eo[i])
|
|
386
|
+
end
|
|
315
387
|
self
|
|
316
388
|
end
|
|
317
389
|
def +(other)
|
|
318
390
|
self.dup.add!(other)
|
|
319
391
|
end
|
|
320
|
-
Zero = self.new(28, Vec.new(6, 0).freeze, 12, 12, Array.new(9){Const.new(0)}.freeze)
|
|
392
|
+
Zero = self.new(28, Vec.new(6, 0).freeze, 12, 12, Array.new(9){Const.new(0)}.freeze, Array.new(9, nil).freeze)
|
|
321
393
|
Zero.rein.freeze; Zero.freeze
|
|
322
394
|
|
|
323
395
|
class << self
|
|
@@ -368,7 +440,15 @@ module Mgmg
|
|
|
368
440
|
end
|
|
369
441
|
end
|
|
370
442
|
|
|
371
|
-
new(
|
|
443
|
+
eo = Array.new(9) do |i|
|
|
444
|
+
if EquipFilter[main_k][i] == 0
|
|
445
|
+
main.eo[i]
|
|
446
|
+
else
|
|
447
|
+
eo_add(main.eo[i], eo_mul(2**(Equip9[main_k][i]&1), sub.eo[i]))
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
new(main_k, main_s+sub_s, main_sub, sub_main, para, eo)
|
|
372
452
|
end
|
|
373
453
|
def smith(str)
|
|
374
454
|
str = Mgmg.check_string(str)
|
|
@@ -395,7 +475,15 @@ module Mgmg
|
|
|
395
475
|
end
|
|
396
476
|
end
|
|
397
477
|
|
|
398
|
-
|
|
478
|
+
eo = Array.new(9) do |i|
|
|
479
|
+
if coef[i] == 0
|
|
480
|
+
nil
|
|
481
|
+
else
|
|
482
|
+
0
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
ret = new(kind, (main_s+sub_s).div(2), main_mc, sub_mc, para, eo)
|
|
399
487
|
Cache.store(str, ret.freeze)
|
|
400
488
|
ret.dup
|
|
401
489
|
end
|
|
@@ -403,7 +491,33 @@ module Mgmg
|
|
|
403
491
|
para = equip.para.map do |value|
|
|
404
492
|
Mgmg::IR::Const.new(value)
|
|
405
493
|
end
|
|
406
|
-
|
|
494
|
+
eo = equip.para.map do |value|
|
|
495
|
+
if value == 0
|
|
496
|
+
nil
|
|
497
|
+
else
|
|
498
|
+
0
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
new(equip.kind, equip.star, equip.main, equip.sub, para, eo)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def eo_add(eo0, eo1)
|
|
505
|
+
if eo0
|
|
506
|
+
if eo1
|
|
507
|
+
eo0 | eo1
|
|
508
|
+
else
|
|
509
|
+
eo0
|
|
510
|
+
end
|
|
511
|
+
else
|
|
512
|
+
eo1
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
def eo_mul(eq, seo)
|
|
516
|
+
if seo
|
|
517
|
+
eq | seo
|
|
518
|
+
else
|
|
519
|
+
nil
|
|
520
|
+
end
|
|
407
521
|
end
|
|
408
522
|
end
|
|
409
523
|
end
|
data/lib/mgmg/option.rb
CHANGED
|
@@ -2,12 +2,14 @@ module Mgmg
|
|
|
2
2
|
class Option
|
|
3
3
|
Defaults = {
|
|
4
4
|
left_associative: true, include_system_equips: true,
|
|
5
|
-
smith_max:
|
|
5
|
+
smith_max: 100_000, armor_max: 100_000, comp_max: 100_000,
|
|
6
|
+
fib_ext: [4, 10]
|
|
6
7
|
}
|
|
7
8
|
def initialize(
|
|
8
9
|
left_associative: Defaults[:left_associative],
|
|
9
10
|
smith_min: nil, armor_min:nil, comp_min: nil, smith_max: Defaults[:smith_max], armor_max: Defaults[:armor_max], comp_max: Defaults[:comp_max],
|
|
10
|
-
|
|
11
|
+
fib_ext: Defaults[:fib_ext],
|
|
12
|
+
magdef_maximize: true,
|
|
11
13
|
target_weight: 0, reinforcement: [], buff: nil,
|
|
12
14
|
irep: nil, cut_exp: Float::INFINITY,
|
|
13
15
|
include_system_equips: Defaults[:include_system_equips]
|
|
@@ -19,7 +21,7 @@ module Mgmg
|
|
|
19
21
|
@smith_max = smith_max
|
|
20
22
|
@armor_max = armor_max
|
|
21
23
|
@comp_max = comp_max
|
|
22
|
-
@
|
|
24
|
+
@fib_ext = fib_ext
|
|
23
25
|
@magdef_maximize = magdef_maximize
|
|
24
26
|
@target_weight = target_weight
|
|
25
27
|
@reinforcement = reinforcement
|
|
@@ -35,8 +37,8 @@ module Mgmg
|
|
|
35
37
|
@include_system_equips = include_system_equips
|
|
36
38
|
@system_equips_checked = false
|
|
37
39
|
end
|
|
38
|
-
attr_accessor :left_associative, :smith_min, :armor_min, :comp_min, :smith_max, :armor_max, :comp_max
|
|
39
|
-
attr_accessor :
|
|
40
|
+
attr_accessor :left_associative, :smith_min, :armor_min, :comp_min, :smith_max, :armor_max, :comp_max, :fib_ext
|
|
41
|
+
attr_accessor :magdef_maximize, :target_weight, :reinforcement, :irep, :cut_exp, :include_system_equips, :system_equips_checked
|
|
40
42
|
def initialize_copy(other)
|
|
41
43
|
@left_associative = other.left_associative
|
|
42
44
|
@smith_min = other.smith_min
|
|
@@ -45,7 +47,7 @@ module Mgmg
|
|
|
45
47
|
@smith_max = other.smith_max
|
|
46
48
|
@armor_max = other.armor_max
|
|
47
49
|
@comp_max = other.comp_max
|
|
48
|
-
@
|
|
50
|
+
@fib_ext = other.fib_ext.dup
|
|
49
51
|
@magdef_maximize = other.magdef_maximize
|
|
50
52
|
@target_weight = other.target_weight
|
|
51
53
|
@reinforcement = other.reinforcement.dup
|
data/lib/mgmg/search.rb
CHANGED
|
@@ -34,7 +34,7 @@ class String
|
|
|
34
34
|
if target <= opt.irep.para_call(para, smith, opt.comp_min)
|
|
35
35
|
return opt.comp_min
|
|
36
36
|
elsif opt.irep.para_call(para, smith, opt.comp_max) < target
|
|
37
|
-
raise Mgmg::SearchCutException
|
|
37
|
+
raise Mgmg::SearchCutException, "given comp_max=#{opt.comp_max} does not satisfies the target"
|
|
38
38
|
end
|
|
39
39
|
while 1 < opt.comp_max - opt.comp_min do
|
|
40
40
|
comp = (opt.comp_max - opt.comp_min).div(2) + opt.comp_min
|
|
@@ -46,10 +46,37 @@ class String
|
|
|
46
46
|
end
|
|
47
47
|
opt.comp_max
|
|
48
48
|
end
|
|
49
|
+
private def eval_comp(para, target, comp, opt, eo)
|
|
50
|
+
return [nil, Float::INFINITY] if (comp < opt.comp_min or opt.comp_max < comp)
|
|
51
|
+
comp -= 1 if ( opt.comp_min<comp and eo & (2**(comp&1)) == 0 )
|
|
52
|
+
smith = smith_search(para, target, comp, opt:)
|
|
53
|
+
exp = Mgmg.exp(smith, comp)
|
|
54
|
+
[[smith, comp], exp]
|
|
55
|
+
rescue Mgmg::SearchCutException
|
|
56
|
+
[nil, Float::INFINITY]
|
|
57
|
+
end
|
|
58
|
+
private def fine(exp_best, ret, para, target, comp, opt, eo)
|
|
59
|
+
return [exp_best, ret] if eo & (2**(comp&1)) == 0
|
|
60
|
+
smith = smith_search(para, target, comp, opt:)
|
|
61
|
+
exp = Mgmg.exp(smith, comp)
|
|
62
|
+
if exp < exp_best
|
|
63
|
+
exp_best, ret = exp, [smith, comp]
|
|
64
|
+
elsif exp == exp_best
|
|
65
|
+
if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, smith, comp) then
|
|
66
|
+
ret = [smith, comp]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
[exp_best, ret]
|
|
70
|
+
end
|
|
49
71
|
def search(para, target, opt: Mgmg::Option.new)
|
|
50
72
|
opt = opt.dup.set_default(self)
|
|
51
73
|
opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
|
|
52
|
-
|
|
74
|
+
begin
|
|
75
|
+
opt.comp_min = comp_search(para, target, opt.smith_max, opt:)
|
|
76
|
+
rescue Mgmg::SearchCutException
|
|
77
|
+
foo = opt.irep.para_call(para, opt.smith_max, opt.comp_max)
|
|
78
|
+
raise Mgmg::SearchCutException, "#{self} could not reach target=#{target} until (smith_max, comp_max)=(#{opt.smith_max}, #{opt.comp_max}), which yields #{foo.comma3}"
|
|
79
|
+
end
|
|
53
80
|
opt.smith_max = smith_search(para, target, opt.comp_min, opt: opt_nocut)
|
|
54
81
|
opt.smith_min = smith_search(para, target, opt.comp_max, opt: opt_nocut)
|
|
55
82
|
raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.comp_min)
|
|
@@ -59,18 +86,40 @@ class String
|
|
|
59
86
|
opt.cut_exp, ret = exp, [opt.smith_min, opt.comp_max] if exp <= opt.cut_exp
|
|
60
87
|
exp = Mgmg.exp(opt.smith_max, opt.comp_min)
|
|
61
88
|
opt.cut_exp, ret = exp, [opt.smith_max, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
eo = opt.irep.eo_para(para)
|
|
90
|
+
comps = Mgmg.fib_init(opt.comp_min, opt.comp_max)
|
|
91
|
+
values = comps.map do |comp|
|
|
92
|
+
r, e = eval_comp(para, target, comp, opt_nocut, eo)
|
|
93
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
94
|
+
e
|
|
95
|
+
end
|
|
96
|
+
while 3 < comps[3]-comps[0]
|
|
97
|
+
if values[1] <= values[2]
|
|
98
|
+
comp = comps[0] + comps[2]-comps[1]
|
|
99
|
+
comps = [comps[0], comp, comps[1], comps[2]]
|
|
100
|
+
r, e = eval_comp(para, target, comp, opt_nocut, eo)
|
|
101
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
102
|
+
values = [values[0], e, values[1], values[2]]
|
|
103
|
+
else
|
|
104
|
+
comp = comps[1] + comps[3]-comps[2]
|
|
105
|
+
comps = [comps[1], comps[2], comp, comps[3]]
|
|
106
|
+
r, e = eval_comp(para, target, comp, opt_nocut, eo)
|
|
107
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
108
|
+
values = [values[1], values[2], e, values[3]]
|
|
72
109
|
end
|
|
110
|
+
end
|
|
111
|
+
exp_best = opt.cut_exp
|
|
112
|
+
diff = values.max-values.min
|
|
113
|
+
opt.cut_exp = exp_best + diff*opt.fib_ext[0]
|
|
114
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
|
115
|
+
exp_best, ret = fine(exp_best, ret, para, target, comp, opt, eo)
|
|
116
|
+
rescue Mgmg::SearchCutException
|
|
117
|
+
break
|
|
118
|
+
end
|
|
119
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
|
120
|
+
exp_best, ret = fine(exp_best, ret, para, target, comp, opt, eo)
|
|
73
121
|
rescue Mgmg::SearchCutException
|
|
122
|
+
break
|
|
74
123
|
end
|
|
75
124
|
if ret.nil?
|
|
76
125
|
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
|
@@ -90,17 +139,56 @@ class String
|
|
|
90
139
|
end
|
|
91
140
|
smith
|
|
92
141
|
end
|
|
142
|
+
private def eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
143
|
+
return [-Float::INFINITY, Float::INFINITY] if (comp < opt.comp_min or opt.comp_max < comp)
|
|
144
|
+
comp -= 1 if ( opt.comp_min<comp and ( eo & (2**(comp&1)) == 0 ) )
|
|
145
|
+
smith = Mgmg.invexp2(max_exp, comp)
|
|
146
|
+
cur = opt.irep.para_call(para, smith, comp)
|
|
147
|
+
smith = minimize_smith(para, smith, comp, cur, opt) if max <= cur
|
|
148
|
+
[cur, smith]
|
|
149
|
+
end
|
|
93
150
|
def find_max(para, max_exp, opt: Mgmg::Option.new)
|
|
94
151
|
opt = opt.dup.set_default(self)
|
|
95
152
|
exp = Mgmg.exp(opt.smith_min, opt.comp_min)
|
|
96
153
|
raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
|
|
97
154
|
ret = [Mgmg.invexp2(max_exp, opt.comp_min), opt.comp_min]
|
|
98
155
|
max = opt.irep.para_call(para, *ret)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
156
|
+
eo = opt.irep.eo_para(para)
|
|
157
|
+
opt.comp_max = Mgmg.invexp2c(max_exp, opt.smith_min)
|
|
158
|
+
comps = Mgmg.fib_init(opt.comp_min+1, opt.comp_max)
|
|
159
|
+
values = comps.map do |comp|
|
|
160
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
161
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
|
162
|
+
cur
|
|
163
|
+
end
|
|
164
|
+
while 3 < comps[3]-comps[0]
|
|
165
|
+
if values[2] <= values[1]
|
|
166
|
+
comp = comps[0] + comps[2]-comps[1]
|
|
167
|
+
comps = [comps[0], comp, comps[1], comps[2]]
|
|
168
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
169
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
|
170
|
+
values = [values[0], cur, values[1], values[2]]
|
|
171
|
+
else
|
|
172
|
+
comp = comps[1] + comps[3]-comps[2]
|
|
173
|
+
comps = [comps[1], comps[2], comp, comps[3]]
|
|
174
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
175
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
|
176
|
+
values = [values[1], values[2], cur, values[3]]
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
diff = values.max-values.min
|
|
180
|
+
th = max - diff*opt.fib_ext[1]
|
|
181
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
|
182
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
|
183
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
103
184
|
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
|
185
|
+
break if cur < th
|
|
186
|
+
end
|
|
187
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
|
188
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
|
189
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
|
190
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
|
191
|
+
break if cur < th
|
|
104
192
|
end
|
|
105
193
|
ret
|
|
106
194
|
end
|
|
@@ -211,7 +299,7 @@ module Enumerable
|
|
|
211
299
|
if target <= opt.irep.para_call(para, smith, armor, opt.comp_min)
|
|
212
300
|
return opt.comp_min
|
|
213
301
|
elsif opt.irep.para_call(para, smith, armor, opt.comp_max) < target
|
|
214
|
-
raise
|
|
302
|
+
raise Mgmg::SearchCutException, "given comp_max=#{opt.comp_max} does not satisfies the target"
|
|
215
303
|
end
|
|
216
304
|
while 1 < opt.comp_max - opt.comp_min do
|
|
217
305
|
comp = (opt.comp_max - opt.comp_min).div(2) + opt.comp_min
|
|
@@ -223,90 +311,79 @@ module Enumerable
|
|
|
223
311
|
end
|
|
224
312
|
opt.comp_max
|
|
225
313
|
end
|
|
226
|
-
private def
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
opt.cut_exp, ret = exp, [-1, opt.armor_min, opt.comp_max] if exp <= opt.cut_exp
|
|
235
|
-
exp = Mgmg.exp(opt.armor_max, opt.comp_min)
|
|
236
|
-
opt.cut_exp, ret = exp, [-1, opt.armor_max, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
|
|
237
|
-
(opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
|
|
238
|
-
break if opt.cut_exp < Mgmg.exp(opt.armor_min, comp)
|
|
239
|
-
armor = armor_search(para, target, -1, comp, opt:)
|
|
240
|
-
exp = Mgmg.exp(armor, comp)
|
|
241
|
-
if exp < opt.cut_exp
|
|
242
|
-
opt.cut_exp, ret = exp, [-1, armor, comp]
|
|
243
|
-
elsif exp == opt.cut_exp
|
|
244
|
-
if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, -1, armor, comp) then
|
|
245
|
-
ret = [-1, armor, comp]
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
rescue Mgmg::SearchCutException
|
|
249
|
-
end
|
|
250
|
-
if ret.nil?
|
|
251
|
-
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
|
252
|
-
raise Mgmg::SearchCutException, "the maximum output with given cut_exp=#{opt.cut_exp.comma3} is #{max.comma3}, which does not reach given target=#{target.comma3}"
|
|
253
|
-
end
|
|
254
|
-
ret
|
|
314
|
+
private def eval_comp_sa(para, target, comp, opt, eo)
|
|
315
|
+
return [nil, Float::INFINITY] if (comp < opt.comp_min or opt.comp_max < comp)
|
|
316
|
+
comp -= 1 if ( opt.comp_min<comp and eo & (2**(comp&1)) == 0 )
|
|
317
|
+
sa = sa_search(para, target, comp, opt:)
|
|
318
|
+
exp = Mgmg.exp(*sa, comp)
|
|
319
|
+
[[*sa, comp], exp]
|
|
320
|
+
rescue Mgmg::SearchCutException
|
|
321
|
+
[nil, Float::INFINITY]
|
|
255
322
|
end
|
|
256
|
-
private def
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
exp = Mgmg.exp(opt.smith_max, opt.comp_min)
|
|
266
|
-
opt.cut_exp, ret = exp, [opt.smith_max, -1, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
|
|
267
|
-
(opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
|
|
268
|
-
break if opt.cut_exp < Mgmg.exp(opt.smith_min, comp)
|
|
269
|
-
smith = smith_search(para, target, -1, comp, opt:)
|
|
270
|
-
exp = Mgmg.exp(smith, comp)
|
|
271
|
-
if exp < opt.cut_exp
|
|
272
|
-
opt.cut_exp, ret = exp, [smith, -1, comp]
|
|
273
|
-
elsif exp == opt.cut_exp
|
|
274
|
-
if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, smith, -1, comp) then
|
|
275
|
-
ret = [smith, -1, comp]
|
|
276
|
-
end
|
|
323
|
+
private def fine_sa(exp_best, ret, para, target, comp, opt, eo)
|
|
324
|
+
return [exp_best, ret] if eo & (2**(comp&1)) == 0
|
|
325
|
+
sa = sa_search(para, target, comp, opt:)
|
|
326
|
+
exp = Mgmg.exp(*sa, comp)
|
|
327
|
+
if exp < exp_best
|
|
328
|
+
exp_best, ret = exp, [*sa, comp]
|
|
329
|
+
elsif exp == exp_best
|
|
330
|
+
if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, *sa, comp) then
|
|
331
|
+
ret = [*sa, comp]
|
|
277
332
|
end
|
|
278
|
-
rescue Mgmg::SearchCutException
|
|
279
333
|
end
|
|
280
|
-
|
|
281
|
-
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
|
282
|
-
raise Mgmg::SearchCutException, "the maximum output with given cut_exp=#{opt.cut_exp.comma3} is #{max.comma3}, which does not reach given target=#{target.comma3}"
|
|
283
|
-
end
|
|
284
|
-
ret
|
|
334
|
+
[exp_best, ret]
|
|
285
335
|
end
|
|
286
336
|
def search(para, target, opt: Mgmg::Option.new)
|
|
287
337
|
opt = opt.dup.set_default(self)
|
|
288
|
-
|
|
338
|
+
begin
|
|
339
|
+
opt.comp_min = comp_search(para, target, opt.smith_max, opt.armor_max, opt:)
|
|
340
|
+
rescue Mgmg::SearchCutException
|
|
341
|
+
foo = opt.irep.para_call(para, opt.smith_max, opt.armor_max, opt.comp_max)
|
|
342
|
+
raise Mgmg::SearchCutException, "#{self} could not reach target=#{target} until (smith_max, armor_max, comp_max)=(#{opt.smith_max}, #{opt.armor_max}, #{opt.comp_max}), which yields #{foo.comma3}"
|
|
343
|
+
end
|
|
289
344
|
opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
|
|
290
|
-
opt.smith_max = smith_search(para, target, opt.armor_min, opt.comp_min, opt: opt_nocut) rescue (
|
|
291
|
-
opt.armor_max = armor_search(para, target, opt.smith_min, opt.comp_min, opt: opt_nocut) rescue (
|
|
345
|
+
opt.smith_max = smith_search(para, target, opt.armor_min, opt.comp_min, opt: opt_nocut) rescue ( opt.smith_max )
|
|
346
|
+
opt.armor_max = armor_search(para, target, opt.smith_min, opt.comp_min, opt: opt_nocut) rescue ( opt.armor_max )
|
|
292
347
|
opt.smith_min = smith_search(para, target, opt.armor_max, opt.comp_max, opt: opt_nocut)
|
|
293
348
|
opt.armor_min = armor_search(para, target, opt.smith_max, opt.comp_max, opt: opt_nocut)
|
|
294
349
|
raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
|
|
295
350
|
opt.comp_max = comp_search(para, target, opt.smith_min, opt.armor_min, opt:)
|
|
296
351
|
exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_max)
|
|
297
352
|
opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp <= opt.cut_exp
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
353
|
+
eo = opt.irep.eo_para(para)
|
|
354
|
+
comps = Mgmg.fib_init(opt.comp_min, opt.comp_max)
|
|
355
|
+
values = comps.map do |comp|
|
|
356
|
+
r, e = eval_comp_sa(para, target, comp, opt_nocut, eo)
|
|
357
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
358
|
+
e
|
|
359
|
+
end
|
|
360
|
+
while 3 < comps[3]-comps[0]
|
|
361
|
+
if values[1] <= values[2]
|
|
362
|
+
comp = comps[0] + comps[2]-comps[1]
|
|
363
|
+
comps = [comps[0], comp, comps[1], comps[2]]
|
|
364
|
+
r, e = eval_comp_sa(para, target, comp, opt_nocut, eo)
|
|
365
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
366
|
+
values = [values[0], e, values[1], values[2]]
|
|
367
|
+
else
|
|
368
|
+
comp = comps[1] + comps[3]-comps[2]
|
|
369
|
+
comps = [comps[1], comps[2], comp, comps[3]]
|
|
370
|
+
r, e = eval_comp_sa(para, target, comp, opt_nocut, eo)
|
|
371
|
+
opt.cut_exp, ret = e, r if e < opt.cut_exp
|
|
372
|
+
values = [values[1], values[2], e, values[3]]
|
|
308
373
|
end
|
|
374
|
+
end
|
|
375
|
+
exp_best = opt.cut_exp
|
|
376
|
+
diff = values.max-values.min
|
|
377
|
+
opt.cut_exp = exp_best + diff*opt.fib_ext[0]
|
|
378
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
|
379
|
+
exp_best, ret = fine_sa(exp_best, ret, para, target, comp, opt, eo)
|
|
309
380
|
rescue Mgmg::SearchCutException
|
|
381
|
+
break
|
|
382
|
+
end
|
|
383
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
|
384
|
+
exp_best, ret = fine_sa(exp_best, ret, para, target, comp, opt, eo)
|
|
385
|
+
rescue Mgmg::SearchCutException
|
|
386
|
+
break
|
|
310
387
|
end
|
|
311
388
|
if ret.nil?
|
|
312
389
|
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
|
@@ -327,25 +404,107 @@ module Enumerable
|
|
|
327
404
|
end
|
|
328
405
|
smith
|
|
329
406
|
end
|
|
407
|
+
private def eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
408
|
+
smith = Mgmg.invexp3(max_exp, armor, comp)
|
|
409
|
+
exp = Mgmg.exp(smith, armor, comp)
|
|
410
|
+
return [-Float::INFINITY, ret, max] if max_exp < exp
|
|
411
|
+
cur = opt.irep.para_call(para, smith, armor, comp)
|
|
412
|
+
smith = minimize_smith(para, smith, armor, comp, cur, opt) if max <= cur
|
|
413
|
+
ret, max = [smith, armor, comp], cur if ( max < cur || ( max == cur && exp < Mgmg.exp(*ret) ) )
|
|
414
|
+
[cur, ret, max]
|
|
415
|
+
end
|
|
416
|
+
private def eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
417
|
+
return [-Float::INFINITY, ret, max] if (comp < opt.comp_min or opt.comp_max < comp)
|
|
418
|
+
comp -= 1 if ( opt.comp_min<comp and ( eo & (2**(comp&1)) == 0 ) )
|
|
419
|
+
cur = -Float::INFINITY
|
|
420
|
+
a_max = [opt.armor_max, Mgmg.invexp3(max_exp, opt.smith_min, comp)].min
|
|
421
|
+
arms = Mgmg.fib_init(opt.armor_min, a_max)
|
|
422
|
+
a_vals = arms.map do |armor|
|
|
423
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
424
|
+
cur_i
|
|
425
|
+
end
|
|
426
|
+
while 3 < arms[3]-arms[0]
|
|
427
|
+
if a_vals[2] <= a_vals[1]
|
|
428
|
+
armor = arms[0] + arms[2]-arms[1]
|
|
429
|
+
arms = [arms[0], armor, arms[1], arms[2]]
|
|
430
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
431
|
+
a_vals = [a_vals[0], cur_i, a_vals[1], a_vals[2]]
|
|
432
|
+
cur = cur_i if cur < cur_i
|
|
433
|
+
else
|
|
434
|
+
armor = arms[1] + arms[3]-arms[2]
|
|
435
|
+
arms = [arms[1], arms[2], armor, arms[3]]
|
|
436
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
437
|
+
a_vals = [a_vals[1], a_vals[2], cur_i, a_vals[3]]
|
|
438
|
+
cur = cur_i if cur < cur_i
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
diff = a_vals.max-a_vals.min
|
|
442
|
+
th = max - diff*opt.fib_ext[1]
|
|
443
|
+
(arms[0]-1).downto(opt.armor_min) do |armor|
|
|
444
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
445
|
+
break if cur_i < th
|
|
446
|
+
cur = cur_i if cur < cur_i
|
|
447
|
+
end
|
|
448
|
+
(arms[3]+1).upto(a_max) do |armor|
|
|
449
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
|
450
|
+
break if cur_i < th
|
|
451
|
+
cur = cur_i if cur < cur_i
|
|
452
|
+
end
|
|
453
|
+
[cur, ret, max]
|
|
454
|
+
end
|
|
330
455
|
def find_max(para, max_exp, opt: Mgmg::Option.new)
|
|
331
456
|
opt = opt.dup.set_default(self)
|
|
332
457
|
exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
|
|
333
458
|
raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
|
|
334
459
|
ret = [Mgmg.invexp3(max_exp, opt.armor_min, opt.comp_min), opt.armor_min, opt.comp_min]
|
|
335
460
|
max = opt.irep.para_call(para, *ret)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
461
|
+
eo = opt.irep.eo_para(para)
|
|
462
|
+
opt.comp_max = [opt.comp_max, Mgmg.invexp3c(max_exp, opt.smith_min, opt.armor_min)].min
|
|
463
|
+
comps = Mgmg.fib_init(opt.comp_min, opt.comp_max)
|
|
464
|
+
values = comps.map do |comp|
|
|
465
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
466
|
+
cur
|
|
467
|
+
end
|
|
468
|
+
while 3 < comps[3]-comps[0]
|
|
469
|
+
if values[2] <= values[1]
|
|
470
|
+
comp = comps[0] + comps[2]-comps[1]
|
|
471
|
+
comps = [comps[0], comp, comps[1], comps[2]]
|
|
472
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
473
|
+
values = [values[0], cur, values[1], values[2]]
|
|
474
|
+
else
|
|
475
|
+
comp = comps[1] + comps[3]-comps[2]
|
|
476
|
+
comps = [comps[1], comps[2], comp, comps[3]]
|
|
477
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
478
|
+
values = [values[1], values[2], cur, values[3]]
|
|
343
479
|
end
|
|
344
480
|
end
|
|
481
|
+
diff = values.max-values.min
|
|
482
|
+
th = max - diff*opt.fib_ext[1]
|
|
483
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
|
484
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
|
485
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
486
|
+
break if cur < th
|
|
487
|
+
end
|
|
488
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
|
489
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
|
490
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
|
491
|
+
break if cur < th
|
|
492
|
+
end
|
|
345
493
|
ret
|
|
346
494
|
end
|
|
347
495
|
end
|
|
348
496
|
|
|
497
|
+
class << Mgmg
|
|
498
|
+
def fib_init(min, max)
|
|
499
|
+
z = min-1
|
|
500
|
+
a, b = 2, 3
|
|
501
|
+
while z + b < max do
|
|
502
|
+
a, b = b, a+b
|
|
503
|
+
end
|
|
504
|
+
[z, z+b-a, z+a, z+b]
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
349
508
|
module Mgmg
|
|
350
509
|
Eighth = 1.quo(8)
|
|
351
510
|
module_function def find_lowerbound(a, b, para, start, term, opt_a: Option.new, opt_b: Option.new)
|
|
@@ -382,28 +541,27 @@ module Mgmg
|
|
|
382
541
|
loop do
|
|
383
542
|
foo = a.find_max(para, eb, opt: opt_a)
|
|
384
543
|
break if sca == foo
|
|
385
|
-
|
|
544
|
+
bar = opt_a.irep.para_call(para, *foo)
|
|
545
|
+
break if bar < pa
|
|
546
|
+
sca, pa = foo, bar
|
|
386
547
|
scb = b.search(para, pa, opt: opt_b)
|
|
387
548
|
foo = Mgmg.exp(*scb)
|
|
388
549
|
break if eb == foo
|
|
389
550
|
eb = foo
|
|
390
551
|
end
|
|
391
552
|
ea = Mgmg.exp(*sca)
|
|
392
|
-
|
|
393
|
-
tag = pa + Eighth
|
|
394
|
-
raise Mgmg::SearchCutException, "given recipes are never reversed from start target=#{start.comma3} until term target=#{term.comma3}" if term < tag
|
|
395
|
-
sca, scb = a.search(para, tag, opt: opt_a), b.search(para, tag, opt: opt_b)
|
|
396
|
-
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
|
397
|
-
pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
|
|
398
|
-
break if ea == eb && pa < pb
|
|
399
|
-
end
|
|
400
|
-
if eb < ea || ( ea == eb && pa < pb )
|
|
553
|
+
if (eb <= ea and pa <= pb and (eb+pa)!=(ea+pb)) or (eb < ea and sca == a.search(para, pb, opt: opt_a)) then
|
|
401
554
|
until ea < eb || ( ea == eb && pb < pa )
|
|
402
555
|
sca = a.find_max(para, ea-1, opt: opt_a)
|
|
403
556
|
ea, pa = Mgmg.exp(*sca), opt_a.irep.para_call(para, *sca)
|
|
404
557
|
end
|
|
405
558
|
return [pa, pb]
|
|
406
559
|
end
|
|
560
|
+
tag = pa + Eighth
|
|
561
|
+
raise Mgmg::SearchCutException, "given recipes are never reversed from start target=#{start.comma3} until term target=#{term.comma3}" if term < tag
|
|
562
|
+
sca, scb = a.search(para, tag, opt: opt_a), b.search(para, tag, opt: opt_b)
|
|
563
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
|
564
|
+
pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
|
|
407
565
|
end
|
|
408
566
|
raise UnexpectedError
|
|
409
567
|
end
|
|
@@ -430,7 +588,6 @@ module Mgmg
|
|
|
430
588
|
raise Mgmg::SearchCutException, "given recipes are equivalent at start target=#{start.comma3}"
|
|
431
589
|
end
|
|
432
590
|
|
|
433
|
-
|
|
434
591
|
loop do
|
|
435
592
|
loop do
|
|
436
593
|
foo = a.find_max(para, eb, opt: opt_a)
|
|
@@ -444,38 +601,40 @@ module Mgmg
|
|
|
444
601
|
eb = foo
|
|
445
602
|
end
|
|
446
603
|
ea = Mgmg.exp(*sca)
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
res += 1
|
|
604
|
+
pb = opt_b.irep.para_call(para, *scb)
|
|
605
|
+
if ea <= eb and pb <= pa and (ea+pb)!=(eb+pa) then
|
|
606
|
+
until pa < pb
|
|
607
|
+
scb = b.search(para, pb+Eighth, opt: opt_b)
|
|
608
|
+
pb = opt_b.irep.para_call(para, *scb)
|
|
453
609
|
end
|
|
610
|
+
return [pa, pb]
|
|
611
|
+
elsif ea < eb
|
|
612
|
+
return [pa, pb] if scb == b.search(para, pa, opt: opt_b)
|
|
613
|
+
end
|
|
614
|
+
tag = [ea, eb].min - 1
|
|
615
|
+
begin
|
|
616
|
+
scb = b.find_max(para, tag, opt: opt_b)
|
|
617
|
+
rescue Mgmg::SearchCutException
|
|
618
|
+
eb, pb = Mgmg.exp(*scb), opt_b.irep.para_call(para, *scb)
|
|
454
619
|
begin
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
|
|
461
|
-
if ea < eb || ( ea == eb && pb < pa )
|
|
462
|
-
until pa < pb
|
|
463
|
-
scb = b.search(para, pb+Eighth, opt: opt_b)
|
|
464
|
-
pb = opt_b.irep.para_call(para, *scb)
|
|
620
|
+
sca = a.find_max(para, eb, opt: opt_a)
|
|
621
|
+
ea, pa = Mgmg.exp(*sca), opt_a.irep.para_call(para, *sca)
|
|
622
|
+
while eb <= ea
|
|
623
|
+
sca = a.find_max(para, ea-1, opt: opt_a)
|
|
624
|
+
ea, pa = Mgmg.exp(*sca), opt_a.irep.para_call(para, *sca)
|
|
465
625
|
end
|
|
466
|
-
|
|
467
|
-
elsif res == 2
|
|
626
|
+
rescue Mgmg::SearchCutException
|
|
468
627
|
raise Mgmg::SearchCutException, "given recipes are never reversed from the start target=#{start.comma3} until #{pa.comma3}"
|
|
469
628
|
end
|
|
470
|
-
end
|
|
471
|
-
if ea < eb
|
|
472
|
-
pb = opt_b.irep.para_call(para, *scb)
|
|
473
|
-
until pa < pb
|
|
474
|
-
scb = b.search(para, pb+Eighth, opt: opt_b)
|
|
475
|
-
pb = opt_b.irep.para_call(para, *scb)
|
|
476
|
-
end
|
|
477
629
|
return [pa, pb]
|
|
478
630
|
end
|
|
631
|
+
begin
|
|
632
|
+
sca = a.find_max(para, tag, opt: opt_a)
|
|
633
|
+
rescue Mgmg::SearchCutException
|
|
634
|
+
raise Mgmg::SearchCutException, "given recipes are never reversed from the start target=#{start.comma3} until #{opt_a.irep.para_call(para, *sca).comma3}"
|
|
635
|
+
end
|
|
636
|
+
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
|
637
|
+
pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
|
|
479
638
|
end
|
|
480
639
|
raise UnexpectedError
|
|
481
640
|
end
|
data/lib/mgmg/version.rb
CHANGED
data/reference.md
CHANGED
|
@@ -130,12 +130,9 @@
|
|
|
130
130
|
`opt`は,`comp_min`,`comp_max`,`left_associative`,`reinforcement`,`irep`を使用します.
|
|
131
131
|
|
|
132
132
|
## `String#search(para, target, opt: Mgmg.option())`
|
|
133
|
-
|
|
134
|
-
`smith_search`を行い,その過程で得られた最小経験値の鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.
|
|
135
|
-
レシピ中の,対象パラメータの種別値がすべて奇数,または全て偶数であるなら,`opt.step`を`2`にしても探索すべき範囲を網羅できます.
|
|
136
|
-
その他は`String#smith_seach`と同様です.
|
|
133
|
+
合計経験値が最小となる鍛冶・防具製作Lvと道具製作Lvの組を探索します.道具製作Lvを決定変数として,`smith_search`の返り値との合計経験値を最小化する道具製作Lvをフィボナッチ探索で探索した後,得られた解 c の前後を探索し,最適化します.このとき,道具製作Lv c における合計経験値`exp`,及びフィボナッチ探索で得られた最後の4点の経験値の最大値`exp2`に対して,`exp+(exp2-exp)*opt.fib_ext[0]`を超えない範囲を探索します.この目的関数は単峰ではないため,フィボナッチ探索のみでは最適解が得られないことがあります.
|
|
137
134
|
|
|
138
|
-
|
|
135
|
+
その他は`String#smith_seach`と同様で,`opt`は,`String#smith_search`または`String#comp_search`で使われるすべてのパラメータと,`fib_ext`を使用します.
|
|
139
136
|
|
|
140
137
|
## `Enumerable#search(para, target, opt: Mgmg.option())`
|
|
141
138
|
複数装備の組について,`para`の値が`target`以上となる最小経験値の`[鍛冶Lv,防具製作Lv,道具製作Lv]`を返します.
|
|
@@ -143,11 +140,13 @@
|
|
|
143
140
|
|
|
144
141
|
`opt.smith_min`および`opt.armor_min`のデフォルト値は,武器・防具の各総重量を`opt.target_weight`で製作するのに必要な鍛冶・防具製作Lv (`self.min_level(*opt.target_weight)`)です.`opt.target_weight`には2要素からなる配列を指定しますが,整数が与えられた場合,それを2つ並べた配列と同等のものとして扱います.合計重量を指定することにはならないので注意してください.`opt.target_weight`のデフォルト値は`0`です.
|
|
145
142
|
|
|
146
|
-
その他は,`String#
|
|
143
|
+
その他は,`String#seach`と同様です.
|
|
147
144
|
|
|
148
145
|
## `String#find_max(para, max_exp, opt: Mgmg.option())`
|
|
149
146
|
経験値の合計が`max_exp`以下の範囲で,`para`の値が最大となる鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.`para`の値が最大となる組が複数存在する場合,経験値が小さい方が優先されます.
|
|
150
147
|
|
|
148
|
+
`String#search`と同様に,道具製作Lvをフィボナッチ探索で探索した後,得られた解 c の前後を探索し,最適化します.道具製作Lv c における最大の`para`値`p_c`,及びフィボナッチ探索で得られた最後の4点の`para`値の最小値`p_min`に対して,`p_c-(p_c-p_min)*opt.fib_ext[1]`を下回らない範囲を探索します.
|
|
149
|
+
|
|
151
150
|
## `Enumerable#find_max(para, max_exp, opt: Mgmg.option())`
|
|
152
151
|
複数装備の組について,経験値の合計が`max_exp`以下の範囲で,`para`の値が最大となる鍛冶Lv,防具製作Lv,道具製作Lvからなる配列を返します.`para`の値が最大となる組が複数存在する場合,経験値が小さい方が優先されます.
|
|
153
152
|
|
|
@@ -455,9 +454,9 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
|
455
454
|
|smith_min|`recipe.min_level(target_weight)`|非対応|鍛冶Lvに関する探索範囲の最小値|`String#search`など|
|
|
456
455
|
|armor_min|`recipe.min_level(*target_weight)[1]`|非対応|防具製作Lvに関する探索範囲の最小値|`Enumerable#search`など.`String`系では代わりに`smith_min`を使う|
|
|
457
456
|
|comp_min|`recipe.min_comp`|非対応|道具製作Lvに関する探索範囲の最小値|`String#search`など|
|
|
458
|
-
|smith_max, armor_max, comp_max|`
|
|
457
|
+
|smith_max, armor_max, comp_max|`100_000`|対応|各製作Lvの探索範囲の最大値|`String#search`など|
|
|
458
|
+
|fib_ext|`[4, 10]`|対応|フィボナッチ探索後に追加探索を行う範囲|`String#search`など|
|
|
459
459
|
|target_weight|`0`|非対応|`smith_min`のデフォルト値計算に使う目標重量|`String#search`など|
|
|
460
|
-
|step|`1`|非対応|探索時において道具製作Lvを動かす幅|`String#search`など|
|
|
461
460
|
|magdef_maximize|`true`|非対応|目標を魔防最大(真)かコスト最小(偽)にするためのスイッチ|`String#phydef_optimize`|
|
|
462
461
|
|reinforcement|`[]`|非対応|[前述](#mgmgequipreinforcearg)の`Mgmg::Equip#reinforce`による強化リスト|一部を除くすべてのメソッド|
|
|
463
462
|
|buff|`[]`|非対応|`reinforcement`のエイリアス|どちらか一方のみを指定する|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mgmg
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- KAZOON
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-11-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
104
104
|
- !ruby/object:Gem::Version
|
|
105
105
|
version: '0'
|
|
106
106
|
requirements: []
|
|
107
|
-
rubygems_version: 3.3.
|
|
107
|
+
rubygems_version: 3.3.25
|
|
108
108
|
signing_key:
|
|
109
109
|
specification_version: 4
|
|
110
110
|
summary: Calculate specs of equipments of Megurimeguru, a game produced by Kou.
|