On 7/14/08, -j b- [email protected] wrote:
Symbolify (#169)
Your task this week is to count. Yup, that’s it.
Oh, by the way… You may only use the characters ?
, *
, (
, )
and -
.
Fairly straightforward; handles negative and positive. I tried for the
shortest resulting encoding but fell a little short compared to some of
the other results .
My solution tries for the absolute shortest encoding without cheating.
That makes it pretty slow, so I added some optional optimizations to
help it run faster.
Without the ** operator, I get
(0…1000).inject(‘’){|s,i|s+=symbolify(i)}.length == 16001
-Adam
---- symbolify.rb —
class Symbolifier
def initialize opt_lvl=0,max=nil
@strings={} # @strings[n] = [symbolify(n),t]
@values = {} # @values[x] = [all n such that symbolify(n).size == x]
@todo = {}
@newlengths = {}
@optimization = opt_lvl
@max = max&&max2 #store values 2x as big as max so we can subtract
insert(%w{ ?? ?- ? ?) ?(}.map{|s|[s,:digit]})
update_todo
end
def [] x
rec = @strings[x]
p :EXP,rec if rec&&rec[1]==:exp
return rec[0] if rec
rec = @strings[-x]
if rec
r=(rec[1]==:add) ? '-('+rec[0]+')' : '-'+rec[0]
return r.sub(/^--/,'')
end
return rec if rec=gen_alternates(x) if @optimization>=2
until (rec=generate(x))
return rec if rec=gen_alternates(x) if @optimization>=1
end
return rec
end
private
def add_syms s1,s2
[((s2[0]==?-)? “%s%s”:“%s–%s”)%[s1,s2],:add]
end
def sub_syms s1,s2,t2
[((t2==:add)? “%s-(%s)”:“%s-%s”)%[s1,s2],:add]
end
def mul_syms s1,s2,t1,t2
ss=“%s*%s”
ss = “(%s)*%s” if (t1==:add)
ss[-2…-1]=“(%s)” if (t2==:add)
[ss%[s1,s2],:mul]
end
def exp_syms s1,s2
[“(%s)**(%s)”%[s1,s2],:exp]
end
def store v,rep
(@values[rep[0].size]||=[])<<v
@strings[v] = rep
@newlengths[rep[0].size]=true
#~ p :EXP,rep if rep[1]==:exp
end
def insert newsyms
newsyms.each{|s|
if (0 > v=eval(s[0]))
v=-v
s[0]=(s[1]==:add) ? ‘-(’+s[0]+‘)’ : ‘-’+s[0]
end
next if @max && v>@max
if !@strings[v]
store(v,s)
elsif (@strings[v][0].size > s[0].size)
@values[@strings[v][0].size].delete(v)
store(v,s)
end
}
end
def generate(target)
a_idx,b_idx,newlen = 0,0,Float::MAX
@todo.each{|k,a| if (k+a[0]<newlen)
a_idx,b_idx = k,a[0]
newlen = a_idx+b_idx
end
}
@todo[a_idx].delete(b_idx)
p “generating strings of length>= #{newlen+1} (#{a_idx}+#{b_idx}+1)”
newvals=[]
@values[a_idx].each{|v1|
@values[b_idx].each{|v2|
s1,t1 = @strings[v1]
s2,t2 = @strings[v2]
newvals<< add_syms(s1,s2)
newvals<< sub_syms(s1,s2,t2)
newvals << mul_syms(s1,s2,t1,t2)
REMOVE following line for significant speedup
newvals <<exp_syms(s1,s2)
}
}
insert(newvals)
update_todo
f=@strings[target]
p :EXP,f if f&&f[1]==:exp
return f[0] if f
end
def gen_alternates(x)
newvals=[]
len,alt = 3e30,nil
(1…5).each{|i|
s1,t1=@strings[i]
if (s1)
s2,t2 = @strings[x-i]
newvals<< add_syms(s1,s2) if (s2)
s2,t2 = @strings[x+i]
newvals<< sub_syms(s2,s1,t1) if (s2)
s2,t2 = @strings[x/i]
m,tm=@strings[x%i]
if (s2 && m)
s3,t3 = mul_syms(s1,s2,t1,t2)
newvals<< add_syms(s2,m)
end
end
}
insert(newvals)
update_todo
f=@strings[x]
return f[0] if f
end
def update_todo
@newlengths.keys.each{|len|@todo[len]||=[]
@todo.each{|k,a| a<<len if k<=len;a.sort!.uniq!}
}
@newlengths={}
end
end
def symbolify x
$ymbolifier ||= Symbolifier.new
CHANGE TO
$ymbolifier ||= Symbolifier.new opt_level_1_or_2,max_input
for faster performance
return $ymbolifier[x]
end