Help needed: Dynamically create a Proc from a String and eva

Dear all,

I need help in dynamically creating a Proc from a String like, say,

a='f(x)=c*exp(x/k)',

(I need to do this many times for many different formulas)
which I want to use Ruby to calculate as a function of x, given
constants c,k, i.e.,
In this example, I want the following lines to produce,

b=a.generate_formula => "def f(x)\n\n return Proc.new{|c,x,k|
cexp(x/k) }\n end \n"
c=a.eval_formula({‘c’,5.0,‘k’,2.0,‘x’,1.0}) => 5
exp(0.5)

The first line is o.k., and I manage to change the string b
to

d=“f(1.0).call(5.0,2.0)”,

but I can’t eval it using

eval(b) # (should make the function available as a Proc method)
eval(d) # (should output the value at x=1.0)

because the first variable,x , doesn’t get its value assigned:

t00.rb:102:in eval_formula': (eval):6:in/’: nil can’t be coerced into
Float (TypeError)
from (eval):6:in Ie' from (eval):1:incall’
from (eval):1:in eval_formula' from t00.rb:64:ineval’
from t00.rb:102:in eval_formula' from t00.rb:64:ineach’
from t00.rb:64:in `eval_formula’
from t00.rb:131

Is there a better way to do this ?

Thank you!

Best regards,

Axel

Can we see the code of your eval_formula?

Jason

On Tue, Jun 05, 2007 at 04:18:58AM +0900, Axel E. wrote:

I need help in dynamically creating a Proc from a String like, say,

a='f(x)=c*exp(x/k)',

If you’re passing in c and k each time, then

b = eval(“proc{|c,x,k| c*Math.exp(x/k) }”)
puts b.call(5.0, 2.0, 1.0)

This means you only call eval once, to create the proc object, then you
can
call it as many times as you like.

If c and k really are constants then you can substitute them in to the
proc
definition:

c = 5
k = 2
a = eval(“proc { |x| #{c}*Math.exp(x/#{k}) }”)
puts a.call(3)

or you can use the closure property to bind the local variables
directly:

c = 5
k = 2
a = eval(“proc { |x| c*Math.exp(x/k) }”)
puts a.call(3)

Brian.

Dear Brian,

thank you for responding.
However, I still haven’t solved my problem.
So, following one of your suggestions, I get:

p ‘function-text’
p f => “eval(‘proc{|c,x,k| c*Math.exp(x/k) }’)”
g=eval(f)=> #Proc:[email protected]:1(eval)

p g(1.0).call(2,5) => undefined function or variable ‘g’

I can’t get to use the proc I just created… Why not ?

Thank you,
Axel

-------- Original-Nachricht --------
Datum: Tue, 5 Jun 2007 04:55:57 +0900
Von: Brian C. [email protected]
An: [email protected]
Betreff: Re: Help needed: Dynamically create a Proc from a String and
evaluate it

Dear Jason,

thank you for responding.
Here is what I have so far ( I hope the formatting won’t
be destroyed):

class String
def generate_formula
# left-hand side of equation gives the function
f=self.split(/=/)
formula=‘def ’ + f[0]
args=f[1].gsub(/[^±*/]+(/,’’).gsub(/)/,’’).split(/[/*-+]/).uniq
args_new=args.collect{|x| if x==x.capitalize ; x=’_’ + x; else x=x;
end}
rhs=f[1]
lhs=f[0]
args.each_with_index{|x,i|
if args_new[i]!=x
lhs.gsub!(x,args_new[i])
rhs.gsub!(x,args_new[i])
end
}
formula=‘def ’ + lhs + “\n”
#formula<<‘p ’ + lhs
#formula<<‘p ’ + rhs
formula<<"\n return Proc.new{|" + args_new.join(’,’) + ‘| ’
formula<< rhs + ’ }’
formula<<"\n end \n"
name=f[0][0…f[0].index(’(’)]
# return the following:
# 1) formula=String containing Proc method to be evaluated
# 2) name of the Proc method
# 3) Array of arguments ( variables and constants occurring
# in the original formula
# 4) arguments from 3) changed to non-uppercase, if needed
return formula,name,args,args_new
end
def eval_formula(hash)
f,name,vars,new_vars=self.generate_formula
# do this to change uppercase variables, if needed
hash2={}
hash.each{|k,v|
ind=vars.index(k)
if v.class!=Array
v=[v]
end
hash2.store(new_vars[ind],v)
}
# generate string for Proc to be evaluated
ind1=f.split(/\n/)[0].index(’(’)
ind2=f.split(/\n/)[0].index(’)’)
args_left=f.split(/\n/)[0][ind1+1…ind2]
other_args=new_vars-args_left.split(’,’)
eval_fn = name + ‘(args_left)’
max_nr_of_vals=[]
# how many evaluations ?
# to do: check that number of changed values
# is either 1 or coincides for all variables
hash2.values.each{|x| max_nr_of_vals<<x.length }
# to evaluate Proc (later), substitute constant values
ev_hash={}
for k in 0…max_nr_of_vals.max
ev_hash_text=eval_fn + ‘.call(’
for my_var in other_args
if hash2[my_var].length>1
this_val=hash2[my_var][k] # several values of “constants”
else
this_val=hash2[my_var][0] # just one value
end
ev_hash_text<<this_val.to_s + ‘,’
end
ev_hash_text.chop!
ev_hash_text<<’)’
repl=’’

  # substitute actual function values
  args_left.each{|y|
    for m  in hash2[y]
      repl<<m.to_s + ','
    end
  }


  ev_hash_text.sub!('args_left',repl.chop)
  # this is the call to the formula with substituted values
  p ev_hash_text
  eval(ev_hash_text)
end

end
end

a=‘f(x)=c*exp(x/k)’
b=a.generate_formula
a.eval_formula({‘c’,[5.0],‘k’,[2.0],‘x’,[1.0]})

Thank you,

Axel

Don’t you mean

g.call(1.0, 2, 5) ?

You have to do proc.call, they aren’t regular methods.

Jason

Dear Jason,

This: g.call(1.0, 2, 5) worked.
I made a mistake copying text from the Ruby Proc webpage.

Thank you both very much!

Best regards,

Axel

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs