#!/usr/bin/ruby -w # Symbolic differentiation example in Ruby # without any simplification... class Expr def initialize(a,op,b) @arg1 = a; @op = op; @arg2 = b end def to_s; "(#@arg1 #@op #@arg2)" end def +(arg2) Expr.new(self,:+,arg2) end def -(arg2) Expr.new(self,:-,arg2) end def *(arg2) Expr.new(self,:*,arg2) end def sym_diff(var) case @op when :+ then @arg1.sym_diff(var) + @arg2.sym_diff(var) when :- then @arg1.sym_diff(var) - @arg2.sym_diff(var) when :* then @arg1.sym_diff(var) * @arg2 + @arg1 * @arg2.sym_diff(var) end end def to_proc f = @arg1.to_proc g = @arg2.to_proc lambda {|x| f.call(x).send(@op,g.call(x))} end end Zero = Expr.new(0,:+,0) One = Expr.new(1,:+,0) class Numeric def sym_diff(var) Zero end def to_proc; lambda {|n| self} end end class Symbol def sym_diff(var) self === var ? One : Zero end def +(arg2) Expr.new(self,:+,arg2) end def -(arg2) Expr.new(self,:-,arg2) end def *(arg2) Expr.new(self,:*,arg2) end def to_proc; lambda {|n| n} end def coerce(other) if Numeric === other [Expr.new(other,:+,0),self] else [other,self] end end end # Create a regular Ruby function... # f(x) = x^2 + 12x - 7 f = lambda {|x| x*x + 12*x - 7} # Print the symbolic form puts f.call(:x) # Print the numeric value at f(10) puts f.call(10) # Symbolically differentiate puts f.call(:x).sym_diff(:x) # Value of f'(10) puts f.call(:x).sym_diff(:x).to_proc.call(10)