Skip to content

Instantly share code, notes, and snippets.

@vznvzn

vznvzn/hybrid53c.rb

Created Jan 2, 2021
Embed
What would you like to do?
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 log2(x)
return Math.log(x) / Math.log(2.0)
end
def count(ns)
d = d(ns)
e = e(ns)
da = (0.5 - d).abs
ea = (0.5 - e).abs
return if (da > 0.05 || ea > 0.05)
return if (len1(ns).max > log2(ns.length))
l = seq(n = ns.to_i(2))
nw = ns.length
cg = l.index { |x| x < l[0] }
cm = (0..cg).max_by { |x| l[x] }
c = l.size
return {
'ns' => ns,
'ns2' => ns.reverse,
'nw' => nw,
'c' => c,
'cg' => cg,
'cm' => cm,
'd' => d,
'e' => e,
'mp2' => midpt2(ns),
'hc' => c.to_f / ns.length,
}
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', 'd', 'e', 'mp2', 'hc', 'pd', 'hc_d', 'hc_x', 'z2']) if ($a2.nil?)
return $a2
end
def off()
return {'ns' => nil, 'ns2' => nil}
end
def opts()
return x1y2().merge(off())
end
def d1(s)
c = s.split('').select { |x| x == '1' }.size
return c
end
def midpt2(ns)
w2 = d1(ns) / 2
l = ns.split('')
i = j = 0
while (i < w2 && j < l.size)
i += l[j].to_i
j += 1
end
return j.to_f / ns.length
end
def d(s)
c = s.split('').select { |x| x == '1' }.size
d = c.to_f / s.length
return d
end
def len(ns, p)
l = ns.split(p)
l = [] if (l.nil?)
l.shift if (l[0] == '')
return l.map { |x| x.length }
end
def len1(ns)
return len(ns, /0+/)
end
def len0(ns)
return len(ns, /1+/)
end
def len01(ns)
return len1(ns), len0(ns)
end
def e(ns)
return len01(ns).flatten.size.to_f / ns.length
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 \\")
c1, c2 = ":(column('w'))", 'linecolor palette' if (a.key?('w'))
(a.keys - ['t']).each \
{
|x|
next if (a2.member?(x) && a2[x].nil?)
f2.puts("'#{fn}' using (column('t')):(column('#{x}'))#{c1} every #{d} with line lw 2 #{c2} #{a2[x]} title '#{x}', \\")
}
f2.puts
f2.close
end
def fmt2(x)
x = x.dup
x.keys.each \
{
|k|
x.delete(k) if (k.end_with?('s'))
}
return x
end
def outd(f, l)
f.puts('$dat << eof')
k = l[0].keys
f.puts(k.join("\t"))
l.each { |x| f.puts(x.values.join("\t")) }
f.puts('eof')
return k
end
def hide(a, x)
return (a.member?(x) && a[x].nil?)
end
def outa(f, l, a = {}, t = '')
k = outd(f, l)
k1 = "key top left opaque"
f.puts("set colors classic; set #{k1}; set title '#{t}'; ")
f.puts("set ytics nomirror; set y2tics;")
f.puts("plot \\")
ct = ''
k, ct = [k - ['t'], "(column('t')):"] if (k.member?('t') && !hide(a, 't'))
k.each \
{
|x|
next if (hide(a, x))
opt = a.fetch(x, '')
opt += ' with line lw 2 ' if (!opt.include?('with') && !opt.include?('pt'))
f.puts("'$dat' using #{ct}(column('#{x}')) #{opt} title '#{x}',\\")
}
f.puts
f.puts("set ytics")
# f.puts("pause -1;")
end
def outafn(l, fn = nil, t = '', a = {})
fn = 'gnuplot.cmd' if (fn.nil?)
outa(f = File.open(fn, 'w'), l, a, t.sub("{", "\\{").sub("}", "\\}"))
f.close
$stderr.puts([fn, l.size, t].inspect)
end
def fmt1(l, f)
w = l.max_by { |x| x.length }.length
f.puts("set colors classic; set ytics nomirror; set y2tics; set key top right opaque;\\")
f.puts("plot \\")
f.puts("[0:#{l.size - 1}][0:#{w}] '-' matrix using 2:1:3 with image title '', \\")
f.puts("'-' using (column('d')) with line axes x1y2 dt 2 lw 3, \\")
f.puts("'-' using 1 with line title 'e' axes x1y2 dt 2 lw 3")
l1 = []
l.each_with_index \
{
|z, i|
l1 << [d(z), e(z)]
c = w - z.length
z[z.length...w] = '0' * c
f.puts(z.split('').join(' '))
}
f.puts("eof")
f.puts("eof")
f.puts("d")
l1.each { |x| f.puts(x[0]) }
f.puts("eof")
l1.each { |x| f.puts(x[1]) }
f.puts("eof")
f.puts("set ytics;")
end
def grid(l, fn, t = '')
f = File.open(fn, 'w')
f.puts("set palette negative grayscale; unset colorbox; set title '#{t}';")
fmt1(l.map { |x| x.reverse }, f)
f.puts("set palette; set colorbox; set title;")
f.close
$stderr.puts([fn, l.size, t].inspect)
end
def fn(n2)
return "gnuplot#{$n}-#{n2}.cmd"
end
def out1(h, k, a)
l = h.values.flatten
l1 = l.map { |x| x['z'] }
mn, mx = [l1.min, l1.max]
l.each { |x| x['z2'] = (x['z'] - mn) / (mx - mn) }
l.sort_by! { |x| x[k] }
t = a.inspect
outafn(l, fn(1), t, opts().merge({'t' => nil, 'z' => nil, 'z_d' => nil}))
grid(l.map { |x| x['ns'] }, fn(2), t)
end
def insert(a, x)
a['ks'].each \
{
|k|
a[k][x[k]] = a[k].fetch(x[k], []) + [x]
mm = [a[k].keys.min, a[k].keys.max]
a[k].delete_if { |k1,| !mm.member?(k1) }
}
end
def delete(a, x)
a['ks'].each \
{
|k|
next if (!a[k].member?(x[k]))
a[k][x[k]].delete(x)
k1 = a[k].keys
a[k].delete(x[k]) if (a[k][x[k]].empty?)
k2 = a[k].keys
raise [k1, k2].inspect if (k1.min != k2.min)
}
end
def unique(a, x)
a['ks'].each \
{
|k|
return true if (a[k].fetch(x[k], []).size == 1)
}
return false
end
def pass(x, h, j, bs, km, j1)
if ($x.nil?) then
$x = {}
$x['ks'] = km.keys.select { |x| x.end_with?('_x') }.map { |x| x.chomp('_x') }
$x['ks'].each { |x| $x[x] = {} }
end
j2 = (0...h[j].size).bsearch { |i| h[j][i]['z'] <= x['z'] }
j2 = h[j].size if (j2.nil?)
j1.replace(j2.to_s)
h[j][j2, 0] = x
insert($x, x)
return if (h[j].size <= bs)
i = h[j].size - 1
i -= 1 while (unique($x, h[j][i]))
delete($x, h[j][i])
h[j][i, 1] = []
end
def add(bs, km, h, ns, l1, wt, t, j1)
return 0 if (ns.nil? || (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']))
pass(x, h, j, bs, km, j1)
x1 = x.dup
out(1, x1, opts())
l1 << x1 if (!l1.nil?)
return 1
end
def initd(w)
return(dense(w, rand))
end
def initdh(w)
return(dense(w, 0.5))
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 inity(w)
return '1' * w if (w <= 2)
w2 = w / 2
w1 = rand(w2)
ns = '1' + '0' * (w - w1 - 1) + '1' * w1
l = (1..(w - w1 - 1)).to_a
(w2 - w1 - 1).times { ns[l.delete_at(rand(l.size)), 1] = '1' }
return ns
end
def mark(w, c)
l = (0...w).to_a
ns = '0' * w
c.times { ns[l.delete_at(rand(l.size))] = '1' }
return ns
end
def mark2(w, c2)
w1 = rand(w2 = w / 2)
ns1 = mark(w1, c = rand(w1 + 1))
ns2 = mark(w - w1 - 1, c2 - c)
# p([[ns1, ns1.length, c], [ns2, ns2.length, c2 - c]])
return ns1 + ns2
end
def flip(ns)
ns = ns.dup
ns.length.times { |i| ns[i] = (ns[i].to_i ^ 1).to_s }
return ns
end
def initm(w)
return '1' * w if (w <= 2)
ns = '1' + mark2(w, w / 2 - 1)
return ns
end
def initmf(w)
return '1' * w if (w <= 2)
ns = '1' + flip(mark2(w, w / 2)).reverse
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)
inner(ns1 = ns1.dup, ns2 = ns2.dup)
return (0...ns1.length).map { |x| [ns1, ns2][rand(2)][x, 1] }.join
end
def cut(ns1, ns2)
inner(ns1 = ns1.dup, ns2 = ns2.dup)
i = rand(ns1.length)
return ns1[0...i] + ns2[i..-1]
end
def ext(ns)
ns = ns.dup
$bd.times { ns[rand(ns.length) + 1, 0] = rand(2).to_s }
return ns
end
def short(ns)
return nil if (ns.length <= 50)
ns = ns.dup
$bd.times { ns[rand(ns.length - 1) + 1, 1] = '' }
return ns
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 sum(l)
return l.inject { |t, x| t + x }
end
def avg(l)
return l.empty? ? 0 : sum(l).to_f / l.size
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 top(l, c)
return l[rand(l.size < c ? l.size : l.size / c)]
end
def linediffs(h, k)
l = h.values.flatten
kd = "#{k}_d"
l.sort_by! { |x| x[k] }
mn = l[0][k]
mx = l[-1][k]
l.size.times \
{
|i|
y = mn + (i.to_f / (l.size - 1)) * (mx - mn)
d = (y - l[i][k])
l[i][kd] = d
}
end
def dist(ks, h, wt)
l = h.values.flatten
ks.each \
{
|k|
l1 = l.map { |x| x[k] }.compact
next if (l1.empty?)
a, sd = stat(l1)
sd = 1.0 if (sd == 0)
wt.merge!({"#{k}_a" => a, "#{k}_s" => sd})
}
end
def absnorm(k, h, wt)
ka = "#{k}_a"
ks = "#{k}_s"
kz = "#{k}_x"
h.values.flatten.each \
{
|x|
x[kz] = (x[k] - wt[ka]).abs / wt[ks]
}
end
def adj(x, wt, km)
z = 0.0
km.keys.each \
{
|k|
if (!wt.member?("#{k}_a")) then
z += x.fetch(k, 0)
next
end
next if (!x.member?(k))
z += (x[k] - wt["#{k}_a"]) / wt["#{k}_s"] * km[k]
}
x['z'] = z
raise [x['z'], wt].to_s if (!x['z'].finite?)
return x
end
def rank(x)
return -x.fetch('z', 0)
end
def bitdiff(ns1, ns2)
mn = [ns1.length, ns2.length].min
b1 = ns1[-mn..-1].to_i(2)
b2 = ns2[-mn..-1].to_i(2)
s = (b1 ^ b2).to_s(2)
t = 0
s.length.times { |i| t += s[i].to_i }
return t
end
def prefixdiff(x, ns1, ns2, k, n = '')
x["pd#{n}"] = [bitdiff(x[k], ns1), bitdiff(x[k], ns2)].min.to_f / [ns1.length + 1, ns2.length + 1].max
end
def prefixdiffs(h, k = 'ns', n = '')
l = h.values.flatten.sort_by! { |x| x[k] }
l.size.times \
{
|x|
prefixdiff(l[x], x == 0 ? '' : l[x - 1][k], x == l.size - 1 ? '' : l[x + 1][k], k, n)
}
end
def prefixdiffs2(h)
prefixdiffs(h, 'ns', 1)
prefixdiffs(h, 'ns2', 2)
h.values.flatten.each { |x| x['pd'] = [x['pd1'], x['pd2']].min }
end
def auxvars(km, h, wt)
prefixdiffs2(h) if (km.member?('pd'))
l1 = []
km2 = km.keys.select { |x| x.include?('_') }
dist(km1 = km.keys - km2, h, wt)
km2.each \
{
|k|
if (k.end_with?('_d')) then
k1 = k.chomp('_d')
linediffs(h, k1)
elsif (k.end_with?('_x')) then
k1 = k.chomp('_x')
dist([k1], h, wt) if (!km1.member?(k1))
absnorm(k1, h, wt)
end
}
dist(km2, h, wt)
h.values.flatten.each { |x| adj(x, wt, km) }
h.each { |k, l| l.sort_by! { |x| rank(x) } }
end
def try(h, ops, ar, ar1, ar2, w1, bc)
begin
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]) }
end while (p > 0 && ks.empty?)
h.delete(ks.pop) if (ks.size > bc)
case (p)
when 0
w = ks.empty? ? w1 : ks[rand(ks.size)]
ns = send(op, w)
when 1, 2
arg = (1..p).map { top(ks, 5) }
l = arg.map { |x| top(h[x], 5)['ns'] }
ns = send(op, *l)
ns[0, 1] = '1' if (!ns.nil?)
end
# raise op if (ns[0, 1] != '1')
return ns, r
end
def log10(x)
return x == 0 ? 0 : Math.log(x) / Math.log(10)
end
def opt(km, w1, l1, n, k)
h = {}
ops = ['init', 'initd', 'initb', 'initw', 'initr', 'initx',
'inity',
'initm', 'initmf',
'initdh',
'muta1', 'mutb1', 'remixa1', 'remixb1',
'mix2', 'cut2']
ops += ['ext1', 'short1'] if (km.member?('w2'))
bs = 50
bs = 500
bc = 20
$bd = 10
t = c1 = 0
wt = {}
ar1 = [0] * ops.size
ar2 = ar1.dup
ar = {}
k0 = z0 = t1 = t2 = t3 = t4 = t21 = 0
loop \
{
ns, r = try(h, ops, ar, ar1, ar2, w1, bc)
c = add(bs, km, h, ns, l1, wt, t, j1 = '')
c1 += c
ar1[r] += c
ar2[r] += 1
if (c == 1 && c1 != 0 && (c1 % 250 == 0)) then
auxvars(km, h, wt)
t21 = log10(t) - log10(t1)
out(2, {
'hmn' => h.keys.min,
'hmx' => h.keys.max,
'hvs' => h.values.flatten.size,
"#{k}0" => k0,
'z0' => z0,
'hc' => h.size,
'j1' => j1.to_i,
't1' => log10(t1),
't2' => log10(t2),
't3' => log10(t3),
't4' => log10(t4),
't21' => t21,
't' => t},
axes2([ "#{k}0", 'z0', 't1', 't2', 't3', 't4', 't21']))
out1(h, k, km.merge({'k' => k, 'c1' => c1})) if (c1 % 5e3 == 0)
end
if (t != 0 && t % 1e3 == 0) then
l = h.values.flatten
x1 = l.max_by { |x| x.fetch('z', 0) }
x2 = l.min_by { |x| x.fetch('z', 0) }
t1 = x1['t']
t2 = x2['t']
t3 = (l2 = l.map { |x| x['t'] }).min
t4 = avg(l2)
z0 = x1['z']
k0 = l.map { |x| x.fetch(k, 0) }.max
msg = {'t' => t,
't21' => (t - t1),
'c1' => c1,
'f' => (c1.to_f / t * 100).round(2),
'hmn' => h.keys.min,
'hmx' => h.keys.max,
'hc' => h.size,
}
z = Hash[$x['ks'].map { |k1| [k1, Hash[$x[k1].map { |k2, v| [k2, v.size] }.sort]]}]
$stderr.puts(msg)
$stderr.puts("\t" + ar.inspect + "\n\t" + z.inspect) if (t % 2e4 == 0)
break if (t > 1e4 && t21 > 1.0)
end
t += 1
}
return h
end
a = {
# 'c' => 1
'hc_d' => 1,
'hc_x' => 1,
'cg_d' => 1,
'cg_x' => 1,
'cm_d' => 1,
'cm_x' => 1,
'pd' => 1,
# 'cm' => 1,
# 'nw_d' => 1,
# 'w2' => nil
}
h = opt(a, w = 200, nil, c = 1e4.to_i, k = 'hc')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment