# HG changeset patch # User Harald Schilly # Date 1280507166 -7200 # Node ID 8c81adcbd3dcbdf24634dd63305ea0c9a9c88845 # Parent 12c5ece399703e70d63205c71a66ff1d9f735cfb #9623 selected interact examples from wiki.sagemath.org/interacts diff --git a/module_list.py b/module_list.py --- a/module_list.py +++ b/module_list.py @@ -451,6 +451,16 @@ ################################ ## + ## sage.interacts + ## + ################################ + + Extension('sage.interacts.library_cython', + sources = ['sage/interacts/library_cython.pyx'], + libraries = []), + + ################################ + ## ## sage.libs ## ################################ diff --git a/sage/interacts/__init__.py b/sage/interacts/__init__.py --- a/sage/interacts/__init__.py +++ b/sage/interacts/__init__.py @@ -4,3 +4,5 @@ import calculus import geometry import statistics +import fractals +import algebra diff --git a/sage/interacts/algebra.py b/sage/interacts/algebra.py new file mode 100644 --- /dev/null +++ b/sage/interacts/algebra.py @@ -0,0 +1,14 @@ +""" +Interacts for Algebra and Number Theory + +""" + + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from library import polar_prime_spiral diff --git a/sage/interacts/calculus.py b/sage/interacts/calculus.py --- a/sage/interacts/calculus.py +++ b/sage/interacts/calculus.py @@ -11,7 +11,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from library import taylor_polynomial, definite_integral +from library import taylor_polynomial +from library import 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 +from library import function_tool diff --git a/sage/interacts/fractals.py b/sage/interacts/fractals.py new file mode 100644 --- /dev/null +++ b/sage/interacts/fractals.py @@ -0,0 +1,14 @@ +""" +Interacts for Fractals + +""" + + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from library import mandelbrot, julia, cellular_automaton diff --git a/sage/interacts/library.py b/sage/interacts/library.py --- a/sage/interacts/library.py +++ b/sage/interacts/library.py @@ -13,9 +13,11 @@ 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 factor, srange, Integer, points 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.all import implicit_plot3d, plot3d, cube, integral_numerical, CDF, complex_plot, matrix_plot, disk +from sage.ext.fast_callable import fast_callable from sage.misc.misc import sage_wraps from sage.misc.html import html @@ -987,3 +989,354 @@ sum_formula_html, sum_placement_html, sum_values_html, N(approx,digits=7) )) + +x = SR.var('x') +@library_interact +def function_tool(f=sin(x), g=cos(x), xrange=range_slider(-3,3,default=(0,1),label='x-range'), + yrange='auto', + a=1, + action=selector(['f', 'df/dx', 'int f', 'num f', 'den f', '1/f', 'finv', + 'f+a', 'f-a', 'f*a', 'f/a', 'f^a', 'f(x+a)', 'f(x*a)', + 'f+g', 'f-g', 'f*g', 'f/g', 'f(g)'], + width=15, nrows=5, label="h = "), + do_plot = ("Draw Plots", True)): + """ + Function Plotting Tool (by William Stein (?)) + http://wiki.sagemath.org/interact/calculus#Functiontool + + INPUT: + + - `f` -- function f(x) + - `g` -- function g(x) + - `xrange` -- range for plotting (x) + - `yrange` -- range for plotting ('auto' is default, otherwise a tuple) + - `a` -- factor ``a`` + - `action` -- select given operation on or combination of functions + - `do_plot` -- if true, a plot is drawn + + TESTS:: + + sage: interacts.calculus.function_tool() + ... + """ + x = SR.var('x') + try: + f = SR(f); g = SR(g); a = SR(a) + except TypeError, msg: + print msg[-200:] + print "Unable to make sense of f,g, or a as symbolic expressions in single variable x." + return + if not (isinstance(xrange, tuple) and len(xrange) == 2): + xrange = (0,1) + h = 0; lbl = '' + if action == 'f': + h = f + lbl = 'f' + elif action == 'df/dx': + h = f.derivative(x) + lbl = r'\frac{df}{dx}' + elif action == 'int f': + h = f.integrate(x) + lbl = r'\int f dx' + elif action == 'num f': + h = f.numerator() + lbl = r'\text{numer(f)}' + elif action == 'den f': + h = f.denominator() + lbl = r'\text{denom(f)}' + elif action == '1/f': + h = 1/f + lbl = r'\frac{1}{f}' + elif action == 'finv': + h = solve(f == var('y'), x)[0].rhs() + lbl = 'f^{-1}(y)' + elif action == 'f+a': + h = f+a + lbl = 'f + a' + elif action == 'f-a': + h = f-a + lbl = 'f - a' + elif action == 'f*a': + h = f*a + lbl = r'f \times a' + elif action == 'f/a': + h = f/a + lbl = r'\frac{f}{a}' + elif action == 'f^a': + h = f**a + lbl = 'f^a' + elif action == 'f^a': + h = f**a + lbl = 'f^a' + elif action == 'f(x+a)': + h = f(x+a) + lbl = 'f(x+a)' + elif action == 'f(x*a)': + h = f(x*a) + lbl = 'f(xa)' + elif action == 'f+g': + h = f+g + lbl = 'f + g' + elif action == 'f-g': + h = f-g + lbl = 'f - g' + elif action == 'f*g': + h = f*g + lbl = r'f \times g' + elif action == 'f/g': + h = f/g + lbl = r'\frac{f}{g}' + elif action == 'f(g)': + h = f(g) + lbl = 'f(g)' + html('
$f = %s$
'%latex(f)) + html('
$g = %s$
'%latex(g)) + html('
$h = %s = %s$
'%(lbl, latex(h))) + if do_plot: + P = plot(f, xrange, color='red', thickness=2) + \ + plot(g, xrange, color='green', thickness=2) + \ + plot(h, xrange, color='blue', thickness=2) + if yrange == 'auto': + show(P, xmin=xrange[0], xmax=xrange[1]) + else: + yrange = sage_eval(yrange) + show(P, xmin=xrange[0], xmax=xrange[1], ymin=yrange[0], ymax=yrange[1]) + +@library_interact +def julia(expo = slider(-10,10,0.1,2), + c_real = slider(-2,2,0.01,0.5, label='real part const.'), + c_imag = slider(-2,2,0.01,0.5, label='imag part const.'), + iterations=slider(1,100,1,20, label='# iterations'), + zoom_x = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom X'), + zoom_y = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom Y'), + plot_points = slider(20,400,20, default=150, label='plot points'), + dpi = slider(20, 200, 10, default=80, label='dpi')): + """ + Julia Fractal, based on work by Harald Schilly + http://wiki.sagemath.org/interact/fractal#Julia + + INPUT: + + - `exponent` -- exponent ``e`` in $z^e+c$ + - `c_real` -- real part of the constant ``c`` + - `c_imag` -- imaginary part of the constant ``c`` + - `iterations` -- number of iterations + - `zoom_x` -- range slider for zoom in x direction + - `zoom_y` -- range slider for zoom in y direction + - `plot_points` -- number of points to plot + - `dpi` -- dots-per-inch parameter for the plot + + TESTS:: + + sage: interacts.fractals.julia() + ... + """ + z = SR.var('z') + I = CDF.gen() + f = symbolic_expression(z**expo + c_real + c_imag*I).function(z) + ff_j = fast_callable(f, vars=[z], domain=CDF) + + from sage.interacts.library_cython import julia + + html('

Julia Fractal

') + html(r'Recursive Formula: $z \leftarrow z^{%.2f} + (%.2f+%.2f*\mathbb{I})$' % (expo, c_real, c_imag)) + complex_plot(lambda z: julia(ff_j, z, iterations), zoom_x, zoom_y, plot_points=plot_points, dpi=dpi).show(frame=True, aspect_ratio=1) + +@library_interact +def mandelbrot(expo = slider(-10,10,0.1,2), + iterations=slider(1,100,1,20, label='# iterations'), + zoom_x = range_slider(-2,2,0.01,(-2,1), label='Zoom X'), + zoom_y = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom Y'), + plot_points = slider(20,400,20, default=150, label='plot points'), + dpi = slider(20, 200, 10, default=80, label='dpi')): + """ + Mandelbrot Fractal, based on work by Harald Schilly + http://wiki.sagemath.org/interact/fractal#Mandelbrot + + INPUT: + + - `exponent` -- exponent ``e`` in $z^e+c$ + - `iterations` -- number of iterations + - `zoom_x` -- range slider for zoom in x direction + - `zoom_y` -- range slider for zoom in y direction + - `plot_points` -- number of points to plot + - `dpi` -- dots-per-inch parameter for the plot + + TESTS:: + + sage: interacts.fractals.mandelbrot() + ... + """ + x, z, c = SR.var('x, z, c') + f = symbolic_expression(z**expo + c).function(z, c) + ff_m = fast_callable(f, vars=[z,c], domain=CDF) + + from sage.interacts.library_cython import mandel + + html('

Mandelbrot Fractal

') + html(r'Recursive Formula: $z \leftarrow z^{%.2f} + c$ for $c \in \mathbb{C}$' % expo) + complex_plot(lambda z: mandel(ff_m, z, iterations), zoom_x, zoom_y, plot_points=plot_points, dpi=dpi).show(frame=True, aspect_ratio=1) + + +@library_interact +def cellular_automaton( + N=slider(1,500,1,label='Number of iterations',default=100), + rule_number=slider(0, 255, 1, default=110, label='Rule number'), + size = slider(1, 11, step_size=1, default=6, label='size')): + """ + Yields a matrix showing the evolution of a Wolfram's cellular automaton. + Based on work by Pablo Angulo. + http://wiki.sagemath.org/interact/misc#CellularAutomata + + INPUT: + + - `N` -- iterations + - `rule_number` -- rule number (0 to 255) + - `size` -- size of the shown picture + + TESTS:: + + sage: interacts.fractals.cellular_automaton() + ... + """ + from sage.all import Integer + if not 0 <= rule_number <= 255: + raise Exception('Invalid rule number') + binary_digits = Integer(rule_number).digits(base=2) + rule = binary_digits + [0]*(8-len(binary_digits)) + + html('

Cellular Automaton

'+ + '
"A cellular automaton is a collection of "colored" cells \ + on a grid of specified shape that evolves through a number of \ + discrete time steps according to a set of rules based on the \ + states of neighboring cells." — \ + Mathworld,\ + Cellular Automaton
\ +
Rule %s expands to %s
' % (rule_number, ''.join(map(str,rule))) + ) + + from sage.interacts.library_cython import cellular + M = cellular(rule, N) + plot_M = matrix_plot(M) + plot_M.show(figsize=[size,size]) + + +@library_interact +def polar_prime_spiral( + interval = range_slider(1, 4000, 10, default=(1, 1000), label="range"), + show_factors = True, + highlight_primes = True, + show_curves = True, + n = slider(1,200, 1, default=89, label="number n"), + dpi = slider(10,300, 10, default=100, label="dpi")): + """ + Polar Prime Spiral interact, based on work by David Runde. + + For more information about the factors in the spiral, + visit http://www.dcs.gla.ac.uk/~jhw/spirals/index.html by John Williamson. + + INPUT: + + - `interval` -- range slider to specify start and end + - `show_factors` -- if true, show factors + - `highlight_primes` -- if true, prime numbers are highlighted + - `show_curves` -- if true, curves are plotted + - `n` -- number n + - `dpi` -- dots per inch resolution for plotting + + TESTS:: + + sage: sage.interacts.algebra.polar_prime_spiral() + ... + + """ + + html('

Polar Prime Spiral

\ +
\ + For more information about the factors in the spiral, visit \ + \ + Number Spirals by John Williamson.
' + ) + + start, end = interval + from sage.ext.fast_eval import fast_float + from math import floor, ceil + from sage.plot.colors import hue + + if start < 1 or end <= start: + print "invalid start or end value" + return + if n > end: + print "WARNING: n is greater than end value" + return + if n < start: + print "n < start value" + return + nn = SR.var('nn') + f1 = fast_float(sqrt(nn)*cos(2*pi*sqrt(nn)), 'nn') + f2 = fast_float(sqrt(nn)*sin(2*pi*sqrt(nn)), 'nn') + f = lambda x: (f1(x), f2(x)) + + list =[] + list2=[] + if show_factors == False: + for i in srange(start, end, include_endpoint = True): + if Integer(i).is_pseudoprime(): list.append(f(i-start+1)) #Primes list + else: list2.append(f(i-start+1)) #Composites list + P = points(list) + R = points(list2, alpha = .1) #Faded Composites + else: + for i in srange(start, end, include_endpoint = True): + list.append(disk((f(i-start+1)),0.05*pow(2,len(factor(i))-1), (0,2*pi))) #resizes each of the dots depending of the number of factors of each number + if Integer(i).is_pseudoprime() and highlight_primes: list2.append(f(i-start+1)) + P = plot(list) + p_size = 5 #the orange dot size of the prime markers + if not highlight_primes: list2 = [(f(n-start+1))] + R = points(list2, hue = .1, pointsize = p_size) + + if n > 0: + html('n = %s' % factor(n)) + + p = 1 + #The X which marks the given n + W1 = disk((f(n-start+1)), p, (pi/6, 2*pi/6)) + W2 = disk((f(n-start+1)), p, (4*pi/6, 5*pi/6)) + W3 = disk((f(n-start+1)), p, (7*pi/6, 8*pi/6)) + W4 = disk((f(n-start+1)), p, (10*pi/6, 11*pi/6)) + Q = plot(W1 + W2 + W3 + W4, alpha = .1) + + n = n - start +1 #offsets the n for different start values to ensure accurate plotting + if show_curves: + begin_curve = 0 + t = SR.var('t') + a=1.0 + b=0.0 + if n > (floor(sqrt(n)))**2 and n <= (floor(sqrt(n)))**2 + floor(sqrt(n)): + c = -((floor(sqrt(n)))**2 - n) + c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) + else: + c = -((ceil(sqrt(n)))**2 - n) + c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) + html('Pink Curve: $n^2 + %s$' % c) + html('Green Curve: $n^2 + n + %s$' % c2) + m = SR.var('m') + g = symbolic_expression(a*m**2+b*m+c).function(m) + r = symbolic_expression(sqrt(g(m))).function(m) + theta = symbolic_expression(r(m)- m*sqrt(a)).function(m) + S1 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), + (begin_curve, ceil(sqrt(end-start))), color=hue(0.8), thickness = .3) #Pink Line + + b = 1 + c = c2; + g = symbolic_expression(a*m**2+b*m+c).function(m) + r = symbolic_expression(sqrt(g(m))).function(m) + theta = symbolic_expression(r(m)- m*sqrt(a)).function(m) + S2 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), + (begin_curve, ceil(sqrt(end-start))), color=hue(0.6), thickness = .3) #Green Line + + show(R+P+S1+S2+Q, aspect_ratio = 1, axes = False, dpi = dpi) + else: show(R+P+Q, aspect_ratio = 1, axes = False, dpi = dpi) + else: show(R+P, aspect_ratio = 1, axes = False, dpi = dpi) + + + diff --git a/sage/interacts/library_cython.pyx b/sage/interacts/library_cython.pyx new file mode 100644 --- /dev/null +++ b/sage/interacts/library_cython.pyx @@ -0,0 +1,99 @@ +r""" +Library of cythonized methods +""" + +#***************************************************************************** +# Copyright (C) 2010 Harald Schilly +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.misc import prod + +include '../ext/interrupt.pxi' +include '../ext/cdefs.pxi' +include "../ext/stdsage.pxi" + +cpdef julia(ff_j, z, int iterations): + """ + Helper function for the Julia Fractal interact example. + + INPUT: + + - `ff_j` -- fast callable for the inner iteration + - `z` -- complex number + - `iterations` -- number of loops + + TESTS:: + + sage: from sage.interacts.library_cython import julia + sage: z = var('z') + sage: c_real, c_imag = 1, 1 + sage: f = symbolic_expression(z**2 + c_real + c_imag * CDF.gen()).function(z) + sage: ff_m = fast_callable(f, vars=[z], domain=CDF) + sage: julia(ff_m, CDF(1,1), 3) + 1.0 + 3.0*I + """ + for i in range(iterations): + z = ff_j(z) + if z.abs() > 2: break + return z + +cpdef mandel(ff_m, z, int iterations): + """ + Helper function for the Mandelbrot Fractal interact example. + + INPUT: + + - `ff_m` -- fast callable for the inner iteration + - `z` -- complex number + - `iterations` -- number of loops + + TESTS:: + + sage: from sage.interacts.library_cython import mandel + sage: z, c = var('z, c') + sage: f = symbolic_expression(z**2 + c).function(z,c) + sage: ff_m = fast_callable(f, vars=[z,c], domain=CDF) + sage: mandel(ff_m, CDF(1,1), 3) + 1.0 + 3.0*I + + """ + c = z + for i in range(iterations): + z = ff_m(z, c) + if z.abs() > 2: break + return z + + +cpdef cellular(rule, int N): + ''' + Cythonized helper function for the callular_automata fractal. + Yields a matrix showing the evolution of a Wolfram's cellular automaton. + Based on work by Pablo Angulo. + http://wiki.sagemath.org/interact/misc#CellularAutomata + + INPUT: + + - `rule` -- determines how a cell's value is updated, depending on its neighbors + - `N` -- number of iterations + + TESTS:: + + sage: from sage.interacts.library_cython import cellular + sage: rule = [1, 0, 1, 0, 0, 1, 1, 0] + sage: N = 3 + sage: print cellular(rule, 3) + + ''' + from numpy import zeros + cdef int j, k, l + M=zeros((N, 2*N+1), dtype=int) + M[0,N]=1 + + for j in range(1, N): + for k in range(N-j, N+j+1): + l = 4 * M[j-1, k-1] + 2 * M[j-1, k] + M[j-1, k+1] + M[j,k] = rule[l] + return M