# HG changeset patch # User Harald Schilly # Date 1280358068 -7200 # Node ID 12c5ece399703e70d63205c71a66ff1d9f735cfb # Parent cb1ad1ee5bd452850fde04d47f9618dec4c3e997 #9623 interacts for high school level education by Lauri Ruotsalainen adopted for the sage library diff --git a/sage/interacts/__init__.py b/sage/interacts/__init__.py --- a/sage/interacts/__init__.py +++ b/sage/interacts/__init__.py @@ -2,4 +2,5 @@ Interacts included with sage """ import calculus -import library +import geometry +import statistics diff --git a/sage/interacts/calculus.py b/sage/interacts/calculus.py --- a/sage/interacts/calculus.py +++ b/sage/interacts/calculus.py @@ -1,1 +1,17 @@ -from library import taylor_polynomial +""" +Interacts for Calculus + +""" + + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from library import taylor_polynomial, definite_integral +from library import function_derivative, difference_quotient, quadratic_equation +from library import practice_differentiating_polynomials, trigonometric_properties_triangle +from library import secant_method, newton_method, trapezoid_integration, simpson_integration diff --git a/sage/interacts/geometry.py b/sage/interacts/geometry.py new file mode 100644 --- /dev/null +++ b/sage/interacts/geometry.py @@ -0,0 +1,15 @@ +""" +Interacts for Geometry + +""" + + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from library import unit_circle, cube_hemisphere +from library import trigonometric_properties_triangle, special_points diff --git a/sage/interacts/library.py b/sage/interacts/library.py --- a/sage/interacts/library.py +++ b/sage/interacts/library.py @@ -2,9 +2,19 @@ A library of interacts """ -from sagenb.notebook.interact import interact, slider, range_slider, input_box -from sage.all import sin, plot, point, html, show, latex, SR,exp -x=SR.var('x') + +#***************************************************************************** +# Copyright (C) 2009 William Stein +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sagenb.notebook.interact import interact, slider, range_slider, input_box, selector, checkbox +from sage.all import sin, cos, asin, acos, tan, sqrt, SR, exp, symbolic_expression, N, derivative, pi +from sage.all import point, line2d, text, Graphics, plot, point, html, show, latex, circle, line, parametric_plot +from sage.all import implicit_plot3d, plot3d, cube, integral_numerical from sage.misc.misc import sage_wraps from sage.misc.html import html @@ -47,8 +57,7 @@ """ print n+m - - +x=SR.var('x') @library_interact def taylor_polynomial(f=input_box(sin(x)*exp(-x)), order=slider(range(1,13))): """ @@ -71,3 +80,910 @@ html('$f(x)\;=\;%s$'%latex(f)) html('$\hat{f}(x;%s)\;=\;%s+\mathcal{O}(x^{%s})$'%(x0,latex(ft),order+1)) show(dot + p + pt, ymin = -.5, ymax = 1) + +@library_interact +def definite_integral( + f = input_box(default = "3*x", label = 'f(x)'), + g = input_box(default = "x^2", label = 'g(x)'), + interval = range_slider(-10,10,default=(0,3), label="Interval"), + x_range = range_slider(-10,10,default=(0,3), label = "plot range (x)"), + selection = selector(["f", "g", "f and g", "f - g"], default="f and g", label="Select")): + """ + This is a demo interact for plotting the definite intergral of a function + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `function` -- input box, function in x + - `interval` -- interval for the definite integral + - `x_range` -- range slider for plotting range + - `selection` -- selector on how to visualize the integrals + + EXAMPLES:: + + sage: interacts.calculus.definite_integral() + ... + """ + x = SR.var('x') + f = symbolic_expression(f).function(x) + g = symbolic_expression(g).function(x) + f_plot = Graphics(); g_plot = Graphics(); h_plot = Graphics(); + text = "" + + # Plot function f. + if selection != "g": + f_plot = plot(f(x), x, x_range, color="blue", thickness=1.5) + + # Color and calculate the area between f and the horizontal axis. + if selection == "f" or selection == "f and g": + f_plot += plot(f(x), x, interval, color="blue", fill=True, fillcolor="blue", fillalpha=0.15) + text += r"$\int_{%.2f}^{%.2f}(\color{Blue}{f(x)})\,dx=\int_{%.2f}^{%.2f}(%s)\,dx=%.2f$" % ( + interval[0], interval[1], + interval[0], interval[1], + latex(f(x)), + f(x).nintegrate(x, interval[0], interval[1])[0] + ) + + if selection == "f and g": + text += r"
" + + # Plot function g. Also color and calculate the area between g and the horizontal axis. + if selection == "g" or selection == "f and g": + g_plot = plot(g(x), x, x_range, color="green", thickness=1.5) + g_plot += plot(g(x), x, interval, color="green", fill=True, fillcolor="yellow", fillalpha=0.5) + text += r"$\int_{%.2f}^{%.2f}(\color{Green}{g(x)})\,dx=\int_{%.2f}^{%.2f}(%s)\,dx=%.2f$" % ( + interval[0], interval[1], + interval[0], interval[1], + latex(g(x)), + g(x).nintegrate(x, interval[0], interval[1])[0] + ) + + # Plot function f-g. Also color and calculate the area between f-g and the horizontal axis. + if selection == "f - g": + g_plot = plot(g(x), x, x_range, color="green", thickness=1.5) + g_plot += plot(g(x), x, interval, color="green", fill=f(x), fillcolor="red", fillalpha=0.15) + h_plot = plot(f(x)-g(x), x, interval, color="red", thickness=1.5, fill=True, fillcolor="red", fillalpha=0.15) + text = r"$\int_{%.2f}^{%.2f}(\color{Red}{f(x)-g(x)})\,dx=\int_{%.2f}^{%.2f}(%s)\,dx=%.2f$" % ( + interval[0], interval[1], + interval[0], interval[1], + latex(f(x)-g(x)), + (f(x)-g(x)).nintegrate(x, interval[0], interval[1])[0] + ) + + show(f_plot + g_plot + h_plot, gridlines=True) + html(text) + +@library_interact +def function_derivative( + function = input_box(default="x^5-3*x^3+1", label="Function:"), + x_range = range_slider(-15,15,0.1, default=(-2,2), label="Range (x)"), + y_range = range_slider(-15,15,0.1, default=(-8,6), label="Range (y)")): + """ + This is a demo interact for plotting derivatives of a function based on work by + Lauri Ruotsalainen, 2010. + + INPUT: + + - `function` -- input box, function in x + - `x_range` -- range slider for plotting range + - `y_range` -- range slider for plotting range + + EXAMPLES:: + + sage: interacts.calculus.function_derivative() + ... + """ + x = SR.var('x') + f = symbolic_expression(function).function(x) + df = derivative(f, x) + ddf = derivative(df, x) + plots = plot(f(x), x_range, thickness=1.5) + plot(df(x), x_range, color="green") + plot(ddf(x), x_range, color="red") + if y_range == (0,0): + show(plots, xmin=x_range[0], xmax=x_range[1]) + else: + show(plots, xmin=x_range[0], xmax=x_range[1], ymin=y_range[0], ymax=y_range[1]) + + html("
$\color{Blue}{f(x) = %s}$
"%latex(f(x))) + html("
$\color{Green}{f'(x) = %s}$
"%latex(df(x))) + html("
$\color{Red}{f''(x) = %s}$
"%latex(ddf(x))) + +@library_interact +def difference_quotient( + f = input_box(default="sin(x)", label='f(x)'), + interval= range_slider(0, 10, 0.1, default=(0.0,10.0), label="Range"), + a = slider(0, 10, None, 5.5, label = 'a'), + x0 = slider(0, 10, None, 2.5), label = 'start point'): + """ + This is a demo interact for difference quotient based on work by + Lauri Ruotsalainen, 2010. + + INPUT: + + - `f` -- input box, function in x + - `interval` -- range slider for plotting + - `a` -- slider for a + - `x0` -- slider for x0 + + EXAMPLES:: + + sage: interacts.calculus.difference_quotient() + ... + """ + html('

Difference Quotient

') + html('' + ) + + x = SR.var('x') + f = symbolic_expression(f).function(x) + fmax = f.find_maximum_on_interval(interval[0], interval[1])[0] + fmin = f.find_minimum_on_interval(interval[0], interval[1])[0] + f_height = fmax - fmin + measure_y = fmin - 0.1*f_height + + measure_0 = line2d([(x0, measure_y), (a, measure_y)], rgbcolor="black") + measure_1 = line2d([(x0, measure_y + 0.02*f_height), (x0, measure_y-0.02*f_height)], rgbcolor="black") + measure_2 = line2d([(a, measure_y + 0.02*f_height), (a, measure_y-0.02*f_height)], rgbcolor="black") + text_x0 = text("x0", (x0, measure_y - 0.05*f_height), rgbcolor="black") + text_a = text("a", (a, measure_y - 0.05*f_height), rgbcolor="black") + measure = measure_0 + measure_1 + measure_2 + text_x0 + text_a + + tanf = symbolic_expression((f(x0)-f(a))*(x-a)/(x0-a)+f(a)).function(x) + + fplot = plot(f(x), x, interval[0], interval[1]) + tanplot = plot(tanf(x), x, interval[0], interval[1], rgbcolor="#FF0000") + points = point([(x0, f(x0)), (a, f(a))], pointsize=20, rgbcolor="#005500") + dashline = line2d([(x0, f(x0)), (x0, f(a)), (a, f(a))], rgbcolor="#005500", linestyle="--") + html('

Difference Quotient

') + show(fplot + tanplot + points + dashline + measure, xmin=interval[0], xmax=interval[1], ymin=fmin-0.2*f_height, ymax=fmax) + html(r"
$\text{Line's equation:}$") + html(r"$y = %s$
"%tanf(x)) + html(r"$\text{Slope:}$") + html(r"$k = \frac{f(x0)-f(a)}{x0-a} = %s$
" % (N(derivative(tanf(x), x), digits=5))) + +@library_interact +def quadratic_equation(A = slider(-7, 7, 1, 1), B = slider(-7, 7, 1, 1), C = slider(-7, 7, 1, -2)): + """ + This is a demo interact for solving quadratic equations based on work by + Lauri Ruotsalainen, 2010. + + INPUT: + + - `A` -- integer slider + - `B` -- integer slider + - `C` -- integer slider + + EXAMPLES:: + + sage: interacts.calculus.quadratic_equation() + ... + """ + x = SR.var('x') + f = symbolic_expression(A*x**2 + B*x + C).function(x) + html('

The Solutions of the Quadratic Equation

') + html("$%s = 0$" % f(x)) + + show(plot(f(x), x, (-10, 10), ymin=-10, ymax=10), aspect_ratio=1, figsize=4) + + d = B**2 - 4*A*C + + if d < 0: + color = "Red" + sol = r"\text{solution} \in \mathbb{C}" + elif d == 0: + color = "Blue" + sol = -B/(2*A) + else: + color = "Green" + a = (-B+sqrt(B**2-4*A*C))/(2*A) + b = (-B-sqrt(B**2-4*A*C))/(2*A) + sol = r"\begin{cases}%s\\%s\end{cases}" % (latex(a), latex(b)) + + if B < 0: + dis1 = "(%s)^2-4*%s*%s" % (B, A, C) + else: + dis1 = "%s^2-4*%s*%s" % (B, A, C) + dis2 = r"\color{%s}{%s}" % (color, d) + + html("$Ax^2 + Bx + C = 0$") + calc = r"$x = \frac{-B\pm\sqrt{B^2-4AC}}{2A} = " + \ + r"\frac{-%s\pm\sqrt{%s}}{2*%s} = " + \ + r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" + html(calc % (B, dis1, A, B, dis2, (2*A), sol)) + +#R. = ZZ[] +new_ex_state = True +prac_function = None + +@library_interact +def practice_differentiating_polynomials( + answer = input_box(label="Answer"), + new_exercise = checkbox(default=False, label="New exercise"), + show_solution = checkbox(default=False, label="Show solution")): + """ + This is an interact for practicing differentiating random polynomials + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `answer` -- enter your answer here + - `new_exercise` -- generate a new exercise + - `show_solution` -- show the solution + + EXAMPLES:: + + sage: interacts.calculus.practice_differentiating_polynomials() + ... + """ + import sage + from sage.interacts.library import prac_function, new_ex_state + from sage.all import ZZ + R = ZZ['x']; (x,) = R._first_ngens(1) + if prac_function is None: + prac_function = R.random_element(3, -10,10) + sage.interacts.library.prac_function = prac_function + + if answer == derivative(prac_function(x)) or new_exercise == new_ex_state: + new_ex_state = not new_exercise + sage.interacts.library.new_ex_state = new_ex_state + prac_function = R.random_element(3, -10,10) + sage.interacts.library.prac_function = prac_function + + if answer == derivative(prac_function(x)): + html(r"$\text{Very good! New exercise:}$") + prac_function = R.random_element(3, -10,10) + sage.interacts.library.prac_function = prac_function + + elif answer and show_solution is False and new_exercise != new_ex_state: + html(r"$\text{You've made an error. Try again!}$") + + html(r"$\text{Calculate the derivative: }\;\;\;\;%s$
"%latex(prac_function(x))) + + if show_solution: + html(r"$\text{Solution: }\;\;\;\;%s$
"%latex(derivative(prac_function(x)))) + + +@library_interact +def trigonometric_properties_triangle( + a0 = slider(0, 360, 1, 30, label="A"), + a1 = slider(0, 360, 1, 180, label="B"), + a2 = slider(0, 360, 1, 300, label="C")): + """ + This is an interact for demonstrating trigonometric properties + in a triangle based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `a0` -- angle + - `a1` -- angle + - `a2` -- angle + + EXAMPLES:: + + sage: interacts.geometry.trigonometric_properties_triangle() + ... + """ + import math + + # Returns the distance between points (x1,y1) and (x2,y2) + def distance((x1, y1), (x2, y2)): + return sqrt((x2-x1)**2 + (y2-y1)**2) + + # Returns an angle (in radians) when sides a and b + # are adjacent and the side c is opposite to the angle + def angle(a, b, c): + a,b,c = map(float,[a,b,c]) + return acos((b**2 + c**2 - a**2)/(2.0*b*c)) + + # Returns the area of a triangle when an angle alpha + # and adjacent sides a and b are known + def area(alpha, a, b): + return 1.0/2.0*a*b*sin(alpha) + + xy = [0]*3 + html('

Trigonometric Properties of a Triangle

') + # Coordinates of the angles + a = map(lambda x : math.radians(float(x)), [a0, a1, a2]) + for i in range(3): + xy[i] = (cos(a[i]), sin(a[i])) + + # Side lengths (bc, ca, ab) corresponding to triangle vertices (a, b, c) + al = [distance(xy[1], xy[2]), distance(xy[2], xy[0]), distance(xy[0], xy[1])] + + # The angles (a, b, c) in radians + ak = [angle(al[0], al[1], al[2]), angle(al[1], al[2], al[0]), angle(al[2], al[0], al[1])] + + # The area of the triangle + A = area(ak[0], al[1], al[2]) + + unit_circle = circle((0, 0), 1, aspect_ratio=1) + + # Triangle + triangle = line([xy[0], xy[1], xy[2], xy[0]], rgbcolor="black") + triangle_points = point(xy, pointsize=30) + + # Labels of the angles drawn in a distance from points + a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) + b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) + c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) + labels = a_label + b_label + c_label + + show(unit_circle + triangle + triangle_points + labels, figsize=[5, 5], xmin=-1, xmax=1, ymin=-1, ymax=1) + angl_txt = r"$< A = {%s}^{\circ},$ $< B = {%s}^{\circ},$ $< C = {%s}^{\circ}$" % ( + math.degrees(ak[0]), + math.degrees(ak[1]), + math.degrees(ak[2]) + ) + html(angl_txt) + html(r"$AB = %s,$ $BC = %s,$ $CA = %s$"%(al[2], al[0], al[1])) + html(r"$\text{Area A} = %s$"%A) + +@library_interact +def unit_circle( + function = selector([(0, sin(x)), (1, cos(x)), (2, tan(x))]), + x = slider(0,2*pi, 0.005*pi, 0)): + """ + This is an interact for Sin, Cos and Tan in the Unit Circle + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `function` -- select Sin, Cos or Tan + - `x` -- slider to select angle in unit circle + + EXAMPLES:: + + sage: interacts.geometry.unit_circle() + ... + """ + xy = (cos(x), sin(x)) + t = SR.var('t') + html('
Lines of the same color have\ + the same length
') + + # Unit Circle + C = circle((0, 0), 1, figsize=[5, 5], aspect_ratio=1) + C_line = line([(0, 0), (xy[0], xy[1])], rgbcolor="black") + C_point = point((xy[0], xy[1]), pointsize=40, rgbcolor="green") + C_inner = parametric_plot((cos(t), sin(t)), (t, 0, x + 0.001), color="green", thickness=3) + C_outer = parametric_plot((0.1 * cos(t), 0.1 * sin(t)), (t, 0, x + 0.001), color="black") + C_graph = C + C_line + C_point + C_inner + C_outer + + # Graphics related to the graph of the function + G_line = line([(0, 0), (x, 0)], rgbcolor="green", thickness=3) + G_point = point((x, 0), pointsize=30, rgbcolor="green") + G_graph = G_line + G_point + + # Sine + if function == 0: + Gf = plot(sin(t), t, 0, 2*pi, axes_labels=("x", "sin(x)")) + Gf_point = point((x, sin(x)), pointsize=30, rgbcolor="red") + Gf_line = line([(x, 0),(x, sin(x))], rgbcolor="red") + Cf_point = point((0, xy[1]), pointsize=40, rgbcolor="red") + Cf_line1 = line([(0, 0), (0, xy[1])], rgbcolor="red", thickness=3) + Cf_line2 = line([(0, xy[1]), (xy[0], xy[1])], rgbcolor="purple", linestyle="--") + # Cosine + elif function == 1: + Gf = plot(cos(t), t, 0, 2*pi, axes_labels=("x", "cos(x)")) + Gf_point = point((x, cos(x)), pointsize=30, rgbcolor="red") + Gf_line = line([(x, 0), (x, cos(x))], rgbcolor="red") + Cf_point = point((xy[0], 0), pointsize=40, rgbcolor="red") + Cf_line1 = line([(0, 0), (xy[0], 0)], rgbcolor="red", thickness=3) + Cf_line2 = line([(xy[0], 0), (xy[0], xy[1])], rgbcolor="purple", linestyle="--") + # Tangent + else: + Gf = plot(tan(t), t, 0, 2*pi, ymin=-8, ymax=8, axes_labels=("x", "tan(x)")) + Gf_point = point((x, tan(x)), pointsize=30, rgbcolor="red") + Gf_line = line([(x, 0), (x, tan(x))], rgbcolor="red") + Cf_point = point((1, tan(x)), pointsize=40, rgbcolor="red") + Cf_line1 = line([(1, 0), (1, tan(x))], rgbcolor="red", thickness=3) + Cf_line2 = line([(xy[0], xy[1]), (1, tan(x))], rgbcolor="purple", linestyle="--") + + C_graph += Cf_point + Cf_line1 + Cf_line2 + G_graph += Gf + Gf_point + Gf_line + + html.table([[r"$\text{Unit Circle}$",r"$\text{Function}$"], [C_graph, G_graph]], header=True) + +@library_interact +def cube_hemisphere(size = slider(0.5, 1, label="The Edge Length x:")): + """ + This interact demo shows a cube within a hemisphere + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `size` -- slider to select the edge length x + + EXAMPLES:: + + sage: interacts.geometry.cube_hemisphere() + ... + """ + html('

Cube within a Hemisphere

') + html('
A cube is placed within a hemisphere so that the corners ' +\ + 'of the cube touch the surface of the hemisphere; Observe numerically' + \ + 'the ratio of the volume of the cube and the volume of the hemisphere.
') + x, y, z = SR.var("x,y,z") + hemisphere_graph = implicit_plot3d(x**2+y**2+z**2==1, (x, -1, 1), (y, -1, 1), (z, 0, 1), color="green", opacity=0.4) + cube_graph = cube(size=size, opacity=0.9, color="red", frame_thickness=1).translate((0, 0, size/2.0)) + surface_graph = plot3d(0, (x, -1.2, 1.2),(y, -1.2, 1.2), color="lightblue", opacity=0.6) + show(hemisphere_graph + cube_graph + surface_graph, aspect_ratio=1) + + V_c = size**3 + V_hs = 4*pi*1**3/6.0 + html(r"$\text{Volume of the Cube: }V_{cube} = x^3 = {%.5f}^3 = %s" % (N(size, digits=5), N(V_c, digits=5))) + html(r"$\text{Volume of the Hemisphere: }V_{hemisphere} = \frac{4\pi r^3}{3}:2 = \frac{4\pi 1^3}{3}:2 = %.5f$" % N(V_hs, digits=5)) + html(r"$\text{Ratio: }V_{cube}/V_{hemisphere} = %.5f/%.5f = %.5f$" % (N(V_c, digits=5), N(V_hs, digits=5), N(V_c/V_hs, digits=5))) + + +@library_interact +def special_points( + a0 = slider(0, 360, 1, 30, label="A"), + a1 = slider(0, 360, 1, 180, label="B"), + a2 = slider(0, 360, 1, 300, label="C"), + show_median = checkbox(False, label="Medians"), + show_pb = checkbox(False, label="Perpendicular Bisectors"), + show_alt = checkbox(False, label="Altitudes"), + show_ab = checkbox(False, label="Angle Bisectors"), + show_incircle = checkbox(False, label="Incircle"), + show_euler = checkbox(False, label="Euler's Line")): + """ + This interact demo shows special points in a triangle + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `a0` -- angle + - `a1` -- angle + - `a2` -- angle + - `show_median` -- checkbox + - `show_pb` -- checkbox to show perpendicular bisectors + - `show_alt` -- checkbox to show altitudes + - `show_ab` -- checkbox to show angle bisectors + - `show_incircle` -- checkbox to show incircle + - `show_euler` -- checkbox to show euler's line + + EXAMPLES:: + + sage: interacts.geometry.special_points() + ... + """ + import math + # Return the intersection point of the bisector of the angle <(A[a],A[c],A[b]) and the unit circle. Angles given in radians. + def half(A, a, b, c): + if (A[a] < A[b] and (A[c] < A[a] or A[c] > A[b])) or (A[a] > A[b] and (A[c] > A[a] or A[c] < A[b])): + p = A[a] + (A[b] - A[a]) / 2.0 + else: + p = A[b] + (2*pi - (A[b]-A[a])) / 2.0 + return (math.cos(p), math.sin(p)) + + # Returns the distance between points (x1,y1) and (x2,y2) + def distance((x1, y1), (x2, y2)): + return math.sqrt((x2-x1)**2 + (y2-y1)**2) + + # Returns the line (graph) going through points (x1,y1) and (x2,y2) + def line_to_points((x1, y1), (x2, y2), **plot_kwargs): + return plot((y2-y1) / (x2-x1) * (x-x1) + y1, (x,-3,3), **plot_kwargs) + + # Coordinates of the angles + a = map(lambda x : math.radians(float(x)), [a0, a1, a2]) + xy = [(math.cos(a[i]), math.sin(a[i])) for i in range(3)] + + # Labels of the angles drawn in a distance from points + a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) + b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) + c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) + labels = a_label + b_label + c_label + + C = circle((0, 0), 1, aspect_ratio=1) + + # Triangle + triangle = line([xy[0], xy[1], xy[2], xy[0]], rgbcolor="black") + triangle_points = point(xy, pointsize=30) + + # Side lengths (bc, ca, ab) corresponding to triangle vertices (a, b, c) + ad = [distance(xy[1], xy[2]), distance(xy[2], xy[0]), distance(xy[0], xy[1])] + + # Midpoints of edges (bc, ca, ab) + a_middle = [ + ((xy[1][0] + xy[2][0])/2.0, (xy[1][1] + xy[2][1])/2.0), + ((xy[2][0] + xy[0][0])/2.0, (xy[2][1] + xy[0][1])/2.0), + ((xy[0][0] + xy[1][0])/2.0, (xy[0][1] + xy[1][1])/2.0) + ] + + # Incircle + perimeter = float(ad[0] + ad[1] + ad[2]) + incircle_center = ( + (ad[0]*xy[0][0] + ad[1]*xy[1][0] + ad[2]*xy[2][0]) / perimeter, + (ad[0]*xy[0][1] + ad[1]*xy[1][1] + ad[2]*xy[2][1]) / perimeter + ) + + if show_incircle: + s = perimeter/2.0 + incircle_r = math.sqrt((s - ad[0]) * (s - ad[1]) * (s - ad[2]) / s) + incircle_graph = circle(incircle_center, incircle_r) + point(incircle_center) + else: + incircle_graph = Graphics() + + # Angle Bisectors + if show_ab: + a_ab = line([xy[0], half(a, 1, 2, 0)], rgbcolor="blue", alpha=0.6) + b_ab = line([xy[1], half(a, 2, 0, 1)], rgbcolor="blue", alpha=0.6) + c_ab = line([xy[2], half(a, 0, 1, 2)], rgbcolor="blue", alpha=0.6) + ab_point = point(incircle_center, rgbcolor="blue", pointsize=28) + ab_graph = a_ab + b_ab + c_ab + ab_point + else: + ab_graph = Graphics() + + # Medians + if show_median: + a_median = line([xy[0], a_middle[0]], rgbcolor="green", alpha=0.6) + b_median = line([xy[1], a_middle[1]], rgbcolor="green", alpha=0.6) + c_median = line([xy[2], a_middle[2]], rgbcolor="green", alpha=0.6) + median_point = point( + ( + (xy[0][0]+xy[1][0]+xy[2][0])/3.0, + (xy[0][1]+xy[1][1]+xy[2][1])/3.0 + ), rgbcolor="green", pointsize=28) + median_graph = a_median + b_median + c_median + median_point + else: + median_graph = Graphics() + + # Perpendicular Bisectors + if show_pb: + a_pb = line_to_points(a_middle[0], half(a, 1, 2, 0), rgbcolor="red", alpha=0.6) + b_pb = line_to_points(a_middle[1], half(a, 2, 0, 1), rgbcolor="red", alpha=0.6) + c_pb = line_to_points(a_middle[2], half(a, 0, 1, 2), rgbcolor="red", alpha=0.6) + pb_point = point((0, 0), rgbcolor="red", pointsize=28) + pb_graph = a_pb + b_pb + c_pb + pb_point + else: + pb_graph = Graphics() + + # Altitudes + if show_alt: + xA, xB, xC = xy[0][0], xy[1][0], xy[2][0] + yA, yB, yC = xy[0][1], xy[1][1], xy[2][1] + a_alt = plot(((xC-xB)*x+(xB-xC)*xA)/(yB-yC)+yA, (x,-3,3), rgbcolor="brown", alpha=0.6) + b_alt = plot(((xA-xC)*x+(xC-xA)*xB)/(yC-yA)+yB, (x,-3,3), rgbcolor="brown", alpha=0.6) + c_alt = plot(((xB-xA)*x+(xA-xB)*xC)/(yA-yB)+yC, (x,-3,3), rgbcolor="brown", alpha=0.6) + alt_lx = (xA*xB*(yA-yB)+xB*xC*(yB-yC)+xC*xA*(yC-yA)-(yA-yB)*(yB-yC)*(yC-yA))/(xC*yB-xB*yC+xA*yC-xC*yA+xB*yA-xA*yB) + alt_ly = (yA*yB*(xA-xB)+yB*yC*(xB-xC)+yC*yA*(xC-xA)-(xA-xB)*(xB-xC)*(xC-xA))/(yC*xB-yB*xC+yA*xC-yC*xA+yB*xA-yA*xB) + alt_intersection = point((alt_lx, alt_ly), rgbcolor="brown", pointsize=28) + alt_graph = a_alt + b_alt + c_alt + alt_intersection + else: + alt_graph = Graphics() + + # Euler's Line + if show_euler: + euler_graph = line_to_points( + (0, 0), + ( + (xy[0][0]+xy[1][0]+xy[2][0])/3.0, + (xy[0][1]+xy[1][1]+xy[2][1])/3.0 + ), + rgbcolor="purple", + thickness=2, + alpha=0.7 + ) + else: + euler_graph = Graphics() + + show( + C + triangle + triangle_points + labels + ab_graph + median_graph + + pb_graph + alt_graph + incircle_graph + euler_graph, + figsize=[5,5], xmin=-1, xmax=1, ymin=-1, ymax=1 + ) + + +@library_interact +def coin(n = slider(1,10000, 100, default=1000, label="Number of Tosses"), interval = range_slider(0, 1, default=(0.45, 0.55), label="Plotting range (y)")): + """ + This interact demo simulates repeated tosses of a coin, + based on work by Lauri Ruotsalainen, 2010. + + INPUT: + + - `n` -- number of tosses + - `interval` -- plot range (y) + + EXAMPLES:: + + sage: interacts.statistics.coin() + ... + """ + from random import random + c = [] + k = 0.0 + for i in range(1, n + 1): + k += random() + c.append((i, k/i)) + show(point(c[1:], gridlines=[None, [0.5]], pointsize=1), ymin=interval[0], ymax=interval[1]) + + +@library_interact +def secant_method( + f = input_box("x^2-2", label='f(x)'), + interval = range_slider(-5,5,default=(0, 4), label="range"), + d = slider(1, 16, 1, 3, label="10^-d precision"), + maxn = slider(0,15,1,10, label="max iterations")): + """ + Interact explaining the secant method, based on work by + Lauri Ruotsalainen, 2010. + Originally this is based on work by William Stein. + + INPUT: + + - `f` -- function + - `interval` -- range slider for the search interval + - `slider` -- slider for the precision (10^-d) + - `maxn` -- max number of iterations + + EXAMPLES:: + + sage: interacts.calculus.secant_method() + ... + """ + def _secant_method(f, a, b, maxn, h): + intervals = [(a,b)] + round = 1 + while True: + c = b-(b-a)*f(b)/(f(b)-f(a)) + if abs(f(c)) < h or round >= maxn: + break + a, b = b, c + intervals.append((a,b)) + round += 1 + return c, intervals + + x = SR.var('x') + f = symbolic_expression(f).function(x) + a, b = interval + h = 10**(-d) + c, intervals = _secant_method(f, float(a), float(b), maxn, h) + html(r"$\text{Precision h =} 10^{-d}=10^{-%s}=%.5f$"%(d, float(h))) + html(r"$\text{c = }%s$"%c) + html(r"$\text{f(c) = }%s"%f(c)) + html(r"$\text{Iterations = }%s"%len(intervals)) + P = plot(f, a, b, color='red') + k = (P.ymax() - P.ymin())/ (1.5*len(intervals)) + L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) + L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) + L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) + S = sum(line([(c,f(c)), (d,f(d)), (d-(d-c)*f(d)/(f(d)-f(c)), 0)], color="green") for (c,d) in intervals) + show(P + L + S, xmin=a, xmax=b) + +@library_interact +def newton_method( + f = input_box("x^2 - 2"), + c = slider(-10,10, default=6, label='Start (x)'), + hh = slider(-16, -1, 1, -3, label="Precision 2h"), + maxn = slider(0, 15, 1, 10, label="max iterations"), + interval = range_slider(-10,10, default = (0,6), label="Interval"), + list_steps = checkbox(default=False, label="List steps")): + """ + Interact explaining the newton method, based on work by + Lauri Ruotsalainen, 2010. + Originally this is based on work by William Stein. + + INPUT: + + - `f` -- function + - `c` -- starting position (x) + - `interval` -- range slider for the search interval + - `slider` -- slider for the precision (10^-d) + - `maxn` -- max number of iterations + - `list_steps` -- checkbox, if true shows the steps numerically + + EXAMPLES:: + + sage: interacts.calculus.newton_method() + ... + """ + def _newton_method(f, c, maxn, h): + midpoints = [c] + round = 1 + while True: + c = c-f(c)/f.derivative(x)(x=c) + midpoints.append(c) + if f(c-h)*f(c+h) < 0 or round == maxn: + break + round += 1 + return c, midpoints + + x = SR.var('x') + f = symbolic_expression(f).function(x) + a, b = interval + h = 10**hh + c, midpoints = _newton_method(f, float(c), maxn, h/2.0) + html(r"$\text{Precision 2h = }%.5f$"%float(h)) + html(r"$\text{c = }%s$"%c) + html(r"$\text{f(c) = }%s"%f(c)) + html(r"$\text{Iterations = }%s"%len(midpoints)) + if list_steps: + s = "

" + s += "" + for i, c in enumerate(midpoints): + s += ""%(i, c, f(c), f(c-h)*f(c+h)) + s += "
$n$$x_n$$f(x_n)$$f(x_n-h)f(x_n+h)$
$%d$$%.4f$$%.4f$$%.4f$
" + html(s) + else: + P = plot(f, x, interval, color="blue") + L = sum(line([(c, 0), (c, f(c))], color="green") for c in midpoints[:-1]) + for i in range(len(midpoints) - 1): + L += line([(midpoints[i], f(midpoints[i])), (midpoints[i+1], 0)], color="red") + show(P + L, xmin=interval[0], xmax=interval[1], ymin=P.ymin(), ymax=P.ymax()) + +@library_interact +def trapezoid_integration( + f = input_box(default = "x^2-5*x + 10", label='f(x)'), + n = slider(1,100,1,5, label='# divisions'), + interval = range_slider(-10,10,default=(0,8), label="Integral interval") + ): + """ + Interact explaining the trapezoid method for definite integrals, based on work by + Lauri Ruotsalainen, 2010 (based on the application "Numerical integrals with various rules" + by Marshall Hampton and Nick Alexander) + + INPUT: + + - `f` -- function of variable x to integrate + - `n` -- number of divisions + - `interval` -- interval to integrate + + EXAMPLES:: + + sage: interacts.calculus.trapezoid_integration() + ... + """ + xs = [] + ys = [] + h = (interval[1]-interval[0])/n + x = SR.var('x') + f = symbolic_expression(f).function(x) + + trapezoids = Graphics() + + for i in range(n): + xi = interval[0] + i*h + yi = f(xi) + trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)],[xi + h, 0],[xi, 0]], rgbcolor = (1,0,0)) + xs.append(xi) + ys.append(yi) + xs.append(xi + h) + ys.append(f(xi + h)) + + show(plot(f, interval[0], interval[1]) + trapezoids, xmin = interval[0], xmax = interval[1]) + + numeric_value = integral_numerical(f, interval[0], interval[1])[0] + approx = h *(ys[0]/2 + sum([ys[i] for i in range(1,n)]) + ys[n]/2) + + sum_formula_html = r"d \cdot \left[\frac{f(x_0)}{2} + %s + \frac{f(x_{%s})}{2}\right]" % ( + ' + '.join([ "f(x_{%s})"%i for i in range(1,n)]), + n + ) + sum_placement_html = r"%.2f \cdot \left[\frac{f(%.2f)}{2} + %s + \frac{f(%.2f)}{2}\right]" % ( + h, + N(xs[0], digits=5), + ' + '.join([ "f(%.2f)" %N(i, digits=5) for i in xs[1:-1]]), + N(xs[n], digits=5) + ) + sum_values_html = r"%.2f \cdot \left[\frac{%.2f}{2} + %s + \frac{%.2f}{2}\right]" % ( + h, + N(ys[0], digits=5), + ' + '.join([ "%.2f" % N(i, digits=5) for i in ys[1:-1]]), + N(ys[n], digits=5) + ) + + html(r''' +
+ \begin{align*} + \int_{%.2f}^{%.2f} {f(x) \, dx} & = %.6f \\\ + \\ + \int_{%.2f}^{%.2f} {f(x) \, dx} + & \approx %s \\ + & = %s \\ + & = %s \\ + & = %s + \end{align*} +
+ ''' % ( + interval[0], interval[1], + N(numeric_value, digits=7), + interval[0], interval[1], + sum_formula_html, sum_placement_html, sum_values_html, + N(approx, digits=7) + )) + + +@library_interact +def simpson_integration( + f = input_box(default = 'x*sin(x)+x+1', label='f(x)'), + n=slider(2,100,2,6, label='# divisions'), + interval=range_slider(-10,10,default=(0,10), label="Integration Interval")): + """ + Interact explaining the simpson method for definite integrals, based on work by + Lauri Ruotsalainen, 2010 (based on the application "Numerical integrals with various rules" + by Marshall Hampton and Nick Alexander) + + INPUT: + + - `f` -- function of variable x to integrate + - `n` -- number of divisions (mult. of 2) + - `interval` -- interval to integrate + + EXAMPLES:: + + sage: interacts.calculus.simpson_integration() + ... + """ + x = SR.var('x') + f = symbolic_expression(f).function(x) + + def parabola(a, b, c): + from sage.all import solve + A, B, C = SR.var("A, B, C") + K = solve([A*a[0]**2+B*a[0]+C==a[1], A*b[0]**2+B*b[0]+C==b[1], A*c[0]**2+B*c[0]+C==c[1]], [A, B, C], solution_dict=True)[0] + f = K[A]*x**2+K[B]*x+K[C] + return f + xs = []; ys = [] + dx = (interval[1]-interval[0])/n + + for i in range(n+1): + xs.append(interval[0] + i*dx) + ys.append(f(xs[-1])) + + parabolas = Graphics() + lines = Graphics() + + for i in range(0, n-1, 2): + p = parabola((xs[i],ys[i]),(xs[i+1],ys[i+1]),(xs[i+2],ys[i+2])) + parabolas += plot(p(x), x, xmin=xs[i], xmax=xs[i+2], color="red") + lines += line([(xs[i],ys[i]), (xs[i],0), (xs[i+2],0)],color="red") + lines += line([(xs[i+1],ys[i+1]), (xs[i+1],0)], linestyle="-.", color="red") + + lines += line([(xs[-1],ys[-1]), (xs[-1],0)], color="red") + + show(plot(f(x),x,interval[0],interval[1]) + parabolas + lines, xmin = interval[0], xmax = interval[1]) + + numeric_value = integral_numerical(f,interval[0],interval[1])[0] + approx = dx/3 *(ys[0] + sum([4*ys[i] for i in range(1,n,2)]) + sum([2*ys[i] for i in range(2,n,2)]) + ys[n]) + + sum_formula_html = r"\frac{d}{3} \cdot \left[ f(x_0) + %s + f(x_{%s})\right]" % ( + ' + '.join([ r"%s \cdot f(x_{%s})" %(i%2*(-2)+4, i+1) for i in range(0,n-1)]), + n + ) + + sum_placement_html = r"\frac{%.2f}{3} \cdot \left[ f(%.2f) + %s + f(%.2f)\right]" % ( + dx, + N(xs[0],digits=5), + ' + '.join([ r"%s \cdot f(%.2f)" %(i%2*(-2)+4, N(xk, digits=5)) for i, xk in enumerate(xs[1:-1])]), + N(xs[n],digits=5) + ) + + sum_values_html = r"\frac{%.2f}{3} \cdot \left[ %s %s %s\right]" %( + dx, + "%.2f + "%N(ys[0],digits=5), + ' + '.join([ r"%s \cdot %.2f" %(i%2*(-2)+4, N(yk, digits=5)) for i, yk in enumerate(ys[1:-1])]), + " + %.2f"%N(ys[n],digits=5) + ) + + html(r''' +
+ \begin{align*} + \int_{%.2f}^{%.2f} {f(x) \, dx} & = %.6f \\ + \\ + \int_{%.2f}^{%.2f} {f(x) \, dx} + & \approx %s \\ + & = %s \\ + & = %s \\ + & = %.6f + \end{align*} +
+ ''' % ( + interval[0],interval[1], + N(numeric_value,digits=7), + interval[0], interval[1], + sum_formula_html, sum_placement_html, sum_values_html, + N(approx,digits=7) + )) diff --git a/sage/interacts/statistics.py b/sage/interacts/statistics.py new file mode 100644 --- /dev/null +++ b/sage/interacts/statistics.py @@ -0,0 +1,14 @@ +""" +Interacts for Statistics + +""" + + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from library import coin