Skip to content

Instantly share code, notes, and snippets.

@vznvzn
Created October 22, 2020 05:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vznvzn/6c7e6b82a7a1d2ee7d67b241bc81d51e to your computer and use it in GitHub Desktop.
Save vznvzn/6c7e6b82a7a1d2ee7d67b241bc81d51e to your computer and use it in GitHub Desktop.
def f2(n)
return n.odd? ? (n * 3 + 1) / 2 : n / 2
end
def seq(n)
l = [n]
while (n != 1)
n = f2(n)
l << n
end
return l
end
def count(ns)
return if (d(ns) != 0.5)
l = seq(n = ns.to_i(2))
nw = ns.length
cg = l.index { |x| x < l[0] }
cg = l.size - 1 if (cg.nil?)
cm = (0..cg).max_by { |x| l[x] }
c = l.size
return {
'ns' => ns,
'c' => c,
'cm' => cm,
'nw' => nw,
'cg' => cg,
'cgnw2' => cg.to_f / nw
}
end
def fmt(a)
['l'].each { |x| a.delete(x) }
return a
end
def axes2(x2)
return x2.inject({}) { |h, x| h.merge({x => 'axes x1y2' }) }
end
def x1y2()
return $a2 if (!$a2.nil?)
$a2 = axes2(['z', 'cgnw2']) if ($a2.nil?)
return $a2
end
def off()
return {'ns' => nil, 'z' => nil}
end
def opts()
return x1y2().merge(off())
end
def d(s)
c = s.split('').select { |x| x == '1' }.size
d = c.to_f / s.length
return d
end
def dense(w, d)
w2 = w - 1
a = (0...w2).to_a
s = '0' * w2
(1..(d * w - 1)).map { a.delete_at(rand(a.size)) }.each { |x| s[x, 1] = '1' }
return ('1' + s)
end
def out(fno, a, a2 = {}, t = nil)
$f = {} if ($f.nil?)
if (!$f.member?(fno)) then
$f[fno] = {'fn' => "out#{fno}.txt", 'c' => 0}
$f[fno]['f'] = File.open($f[fno]['fn'], 'w')
end
f = $f[fno]
f['f'].puts(a.keys.join("\t")) if (f['c'] == 0)
f['f'].puts(a.values.join("\t"))
f['c'] += 1
f['f'].flush
return if ((f['c'] - 1) % 1000 != 0)
d = (f['c'] / 2000).to_i
d = 1 if (d == 0)
f2 = File.open("gnuplot#{fno}.cmd", 'w')
fn = f['fn']
st = t.nil? ? 'unset title; ' : "set title '#{t}'; "
k = "key top left box opaque"
f2.puts("set ytics nomirror; set y2tics; set colors classic; set #{k}; #{st}; plot \\")
(a.keys - ['t']).each \
{
|x|
next if (a2.member?(x) && a2[x].nil?)
f2.puts("'#{fn}' using (column('t')):(column('#{x}')) every #{d} with line title '#{x}' #{a2[x]}, \\")
}
f2.puts
f2.close
end
def rank(x)
return -x['z']
end
def adj(x, wt, km)
z = 0
km.keys.each \
{
|k|
if (x[k].nil?) then
z = nil
break
end
z += (x[k] - wt["#{k}_a"]) / wt["#{k}_s"] * km[k]
}
x['z'] = z.nil? ? 0.0 : z
raise [x['z'], wt].to_s if (!x['z'].finite?)
return x
end
def fmt2(x)
x = x.dup
x.keys.each \
{
|k|
x.delete(k) if (k.end_with?('s'))
}
return x
end
def add(bs, km, h, ns, l1, wt, t)
return 0 if ((a1 = count(ns)).nil?)
j = ns.length
h[j] = [] if (!h.member?(j))
x = adj(a1, wt, km).merge({'t' => t})
return 0 if (h[j].map { |x1| x1['ns'] }.member?(x['ns']))
h[j] << x
h[j].sort_by! { |x| rank(x) }
h[j][bs..-1] = [] if (h[j].size > bs)
x1 = x.dup
out(1, x1, opts())
l1 << x1 if (!l1.nil?)
out(2, fmt2(wt).merge({'t' => t}), {'cgnw2_a' => 'axes x1y2', 'cgnw2_s' => 'axes x1y2'})
return 1
end
def initd(w)
return(dense(w, rand))
end
def initb(w)
r = rand
return '1' + (1...w).map { rand < r ? '0' : '1' }.join
end
def initw(w)
s = dense(w, 0.5)
m = rand(w)
i = rand(w - m) + 1
s[i, m] = rand(2).to_s * m
return s
end
def initr(w)
s = '1'
b = 0
m = rand(w - 1) + 1
while (s.length < w)
z = w - s.length
s += b.to_s * [rand(m - 1) + 1, z].min
b ^= 1
end
return s
end
def init(w)
m = rand(w)
ns1 = dense(w, 0.5)
ns2 = initr(w)
ns1, ns2 = [ns2, ns1] if (rand(2) == 0)
i = rand(w - m) + 1
ns1[i, m] = ns2[i, m]
return ns1
end
def initx(w)
return '1' if (w == 1)
ns = dense(w, 0.5)
r1, r2 = (1..2).map { rand(w - 1) + 1 }.sort
w2 = r2 - r1 + 1
s1 = ['01', '10'][rand(2)]
s = (s1 * ((w2 / 2) + 1))[0...w2]
ns[r1..r2] = s
return ns
end
def range(w)
return [1] if (w == 1)
a = (1..w).to_a
l = (1..2).map { a.delete_at(rand(a.size)) }.sort
return (l[0]..l[1]).to_a
end
def scatter(w)
return [1] if (w == 1)
a = (1..w).to_a
c = rand(a.size) + 1
l = (1..c).map { a.delete_at(rand(a.size)) }.sort
return l
end
def mut(ns, l)
ns2 = ns.dup
l.each { |i| ns2[i, 1] = (ns[i, 1].to_i ^ 1).to_s }
return ns2
end
def muta(ns)
return mut(ns, range(ns.length - 1))
end
def mutb(ns)
return mut(ns, scatter(ns.length - 1))
end
def remix(ns, l1)
ns2 = ns.dup
l2 = l1.shuffle
l1.size.times { |i| ns2[l2[i], 1] = ns[l1[i], 1] }
return ns2
end
def remixa(ns)
return remix(ns, range(ns.length - 1))
end
def remixb(ns)
return remix(ns, scatter(ns.length - 1))
end
def inner(ns1, ns2)
a, b = [ns1, ns2].sort_by { |x| x.length }
d = b.length - a.length
i = rand(d + 1)
c = b.dup
c[i, a.length] = a
ns1.replace(b)
ns2.replace(c)
end
def mix(ns1, ns2)
ns1 = ns1.dup
ns2 = ns2.dup
inner(ns1, ns2)
return (0...ns1.length).map { |x| [ns1, ns2][rand(2)][x, 1] }.join
end
def cut(ns1, ns2)
ns1 = ns1.dup
ns2 = ns2.dup
inner(ns1, ns2)
i = rand(ns1.length)
return ns1[0...i] + ns2[i..-1]
end
def ext(ns)
ns = ns.dup
(rand(3) + 1).times { ns[rand(ns.length) + 1, 0] = rand(2).to_s }
return ns
end
def short(ns)
return ns if (ns.length == 1)
ns = ns.dup
(rand([ns.length - 1, 3].min) + 1).times { ns[rand(ns.length - 1) + 1, 1] = '' }
return ns
end
def top(h1)
return h1[rand([h1.size / 4, h1.size].max)]
end
def stat(l)
return 0, 1.0 if (l.empty?)
t = l.inject { |a, x| a + x }
t2 = l.inject(0) { |a, x| a + x ** 2 }
c = l.size
a = t.to_f / c
z = t2.to_f / c - a ** 2
sd = Math.sqrt(z < 0 ? 0 : z)
raise if (sd.nan?)
return a, sd
end
def dist(km, h, wt, l1)
l = h.values.flatten
['cgnw2', 'cm', 'cg', 'c'].each \
{
|k|
a, sd = stat(l.map { |x| x[k] })
sd = 1.0 if (sd == 0)
wt.merge!({"#{k}_a" => a, "#{k}_s" => sd})
}
end
def nonnil(x, y)
return x.nil? ? y : x
end
def sum(l)
return l.inject { |t, x| t + x }
end
def weighted(ops, ar, ar2, ar1)
ops.size.times \
{
|i|
next if (ar1[i] == 0)
ar[ops[i]] = (ar1[i].to_f / ar2[i]).round(3)
}
return rand(ops.size) if (ar.size != ops.size)
ar.replace(Hash[ar.sort_by { |x| -x[1] }])
wt = sum(ar.values)
x = rand() * wt
i = x1 = 0
i, x1 = [i + 1, x1 + ar[ops[i]]] while (x1 < x)
return i - 1
end
def opt(km, w1, l1, n, w2 = false)
h = {}
ops = ['init', 'initd', 'initb', 'initw', 'initr', 'initx',
'muta1', 'mutb1', 'remixa1', 'remixb1',
'mix2', 'cut2']
ops += ['ext1', 'short1'] if (w2)
bs = 500
bc = 50
t = c1 = 0
wt = {}
ar1 = [0] * ops.size
ar2 = ar1.dup
ar = {}
loop \
{
if (c1 % 100 == 0) then
dist(km, h, wt, l1)
h.values.flatten.each { |x| adj(x, wt, km) }
h.each { |k, l| l.sort_by! { |x| rank(x) } }
end
break if (t == n)
r = weighted(ops, ar, ar2, ar1)
opc = ops[r]
op, p = opc.start_with?('init') ? [opc, 0] : [opc[0..-2], opc[-1..-1].to_i]
ks = h.keys.sort_by { |x| rank(h[x][0]) }
ks = ks[0...[ks.size, ks.size / 4].max]
case (p)
when 0
w = ks.empty? ? w1 : ks[rand(ks.size)]
ns = send(op, w)
when 1, 2
redo if (h.empty?)
h.delete(ks.pop) if (ks.size > bc)
arg = (1..p).map { ks[rand(ks.size)] }
l = arg.map { |x| top(h[x])['ns'] }
ns = send(op, *l)
ns[0, 1] = '1'
end
raise op if (ns[0, 1] != '1')
d = (t.to_f / (c1 + 1) * n / 2000).to_i
c = add(bs, km, h, ns, l1, wt, t)
c1 += c
ar1[r] += c
ar2[r] += 1
if (t % 100 == 0) then
msg = {'t' => t,
'c1' => c1,
'f' => (c1.to_f / t * 100).round(2),
'ar' => ar,
'hmn' => ks.min,
'hmx' => ks.max,
'hc' => h.size,
'wt' => wt}
h0 = nonnil(h.fetch(ks[0], [])[0], {}).dup
msg2 = {'h0' => h0}
['h0'].each { |x| fmt(msg2[x]) }
$stderr.puts(msg)
$stderr.puts("\t" + msg2.inspect) if (t % 1000 == 0)
end
t += 1
}
out(1, {})
out(2, {})
return h
end
def run(a, w = 50, w2 = false)
c = 2e4.to_i
w = 50
h = opt(a, w, nil, c.to_i, w2)
end
run({'cgnw2' => 1})
run({'cgnw2' => 1, 'cm' => 1, 'cg' => 1, 'c' => 1})
run({'cm' => 1, 'cg' => 1, 'c' => 1})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment