class Keisan::Functions::Diff
Public Class Methods
new()
click to toggle source
Calls superclass method
Keisan::Function::new
# File lib/keisan/functions/diff.rb, line 4 def initialize super("diff", -1) @name = "diff" end
Public Instance Methods
evaluate(ast_function, context = nil)
click to toggle source
# File lib/keisan/functions/diff.rb, line 21 def evaluate(ast_function, context = nil) validate_arguments!(ast_function.children.count) context ||= Context.new function, variables = function_and_variables(ast_function) local = context_from(variables, context) result = variables.inject(function.evaluate(local)) do |result, variable| result = differentiate(result, variable, local) if !is_ast_derivative?(result) result = result.evaluate(local) end result end case result when AST::Function result.name == "diff" ? result : result.simplify(context) else result.simplify(context) end end
simplify(ast_function, context = nil)
click to toggle source
# File lib/keisan/functions/diff.rb, line 43 def simplify(ast_function, context = nil) validate_arguments!(ast_function.children.count) raise Exceptions::InternalError.new("received non-diff function") unless ast_function.name == "diff" function, variables = function_and_variables(ast_function) context ||= Context.new local = context_from(variables, context) result = variables.inject(function.simplify(local)) do |result, variable| result = differentiate(result, variable, local) if !is_ast_derivative?(result) result = result.simplify(local) end result end case result when AST::Function result.name == "diff" ? result : result.simplify(context) else result.simplify(context) end end
value(ast_function, context = nil)
click to toggle source
# File lib/keisan/functions/diff.rb, line 9 def value(ast_function, context = nil) validate_arguments!(ast_function.children.count) context ||= Context.new evaluation = evaluate(ast_function, context) if is_ast_derivative?(evaluation) raise Exceptions::NonDifferentiableError.new else evaluation.value(context) end end
Private Instance Methods
context_from(variables, context = nil)
click to toggle source
# File lib/keisan/functions/diff.rb, line 102 def context_from(variables, context = nil) context ||= Context.new(shadowed: variables.map(&:name)) context.spawn_child(shadowed: variables.map(&:name)) end
differentiate(node, variable, context)
click to toggle source
# File lib/keisan/functions/diff.rb, line 72 def differentiate(node, variable, context) if node.unbound_variables(context).include?(variable.name) node.differentiate(variable, context) else return AST::Number.new(0) end rescue Exceptions::NonDifferentiableError => e return AST::Function.new( [node, variable], "diff" ) end
function_and_variables(ast_function)
click to toggle source
# File lib/keisan/functions/diff.rb, line 85 def function_and_variables(ast_function) unless ast_function.is_a?(AST::Function) && ast_function.name == name raise Exceptions::InvalidFunctionError.new("Must receive diff function") end variables = ast_function.children[1..-1] unless variables.all? {|var| var.is_a?(AST::Variable)} raise Exceptions::InvalidFunctionError.new("Diff must differentiate with respect to variables") end [ ast_function.children.first, variables ] end
is_ast_derivative?(node)
click to toggle source
# File lib/keisan/functions/diff.rb, line 68 def is_ast_derivative?(node) node.is_a?(AST::Function) && node.name == name end