Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

Ruby Programming Language

Help needed: Dynamically create a Proc from a String and evaluate it


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|   c*exp(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:in `call'
        from (eval):1:in `eval_formula'
        from t00.rb:64:in `eval'
        from t00.rb:102:in `eval_formula'
        from t00.rb:64:in `each'
        from t00.rb:64:in `eval_formula'
        from t00.rb:131

Is there a better way to do this ?

Thank you!

Best regards,

Axel
--
GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS.
Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail

On Tue, Jun 05, 2007 at 04:18:58AM +0900, Axel Etzold 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 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
--
Psssst! Schon vom neuen GMX MultiMessenger gehrt?
Der kanns mit allen: http://www.gmx.net/de/go/multimessenger

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:0x00002b56c768ef68@(eval):1>

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 Candler <B.Cand@pobox.com>
An: ruby-t@ruby-lang.org
Betreff: Re: Help needed: Dynamically create a Proc from a String and evaluate it

--
Psssst! Schon vom neuen GMX MultiMessenger gehrt?
Der kanns mit allen: http://www.gmx.net/de/go/multimessenger
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
--
Der GMX SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen!
Ideal fr Modem und ISDN: http://www.gmx.net/de/go/smartsurfer

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc