# FunctionAnalyzer Maplet # Copyright 2002 Douglas B. Meade # # The FunctionAnalyzer maplet provides a convenient user interface for the analysis necessary to prepare the graph of a function. Of course, the plot can be obtained with the Maplet, the purpose is to provide support for gathering the information needed to produce a sketch of the plot by hand. # # The user enters a function ( y# ) to be analyzed, the Maplet determines the first ( Dy# ) and second derivative ( D2y# ) of this function. Sign plots and ordinary plots for any combination of the function and its first two derivatives can be produced. User-specified expressions involving y# , Dy# , D2y# , and the independent variable can be evaluated or solved. # # To run this maplet, click the Execute (!!!) button in the context bar. # restart; # ############################################################ # # Supporting procedures for the Maplet # # ############################################################ FuncAnalEval := proc( EXPR, f, Df, D2f, t, T, cmd ) local str, val1, val2; try val1 := eval( EXPR, [ y=f, Dy=Df, D2y=D2f ] ); val2 := eval( val1, t = T ); if nargs>6 then if cmd="simplify" then val2 := simplify( val2 ) end if; if cmd="normal" then val2 := normal( val2 ) end if; if cmd="expand" then val2 := expand( val2 ) end if; if cmd="evalf" then val2 := evalf( val2 ) end if; end if; str := sprintf( "%a = %a, when %a = %a", EXPR, val2, t, T ); catch: str := "Error during evaluation, please check and retry."; end try; return str end proc: FuncAnalSolve := proc( EQN, f, Df, D2f, t, cmd ) local eqn, sol, str; try eqn := eval( EQN, [ y=f, Dy=Df, D2y=D2f ] ); sol := { solve( eqn, t ) }; if nargs>5 then if cmd="simplify" then sol := simplify( sol ) end if; if cmd="normal" then sol := normal( sol ) end if; if cmd="expand" then sol := expand( sol ) end if; if cmd="evalf" then sol := evalf( sol ) end if; end if; str := sprintf( "%a, for %a=%a", EQN, t, sol); catch: str := "Error during solve, please check and retry."; end try; return str end proc: SignPlot := proc( f, dom, desc, Y, C ) local neg_part, pos_part, P1, P2, x, xhi, xlo; pos_part := proc( f, y ) if nargs=1 then y := 1 end if; if type(f,numeric) then return `if`(signum(f)=1,y,undefined) else return 'procname'( 'args' ) end if end proc: neg_part := proc( f, y ) if nargs=1 then y := 1 end if; if type(f,numeric) then return `if`(signum(f)=-1,y,undefined) else return 'procname'( 'args' ) end if end proc: x, xlo, xhi := lhs(dom), op(evalf(rhs(dom))); P1 := plot( [pos_part(f,Y),neg_part(f,Y)], dom, color=C, thickness=3 ); P2 := plots[textplot]( [(xlo+39*xhi)/40, Y, desc], align=ABOVE ); return plots[display]( [P1, P2] ); end proc: FuncAnalPlot := proc( f, Df, D2f, t, T, Y, EXEC ) local p_list, c_list, s_list, ls_list, cmd, hi, lo, P_fns, P_Df_sign, P_D2f_sign; p_list := NULL; c_list := NULL; s_list := NULL; ls_list := NULL; if f[2] then p_list := p_list, f[1]; c_list := c_list, f[3]; if f[4]='POINT' then s_list := s_list, f[4]; ls_list := ls_list, 'SOLID'; else s_list := s_list, 'LINE'; ls_list := ls_list, f[4]; end if end if; if Df[2] then p_list := p_list, Df[1]; c_list := c_list, Df[3]; if Df[4]='POINT' then s_list := s_list, Df[4]; ls_list := ls_list, 'SOLID'; else s_list := s_list, 'LINE'; ls_list := ls_list, Df[4]; end if end if; if D2f[2] then p_list := p_list, D2f[1]; c_list := c_list, D2f[3]; if D2f[4]='POINT' then s_list := s_list, D2f[4]; ls_list := ls_list, 'SOLID'; else s_list := s_list, 'LINE'; ls_list := ls_list, D2f[4]; end if end if; try if p_list<>NULL then cmd := sprintf( "plot( %a, %a=%a, view=[%a,%a], color=%a, style=%a, linestyle=%a )", [p_list], t, T, T, Y, [c_list], [s_list], [ls_list] ); else cmd := sprintf( "plot( 'undefined', %a=%a, view=[%a,%a] )", t, T, T, Y ); end if; P_fns := parse( cmd, statement ); lo,hi := op(Y); P_Df_sign := NULL; P_D2f_sign := NULL; if Df[5] then P_Df_sign := SignPlot( Df[1], t=T, `y'`, lo+(hi-lo)/10, Df[6] ) end if; if D2f[5] then P_D2f_sign := SignPlot( D2f[1], t=T, `y''`, lo+(hi-lo)/20, D2f[6] ) end if; return plots[display]( [P_fns, P_Df_sign, P_D2f_sign] ) catch: return NULL end try; end proc: _COLORS := ['blue', 'cyan', 'brown', 'gold', 'green', 'khaki', 'magenta', 'maroon', 'orange', 'pink', 'plum', 'red', 'sienna', 'tan', 'turquoise', 'violet', 'wheat', 'yellow']: _STYLES := ['SOLID', 'POINT','DOT','DASH','DASHDOT']: # ############################################################ # # Definition of the Maplet # # ############################################################ use Maplets, Maplets:-Elements in FunctionAnalyzer := Maplet( ################ window layout ################ Window( 'title' = "Graphical Function Analysis", BoxRow( 'hscroll' = as_needed, 'vscroll' = as_needed, [ # c 1 - plot window and control [ # r 1 Plotter['PL1']( 'height' = 500, plot(undefined,x=-10..10,view=[-10..10,-10..10]) ) ], # r 1 [ # r 2 GridLayout( [ # c 1 [ # r 1 "Horizontal axis", TextField['X0']( 'value'=-10, 'width'=4 ), " <= ", TextField['X']( 'value'="x", 'width'=4, 'onchange'='new_indep_var' ), " <= ", TextField['X1']( 'value'=10, 'width'=4 ) ], # r 1 [ # r 2 "Vertical axis", TextField['Y0']( 'value'=-10, 'width'=4 ), " <= ", TextField['Y']( 'value'="y", 'width'=4 ), " <= ", TextField['Y1']( 'value'= 10, 'width'=4 ) ] # r 2 ] # c 1 ) ], # r 2 [ # r 3 - plot command BoxLayout( 'border'=true, 'caption'="Evaluate Expression", [ [ "Evaluate the expression (use y, Dy, D2y)", TextField['expr']( 'value'="", 'width'=15 ) ], [ "when the independendent variable (", TextField['X2']( 'value'="x = ", 'width'=3, 'editable'=false ), ") has the value", TextField['x_value']( 'value'="", 'width'=5 ) ], [ TextBox['result_eval']( 3..30, "", 'popupmenu' = 'PM_eval', 'editable' = false ) ], [ Button( "Evaluate expression at specified value", 'onclick'='eval_expr' ) ] ] ) ], # r 3 [ # r 4 Button( "Update plot", 'onclick' = Evaluate('PL1' = 'FuncAnalPlot( [y,y_plot,y_color,y_style], [Dy,Dy_plot,Dy_color,Dy_style,Dy_sign,[Dy_pos,Dy_neg]], [D2y,D2y_plot,D2y_color,D2y_style,D2y_sign,[D2y_pos,D2y_neg]], X, X0..X1, Y0..Y1, true )') ), Button( "Reset all fields", 'onclick' = 'reset' ), Button( "Close Window", Shutdown() ) ] # r 4 ], [ # c 2 - y, Dy, D2y [ # r 1 - function BoxLayout( 'border'=true, 'caption'="Function", [ [ "y = ", TextField['y']('value'='undefined', 'popupmenu'='PM_y', 'onchange'=Action(Evaluate( 'Dy' = 'diff( y,X)' ), Evaluate( 'D2y' = 'diff(Dy,X)' ) ), 'width'=30 ) ], [ CheckBox['y_plot']( 'value'=false, 'caption'="Include in plot" ), "Color:", ComboBox['y_color']( 'magenta', _COLORS ), "Style:", ComboBox['y_style']( 'SOLID', _STYLES ) ] ] ) ], # r 1 [ # r 2 - 1st derivative BoxLayout( 'border'=true, 'caption'="First Derivative", [ [ "y' = Dy =", TextField['Dy']( 'value'='undefined', 'popupmenu'='PM_Dy', 'onchange'=Action(Evaluate( 'y' = 'undefined' ), Evaluate( 'D2y'='diff(Dy,X)' ) ), 'width'=30 ) ], [ CheckBox['Dy_plot']( 'value'=false, 'caption'="Include in plot" ), "Color:", ComboBox['Dy_color']( 'gold', _COLORS ), "Style:", ComboBox['Dy_style']( 'SOLID', _STYLES ) ], [ CheckBox['Dy_sign']( 'value'=false, 'caption'="Show sign chart" ), "Colors: increasing:", ComboBox['Dy_pos']( 'red', _COLORS ), "decreasing:", ComboBox['Dy_neg']( 'blue', _COLORS ) ] ] ) ], # r 2 [ # r 3 - 2nd derivative BoxLayout( 'border'=true, 'caption'="Second Derivative", [ [ "y'' = D2y =", TextField['D2y']( 'value'='undefined', 'popupmenu'='PM_D2y', 'width'=30 ) ], [ CheckBox['D2y_plot']( 'value'=false, 'caption'="Include in plot" ), "Color:", ComboBox['D2y_color']( 'cyan', _COLORS ), "Style:", ComboBox['D2y_style']( 'SOLID', _STYLES ) ], [ CheckBox['D2y_sign']( 'value'=false, 'caption'="Show sign chart" ), "Colors: concave up:", ComboBox['D2y_pos']( 'green', _COLORS ), "concave down:", ComboBox['D2y_neg']( 'orange', _COLORS ) ] ] ) ], # r 3 [ # r 4 - evaluate or solve BoxLayout( 'border'=true, 'caption'="Solve an Equation or Inequality", [ [ "Enter equation to be solved (use y, Dy, D2y):", TextField['eqn']( 'value'="", 'width'=20 ) ], [ TextBox['result_solve']( 3..30, "", 'popupmenu' = 'PM_solve', 'editable'=false )#, 'quotedtext' = true ) ], [ Button( "Attempt to solve equation", 'onclick'='solve_eqn' ) ] ] ) ] # r 4 ] ) ), # end Window ################ action definitions ################ Action['reset']( SetOption( 'X0' =-10 ), SetOption( 'X1' = 10 ), SetOption( 'Y0' =-10 ), SetOption( 'Y1' = 10 ), SetOption( 'Y' = "y" ), SetOption( 'y' = 'undefined' ), SetOption( 'Dy' = 'undefined' ), SetOption( 'D2y' = 'undefined' ), SetOption( 'y_plot' = false ), SetOption( 'Dy_plot' = false ), SetOption( 'D2y_plot' = false ), SetOption( 'y_color' = "magenta" ), SetOption( 'Dy_color' = "gold" ), SetOption( 'D2y_color' = "cyan" ), SetOption( 'y_style' = "SOLID" ), SetOption( 'Dy_style' = "SOLID" ), SetOption( 'D2y_style' = "SOLID" ), SetOption( 'Dy_sign' = false ), SetOption( 'D2y_sign' = false ), SetOption( 'Dy_neg' = blue ), SetOption( 'D2y_neg' = orange ), SetOption( 'Dy_pos' = red ), SetOption( 'D2y_pos' = green ), SetOption( 'result_eval' = " " ), SetOption( 'expr' = "" ), SetOption( 'x_value' = "" ), SetOption( 'eqn' = "" ), SetOption( 'result_solve' = "" ), SetOption( 'X' = "x" ), SetOption( 'X2' = "x = " ), NULL ), Action['show_cmd']( Evaluate( 'plot_cmds' = 'FuncAnalPlot( [y,y_plot,y_color,y_style], [Dy,Dy_plot,Dy_color,Dy_style,Dy_sign, [Dy_pos,Dy_neg]], [D2y,D2y_plot,D2y_color,D2y_style,D2y_sign, [D2y_pos,D2y_neg]], X, X0..X1, Y0..Y1, false )' ) ), Action['eval_expr']( Evaluate('result_eval'='FuncAnalEval( expr, y, Dy, D2y, X, x_value )') ), Action['solve_eqn']( Evaluate('result_solve'='FuncAnalSolve( eqn, y, Dy, D2y, X )') ), Action['new_indep_var']( Evaluate('X2'='sprintf("%s =",X)'), Evaluate('Dy' = 'diff(y,X)' ), Evaluate('D2y' = 'diff(y,X$2)' ) ), ################ popup menu definitions ################ PopupMenu['PM_y']( Menu("Manipulate", MenuItem("simplify", Evaluate('y'='simplify(y)')), MenuItem("normal", Evaluate('y'='normal(y)')), MenuItem("expand", Evaluate('y'='expand(y)')), MenuItem("convert to floating-point", Evaluate('y'='map(evalf,y)')), NULL ), MenuSeparator(), MenuItem("Clear Field", SetOption('y'="")) ), PopupMenu['PM_Dy']( Menu("Manipulate", MenuItem("simplify", Evaluate('Dy'='simplify(Dy)')), MenuItem("normal", Evaluate('Dy'='normal(Dy)')), MenuItem("expand", Evaluate('Dy'='expand(Dy)')), MenuItem("convert to floating-point", Evaluate('Dy'='map(evalf,Dy)')), NULL ), MenuSeparator(), MenuItem("Clear Field", SetOption('Dy'="")) ), PopupMenu['PM_D2y']( Menu("Manipulate", MenuItem("simplify", Evaluate('D2y'='simplify(D2y)')), MenuItem("normal", Evaluate('D2y'='normal(D2y)')), MenuItem("expand", Evaluate('D2y'='expand(D2y)')), MenuItem("convert to floating-point", Evaluate('D2y'='map(evalf,D2y)')), NULL ), MenuSeparator(), MenuItem("Clear Field", SetOption('D2y'="")) ), PopupMenu['PM_eval']( Menu("Manipulate Results", MenuItem("simplify", Evaluate( 'result_eval' = 'FuncAnalEval( expr, y, Dy, D2y, X, x_value, "simplify" )' )), MenuItem("normal", Evaluate( 'result_eval' = 'FuncAnalEval( expr, y, Dy, D2y, X, x_value, "normal" )' )), MenuItem("expand", Evaluate( 'result_eval' = 'FuncAnalEval( expr, y, Dy, D2y, X, x_value, "expand" )' )), MenuItem("evalf", Evaluate( 'result_eval' = 'FuncAnalEval( expr, y, Dy, D2y, X, x_value, "evalf" )' )) ), MenuSeparator(), MenuItem("Clear Field", SetOption( 'result_eval' = "" )) ), PopupMenu['PM_solve']( Menu("Manipulate Results", MenuItem("simplify", Evaluate( 'result_solve' = 'FuncAnalSolve( eqn, y, Dy, D2y, X, "simplify" )' )), MenuItem("normal", Evaluate( 'result_solve' = 'FuncAnalSolve( eqn, y, Dy, D2y, X, "normal" )' )), MenuItem("expand", Evaluate( 'result_solve' = 'FuncAnalSolve( eqn, y, Dy, D2y, X, "expand" )' )), MenuItem("evalf", Evaluate( 'result_solve' = 'FuncAnalSolve( eqn, y, Dy, D2y, X, "evalf" )' )) ), MenuSeparator(), MenuItem("Clear Field", SetOption( 'result_solve' = "" )) ) ): end use: # ############################################################ # # Launch the Maplet # # ############################################################ Maplets:-Display(FunctionAnalyzer);