Skip to content

Instantly share code, notes, and snippets.

@vznvzn
Created February 17, 2018 02:19
Show Gist options
  • Save vznvzn/ed016e31d123e8c8fa5173eb3a4e1594 to your computer and use it in GitHub Desktop.
Save vznvzn/ed016e31d123e8c8fa5173eb3a4e1594 to your computer and use it in GitHub Desktop.
def f2(n)
return n.odd? ? (n * 3 + 1) / 2 : n / 2
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).to_i(2)
end
def stat(l)
l = [0] if (l.empty?)
t = t2 = 0
l.each \
{
|x|
t += x
t2 += x ** 2
}
c = l.size
a = t.to_f / c
z = t2.to_f / c - a ** 2
sd = Math.sqrt(z < 0 ? 0 : z)
return a, sd, l.max.to_f, l.min.to_f
end
def stat2(l, t, n)
return Hash[[["a#{n}", "sd#{n}", "mx#{n}"], stat(l)[0..2]].transpose]
end
def d(s)
c = s.split('').select { |x| x == '1' }.size
d = c.to_f / s.length
return d
end
def data(n)
$seen = {'h' => 0} if ($seen.nil?)
seen = $seen
if (seen.member?(n)) then
seen['h'] += 1
$stderr.puts("h #{seen['h']} ss #{seen.size}") if (seen['h'] % 1000 == 0)
return seen[n]
end
ns = n.to_s(2)
nl = ns.length
m = nl / 2
nsh = ns[0..m]
nsl = ns[m..-1]
asdm1 = stat2(ns.split(/0+/).map { |x| x.length }, nl, 1)
asdm0 = stat2(ns.split(/1+/)[1..-1].map { |x| x.length }, nl, 0)
x = {'n' => n, 'ns' => ns, 'nl' => nl, 'd' => d(ns), 'dh' => d(nsh), 'dl' => d(nsl)}.merge(asdm1).merge(asdm0)
seen[n] = x if (seen.size < 100e3)
return x
end
def count(z)
n = z['n']
n1 = n
l = []
mmx0 = 0
mmx1 = 0
begin
x = data(n)
mmx0, mmx1 = [[mmx0, x['mx0']].max, [mmx1, x['mx1']].max]
l << n
n = f2(n)
end while (n > n1)
m = (0...l.size).max_by { |x| l[x] }
r = l[m].to_s(2).length - n1.to_s(2).length
return z.merge({'c' => l.size, 'n' => n1, 'l' => l, 'm' => m, 'r' => r, 'mmx0' => mmx0, 'mmx1' => mmx1, 'mmx' => [mmx0, mmx1].max})
end
def init1(m)
w = 100
l = []
b = 1
while (w > 0)
r = (w == 1) ? 1 : rand([w, m].min) + 1
l << [b] * r
b ^= 1
w -= r
end
s = l.flatten.join
return s
end
def init(m)
c = 0
l = []
20.times \
{
|i|
c += 1
ns = init1(m)
z = count({'ns' => ns, 'n' => ns.to_i(2)})
# p([i, c, z['mmx'], z['c']])
redo if (z['mmx'] > m)
l << z
}
return l
end
def add(l, m, n)
ns = n.to_s(2)
z = count({'ns' => ns, 'n' => n})
return if (z['mmx'] > m)
l.pop if (l.size > 500)
l << z
end
def opt(t)
l = init(t)
w = l[0]['ns'].length
j = 0
mx = nil
1000.times \
{
|j|
break if (l.empty?)
l.sort_by! { |x| -x['c'] }
x = l.delete_at(rand(l.size / 4))
# x = l.delete_at(rand([l.size, 10].min))
mx = [{'c' => x['c'], 'j' => j, 'w' => x['ns'].length, 'mmx' => x['mmx']}, mx].compact.max_by { |x| x['c'] }
n = x['n']
add(l, t, (n - 1) / 3) if (n % 3 == 1 && ((n - 1) / 3).odd?)
add(l, t, n * 2)
}
return mx.merge({'t' => t})
end
def out(fn, a)
f = File.open(fn, 'a')
f.puts(a.keys.join("\t")) if (f.size == 0)
f.puts(a.values.join("\t"))
f.close
end
f = File.open('gnuplot.cmd', 'w')
f.puts <<eof
set colors classic; set y2tics; set ytics nomirror; set y2range [0:]; \\
plot [][0:] 'out.txt' using (column('t')) with line lw 4,\\
'' using (column('mmx')) with line lw 2,\\
'' using (column('c')) with line lw 3 axes x1y2
eof
f.close
File.open(fn = 'out.txt', 'w').close
25.downto(4) { |t| 4.times { out(fn, opt(t)) } }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment