| 98 | |
| 99 | @library_interact |
| 100 | def definite_integral( |
| 101 | title = text_control('<h2>Definite integral</h2>'), |
| 102 | f = input_box(default = "3*x", label = '$f(x)=$'), |
| 103 | g = input_box(default = "x^2", label = '$g(x)=$'), |
| 104 | interval = range_slider(-10,10,default=(0,3), label="Interval"), |
| 105 | x_range = range_slider(-10,10,default=(0,3), label = "plot range (x)"), |
| 106 | selection = selector(["f", "g", "f and g", "f - g"], default="f and g", label="Select")): |
| 107 | """ |
| 108 | This is a demo interact for plotting the definite intergral of a function |
| 109 | based on work by Lauri Ruotsalainen, 2010. |
| 110 | |
| 111 | INPUT: |
| 112 | |
| 113 | - ``function`` -- input box, function in x |
| 114 | - ``interval`` -- interval for the definite integral |
| 115 | - ``x_range`` -- range slider for plotting range |
| 116 | - ``selection`` -- selector on how to visualize the integrals |
| 117 | |
| 118 | EXAMPLES:: |
| 119 | |
| 120 | sage: interacts.calculus.definite_integral() |
| 121 | <html>...</html> |
| 122 | """ |
| 123 | x = SR.var('x') |
| 124 | f = symbolic_expression(f).function(x) |
| 125 | g = symbolic_expression(g).function(x) |
| 126 | f_plot = Graphics(); g_plot = Graphics(); h_plot = Graphics(); |
| 127 | text = "" |
| 128 | |
| 129 | # Plot function f. |
| 130 | if selection != "g": |
| 131 | f_plot = plot(f(x), x, x_range, color="blue", thickness=1.5) |
| 132 | |
| 133 | # Color and calculate the area between f and the horizontal axis. |
| 134 | if selection == "f" or selection == "f and g": |
| 135 | f_plot += plot(f(x), x, interval, color="blue", fill=True, fillcolor="blue", fillalpha=0.15) |
| 136 | text += r"$\int_{%.2f}^{%.2f}(\color{Blue}{f(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( |
| 137 | interval[0], interval[1], |
| 138 | interval[0], interval[1], |
| 139 | latex(f(x)), |
| 140 | f(x).nintegrate(x, interval[0], interval[1])[0] |
| 141 | ) |
| 142 | |
| 143 | if selection == "f and g": |
| 144 | text += r"<br/>" |
| 145 | |
| 146 | # Plot function g. Also color and calculate the area between g and the horizontal axis. |
| 147 | if selection == "g" or selection == "f and g": |
| 148 | g_plot = plot(g(x), x, x_range, color="green", thickness=1.5) |
| 149 | g_plot += plot(g(x), x, interval, color="green", fill=True, fillcolor="yellow", fillalpha=0.5) |
| 150 | text += r"$\int_{%.2f}^{%.2f}(\color{Green}{g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( |
| 151 | interval[0], interval[1], |
| 152 | interval[0], interval[1], |
| 153 | latex(g(x)), |
| 154 | g(x).nintegrate(x, interval[0], interval[1])[0] |
| 155 | ) |
| 156 | |
| 157 | # Plot function f-g. Also color and calculate the area between f-g and the horizontal axis. |
| 158 | if selection == "f - g": |
| 159 | g_plot = plot(g(x), x, x_range, color="green", thickness=1.5) |
| 160 | g_plot += plot(g(x), x, interval, color="green", fill=f(x), fillcolor="red", fillalpha=0.15) |
| 161 | h_plot = plot(f(x)-g(x), x, interval, color="red", thickness=1.5, fill=True, fillcolor="red", fillalpha=0.15) |
| 162 | text = r"$\int_{%.2f}^{%.2f}(\color{Red}{f(x)-g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( |
| 163 | interval[0], interval[1], |
| 164 | interval[0], interval[1], |
| 165 | latex(f(x)-g(x)), |
| 166 | (f(x)-g(x)).nintegrate(x, interval[0], interval[1])[0] |
| 167 | ) |
| 168 | |
| 169 | show(f_plot + g_plot + h_plot, gridlines=True) |
| 170 | html(text) |
| 171 | |
| 172 | @library_interact |
| 173 | def function_derivative( |
| 174 | title = text_control('<h2>Derivative grapher</h2>'), |
| 175 | function = input_box(default="x^5-3*x^3+1", label="Function:"), |
| 176 | x_range = range_slider(-15,15,0.1, default=(-2,2), label="Range (x)"), |
| 177 | y_range = range_slider(-15,15,0.1, default=(-8,6), label="Range (y)")): |
| 178 | """ |
| 179 | This is a demo interact for plotting derivatives of a function based on work by |
| 180 | Lauri Ruotsalainen, 2010. |
| 181 | |
| 182 | INPUT: |
| 183 | |
| 184 | - ``function`` -- input box, function in x |
| 185 | - ``x_range`` -- range slider for plotting range |
| 186 | - ``y_range`` -- range slider for plotting range |
| 187 | |
| 188 | EXAMPLES:: |
| 189 | |
| 190 | sage: interacts.calculus.function_derivative() |
| 191 | <html>...</html> |
| 192 | """ |
| 193 | x = SR.var('x') |
| 194 | f = symbolic_expression(function).function(x) |
| 195 | df = derivative(f, x) |
| 196 | ddf = derivative(df, x) |
| 197 | plots = plot(f(x), x_range, thickness=1.5) + plot(df(x), x_range, color="green") + plot(ddf(x), x_range, color="red") |
| 198 | if y_range == (0,0): |
| 199 | show(plots, xmin=x_range[0], xmax=x_range[1]) |
| 200 | else: |
| 201 | show(plots, xmin=x_range[0], xmax=x_range[1], ymin=y_range[0], ymax=y_range[1]) |
| 202 | |
| 203 | html("<center>$\color{Blue}{f(x) = %s}$</center>"%latex(f(x))) |
| 204 | html("<center>$\color{Green}{f'(x) = %s}$</center>"%latex(df(x))) |
| 205 | html("<center>$\color{Red}{f''(x) = %s}$</center>"%latex(ddf(x))) |
| 206 | |
| 207 | @library_interact |
| 208 | def difference_quotient( |
| 209 | title = text_control('<h2>Difference quotient</h2>'), |
| 210 | f = input_box(default="sin(x)", label='f(x)'), |
| 211 | interval= range_slider(0, 10, 0.1, default=(0.0,10.0), label="Range"), |
| 212 | a = slider(0, 10, None, 5.5, label = 'a'), |
| 213 | x0 = slider(0, 10, None, 2.5), label = 'start point'): |
| 214 | """ |
| 215 | This is a demo interact for difference quotient based on work by |
| 216 | Lauri Ruotsalainen, 2010. |
| 217 | |
| 218 | INPUT: |
| 219 | |
| 220 | - ``f`` -- input box, function in x |
| 221 | - ``interval`` -- range slider for plotting |
| 222 | - ``a`` -- slider for a |
| 223 | - ``x0`` -- slider for x0 |
| 224 | |
| 225 | EXAMPLES:: |
| 226 | |
| 227 | sage: interacts.calculus.difference_quotient() |
| 228 | <html>...</html> |
| 229 | """ |
| 230 | html('<h2>Difference Quotient</h2>') |
| 231 | html('<div style="white-space: normal;">\ |
| 232 | <a href="http://en.wikipedia.org/wiki/Difference_quotient" target="_blank">\ |
| 233 | Wikipedia article about difference quotient</a></div>' |
| 234 | ) |
| 235 | |
| 236 | x = SR.var('x') |
| 237 | f = symbolic_expression(f).function(x) |
| 238 | fmax = f.find_maximum_on_interval(interval[0], interval[1])[0] |
| 239 | fmin = f.find_minimum_on_interval(interval[0], interval[1])[0] |
| 240 | f_height = fmax - fmin |
| 241 | measure_y = fmin - 0.1*f_height |
| 242 | |
| 243 | measure_0 = line2d([(x0, measure_y), (a, measure_y)], rgbcolor="black") |
| 244 | measure_1 = line2d([(x0, measure_y + 0.02*f_height), (x0, measure_y-0.02*f_height)], rgbcolor="black") |
| 245 | measure_2 = line2d([(a, measure_y + 0.02*f_height), (a, measure_y-0.02*f_height)], rgbcolor="black") |
| 246 | text_x0 = text("x0", (x0, measure_y - 0.05*f_height), rgbcolor="black") |
| 247 | text_a = text("a", (a, measure_y - 0.05*f_height), rgbcolor="black") |
| 248 | measure = measure_0 + measure_1 + measure_2 + text_x0 + text_a |
| 249 | |
| 250 | tanf = symbolic_expression((f(x0)-f(a))*(x-a)/(x0-a)+f(a)).function(x) |
| 251 | |
| 252 | fplot = plot(f(x), x, interval[0], interval[1]) |
| 253 | tanplot = plot(tanf(x), x, interval[0], interval[1], rgbcolor="#FF0000") |
| 254 | points = point([(x0, f(x0)), (a, f(a))], pointsize=20, rgbcolor="#005500") |
| 255 | dashline = line2d([(x0, f(x0)), (x0, f(a)), (a, f(a))], rgbcolor="#005500", linestyle="--") |
| 256 | html('<h2>Difference Quotient</h2>') |
| 257 | show(fplot + tanplot + points + dashline + measure, xmin=interval[0], xmax=interval[1], ymin=fmin-0.2*f_height, ymax=fmax) |
| 258 | html(r"<br>$\text{Line's equation:}$") |
| 259 | html(r"$y = %s$<br>"%tanf(x)) |
| 260 | html(r"$\text{Slope:}$") |
| 261 | html(r"$k = \frac{f(x0)-f(a)}{x0-a} = %s$<br>" % (N(derivative(tanf(x), x), digits=5))) |
| 262 | |
| 263 | @library_interact |
| 264 | def quadratic_equation(A = slider(-7, 7, 1, 1), B = slider(-7, 7, 1, 1), C = slider(-7, 7, 1, -2)): |
| 265 | """ |
| 266 | This is a demo interact for solving quadratic equations based on work by |
| 267 | Lauri Ruotsalainen, 2010. |
| 268 | |
| 269 | INPUT: |
| 270 | |
| 271 | - ``A`` -- integer slider |
| 272 | - ``B`` -- integer slider |
| 273 | - ``C`` -- integer slider |
| 274 | |
| 275 | EXAMPLES:: |
| 276 | |
| 277 | sage: interacts.calculus.quadratic_equation() |
| 278 | <html>...</html> |
| 279 | """ |
| 280 | x = SR.var('x') |
| 281 | f = symbolic_expression(A*x**2 + B*x + C).function(x) |
| 282 | html('<h2>The Solutions of the Quadratic Equation</h2>') |
| 283 | html("$%s = 0$" % f(x)) |
| 284 | |
| 285 | show(plot(f(x), x, (-10, 10), ymin=-10, ymax=10), aspect_ratio=1, figsize=4) |
| 286 | |
| 287 | d = B**2 - 4*A*C |
| 288 | |
| 289 | if d < 0: |
| 290 | color = "Red" |
| 291 | sol = r"\text{solution} \in \mathbb{C}" |
| 292 | elif d == 0: |
| 293 | color = "Blue" |
| 294 | sol = -B/(2*A) |
| 295 | else: |
| 296 | color = "Green" |
| 297 | a = (-B+sqrt(B**2-4*A*C))/(2*A) |
| 298 | b = (-B-sqrt(B**2-4*A*C))/(2*A) |
| 299 | sol = r"\begin{cases}%s\\%s\end{cases}" % (latex(a), latex(b)) |
| 300 | |
| 301 | if B < 0: |
| 302 | dis1 = "(%s)^2-4*%s*%s" % (B, A, C) |
| 303 | else: |
| 304 | dis1 = "%s^2-4*%s*%s" % (B, A, C) |
| 305 | dis2 = r"\color{%s}{%s}" % (color, d) |
| 306 | |
| 307 | html("$Ax^2 + Bx + C = 0$") |
| 308 | calc = r"$x = \frac{-B\pm\sqrt{B^2-4AC}}{2A} = " + \ |
| 309 | r"\frac{-%s\pm\sqrt{%s}}{2*%s} = " + \ |
| 310 | r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" |
| 311 | html(calc % (B, dis1, A, B, dis2, (2*A), sol)) |
| 312 | |
| 313 | @library_interact |
| 314 | def trigonometric_properties_triangle( |
| 315 | a0 = slider(0, 360, 1, 30, label="A"), |
| 316 | a1 = slider(0, 360, 1, 180, label="B"), |
| 317 | a2 = slider(0, 360, 1, 300, label="C")): |
| 318 | """ |
| 319 | This is an interact for demonstrating trigonometric properties |
| 320 | in a triangle based on work by Lauri Ruotsalainen, 2010. |
| 321 | |
| 322 | INPUT: |
| 323 | |
| 324 | - ``a0`` -- angle |
| 325 | - ``a1`` -- angle |
| 326 | - ``a2`` -- angle |
| 327 | |
| 328 | EXAMPLES:: |
| 329 | |
| 330 | sage: interacts.geometry.trigonometric_properties_triangle() |
| 331 | <html>...</html> |
| 332 | """ |
| 333 | import math |
| 334 | |
| 335 | # Returns the distance between points (x1,y1) and (x2,y2) |
| 336 | def distance((x1, y1), (x2, y2)): |
| 337 | return sqrt((x2-x1)**2 + (y2-y1)**2) |
| 338 | |
| 339 | # Returns an angle (in radians) when sides a and b |
| 340 | # are adjacent and the side c is opposite to the angle |
| 341 | def angle(a, b, c): |
| 342 | a,b,c = map(float,[a,b,c]) |
| 343 | return acos((b**2 + c**2 - a**2)/(2.0*b*c)) |
| 344 | |
| 345 | # Returns the area of a triangle when an angle alpha |
| 346 | # and adjacent sides a and b are known |
| 347 | def area(alpha, a, b): |
| 348 | return 1.0/2.0*a*b*sin(alpha) |
| 349 | |
| 350 | xy = [0]*3 |
| 351 | html('<h2>Trigonometric Properties of a Triangle</h2>') |
| 352 | # Coordinates of the angles |
| 353 | a = map(lambda x : math.radians(float(x)), [a0, a1, a2]) |
| 354 | for i in range(3): |
| 355 | xy[i] = (cos(a[i]), sin(a[i])) |
| 356 | |
| 357 | # Side lengths (bc, ca, ab) corresponding to triangle vertices (a, b, c) |
| 358 | al = [distance(xy[1], xy[2]), distance(xy[2], xy[0]), distance(xy[0], xy[1])] |
| 359 | |
| 360 | # The angles (a, b, c) in radians |
| 361 | ak = [angle(al[0], al[1], al[2]), angle(al[1], al[2], al[0]), angle(al[2], al[0], al[1])] |
| 362 | |
| 363 | # The area of the triangle |
| 364 | A = area(ak[0], al[1], al[2]) |
| 365 | |
| 366 | unit_circle = circle((0, 0), 1, aspect_ratio=1) |
| 367 | |
| 368 | # Triangle |
| 369 | triangle = line([xy[0], xy[1], xy[2], xy[0]], rgbcolor="black") |
| 370 | triangle_points = point(xy, pointsize=30) |
| 371 | |
| 372 | # Labels of the angles drawn in a distance from points |
| 373 | a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) |
| 374 | b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) |
| 375 | c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) |
| 376 | labels = a_label + b_label + c_label |
| 377 | |
| 378 | show(unit_circle + triangle + triangle_points + labels, figsize=[5, 5], xmin=-1, xmax=1, ymin=-1, ymax=1) |
| 379 | angl_txt = r"$\angle A = {%s}^{\circ},$ $\angle B = {%s}^{\circ},$ $\angle C = {%s}^{\circ}$" % ( |
| 380 | math.degrees(ak[0]), |
| 381 | math.degrees(ak[1]), |
| 382 | math.degrees(ak[2]) |
| 383 | ) |
| 384 | html(angl_txt) |
| 385 | html(r"$AB = %s,$ $BC = %s,$ $CA = %s$"%(al[2], al[0], al[1])) |
| 386 | html(r"$\text{Area A} = %s$"%A) |
| 387 | |
| 388 | @library_interact |
| 389 | def unit_circle( |
| 390 | function = selector([(0, sin(x)), (1, cos(x)), (2, tan(x))]), |
| 391 | x = slider(0,2*pi, 0.005*pi, 0)): |
| 392 | """ |
| 393 | This is an interact for Sin, Cos and Tan in the Unit Circle |
| 394 | based on work by Lauri Ruotsalainen, 2010. |
| 395 | |
| 396 | INPUT: |
| 397 | |
| 398 | - ``function`` -- select Sin, Cos or Tan |
| 399 | - ``x`` -- slider to select angle in unit circle |
| 400 | |
| 401 | EXAMPLES:: |
| 402 | |
| 403 | sage: interacts.geometry.unit_circle() |
| 404 | <html>...</html> |
| 405 | """ |
| 406 | xy = (cos(x), sin(x)) |
| 407 | t = SR.var('t') |
| 408 | html('<div style="white-space: normal;">Lines of the same color have\ |
| 409 | the same length</div>') |
| 410 | |
| 411 | # Unit Circle |
| 412 | C = circle((0, 0), 1, figsize=[5, 5], aspect_ratio=1) |
| 413 | C_line = line([(0, 0), (xy[0], xy[1])], rgbcolor="black") |
| 414 | C_point = point((xy[0], xy[1]), pointsize=40, rgbcolor="green") |
| 415 | C_inner = parametric_plot((cos(t), sin(t)), (t, 0, x + 0.001), color="green", thickness=3) |
| 416 | C_outer = parametric_plot((0.1 * cos(t), 0.1 * sin(t)), (t, 0, x + 0.001), color="black") |
| 417 | C_graph = C + C_line + C_point + C_inner + C_outer |
| 418 | |
| 419 | # Graphics related to the graph of the function |
| 420 | G_line = line([(0, 0), (x, 0)], rgbcolor="green", thickness=3) |
| 421 | G_point = point((x, 0), pointsize=30, rgbcolor="green") |
| 422 | G_graph = G_line + G_point |
| 423 | |
| 424 | # Sine |
| 425 | if function == 0: |
| 426 | Gf = plot(sin(t), t, 0, 2*pi, axes_labels=("x", "sin(x)")) |
| 427 | Gf_point = point((x, sin(x)), pointsize=30, rgbcolor="red") |
| 428 | Gf_line = line([(x, 0),(x, sin(x))], rgbcolor="red") |
| 429 | Cf_point = point((0, xy[1]), pointsize=40, rgbcolor="red") |
| 430 | Cf_line1 = line([(0, 0), (0, xy[1])], rgbcolor="red", thickness=3) |
| 431 | Cf_line2 = line([(0, xy[1]), (xy[0], xy[1])], rgbcolor="purple", linestyle="--") |
| 432 | # Cosine |
| 433 | elif function == 1: |
| 434 | Gf = plot(cos(t), t, 0, 2*pi, axes_labels=("x", "cos(x)")) |
| 435 | Gf_point = point((x, cos(x)), pointsize=30, rgbcolor="red") |
| 436 | Gf_line = line([(x, 0), (x, cos(x))], rgbcolor="red") |
| 437 | Cf_point = point((xy[0], 0), pointsize=40, rgbcolor="red") |
| 438 | Cf_line1 = line([(0, 0), (xy[0], 0)], rgbcolor="red", thickness=3) |
| 439 | Cf_line2 = line([(xy[0], 0), (xy[0], xy[1])], rgbcolor="purple", linestyle="--") |
| 440 | # Tangent |
| 441 | else: |
| 442 | Gf = plot(tan(t), t, 0, 2*pi, ymin=-8, ymax=8, axes_labels=("x", "tan(x)")) |
| 443 | Gf_point = point((x, tan(x)), pointsize=30, rgbcolor="red") |
| 444 | Gf_line = line([(x, 0), (x, tan(x))], rgbcolor="red") |
| 445 | Cf_point = point((1, tan(x)), pointsize=40, rgbcolor="red") |
| 446 | Cf_line1 = line([(1, 0), (1, tan(x))], rgbcolor="red", thickness=3) |
| 447 | Cf_line2 = line([(xy[0], xy[1]), (1, tan(x))], rgbcolor="purple", linestyle="--") |
| 448 | |
| 449 | C_graph += Cf_point + Cf_line1 + Cf_line2 |
| 450 | G_graph += Gf + Gf_point + Gf_line |
| 451 | |
| 452 | html.table([[r"$\text{Unit Circle}$",r"$\text{Function}$"], [C_graph, G_graph]], header=True) |
| 453 | |
| 454 | @library_interact |
| 455 | def cube_hemisphere(size = slider(0.5, 1, label="The Edge Length x:")): |
| 456 | """ |
| 457 | This interact demo shows a cube within a hemisphere |
| 458 | based on work by Lauri Ruotsalainen, 2010. |
| 459 | |
| 460 | INPUT: |
| 461 | |
| 462 | - ``size`` -- slider to select the edge length x |
| 463 | |
| 464 | EXAMPLES:: |
| 465 | |
| 466 | sage: interacts.geometry.cube_hemisphere() |
| 467 | <html>...</html> |
| 468 | """ |
| 469 | html('<h2>Cube within a Hemisphere</h2>') |
| 470 | html('<div style="white-space: normal">A cube is placed within a hemisphere so that the corners ' +\ |
| 471 | 'of the cube touch the surface of the hemisphere; Observe numerically ' + \ |
| 472 | 'the ratio of the volume of the cube and the volume of the hemisphere.</div>') |
| 473 | x, y, z = SR.var("x,y,z") |
| 474 | 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) |
| 475 | cube_graph = cube(size=size, opacity=0.9, color="red", frame_thickness=1).translate((0, 0, size/2.0)) |
| 476 | surface_graph = plot3d(0, (x, -1.2, 1.2),(y, -1.2, 1.2), color="lightblue", opacity=0.6) |
| 477 | show(hemisphere_graph + cube_graph + surface_graph, aspect_ratio=1) |
| 478 | |
| 479 | V_c = size**3 |
| 480 | V_hs = 4*pi*1**3/6.0 |
| 481 | html(r"$\text{Volume of the Cube: }V_{cube} = x^3 = {%.5f}^3 = %s" % (N(size, digits=5), N(V_c, digits=5))) |
| 482 | 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)) |
| 483 | 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))) |
| 484 | |
| 485 | |
| 486 | @library_interact |
| 487 | def special_points( |
| 488 | title = text_control('<h2>Special points in triangle</h2>'), |
| 489 | a0 = slider(0, 360, 1, 30, label="A"), |
| 490 | a1 = slider(0, 360, 1, 180, label="B"), |
| 491 | a2 = slider(0, 360, 1, 300, label="C"), |
| 492 | show_median = checkbox(False, label="Medians"), |
| 493 | show_pb = checkbox(False, label="Perpendicular Bisectors"), |
| 494 | show_alt = checkbox(False, label="Altitudes"), |
| 495 | show_ab = checkbox(False, label="Angle Bisectors"), |
| 496 | show_incircle = checkbox(False, label="Incircle"), |
| 497 | show_euler = checkbox(False, label="Euler's Line")): |
| 498 | """ |
| 499 | This interact demo shows special points in a triangle |
| 500 | based on work by Lauri Ruotsalainen, 2010. |
| 501 | |
| 502 | INPUT: |
| 503 | |
| 504 | - ``a0`` -- angle |
| 505 | - ``a1`` -- angle |
| 506 | - ``a2`` -- angle |
| 507 | - ``show_median`` -- checkbox |
| 508 | - ``show_pb`` -- checkbox to show perpendicular bisectors |
| 509 | - ``show_alt`` -- checkbox to show altitudes |
| 510 | - ``show_ab`` -- checkbox to show angle bisectors |
| 511 | - ``show_incircle`` -- checkbox to show incircle |
| 512 | - ``show_euler`` -- checkbox to show euler's line |
| 513 | |
| 514 | EXAMPLES:: |
| 515 | |
| 516 | sage: interacts.geometry.special_points() |
| 517 | <html>...</html> |
| 518 | """ |
| 519 | import math |
| 520 | # Return the intersection point of the bisector of the angle <(A[a],A[c],A[b]) and the unit circle. Angles given in radians. |
| 521 | def half(A, a, b, c): |
| 522 | 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])): |
| 523 | p = A[a] + (A[b] - A[a]) / 2.0 |
| 524 | else: |
| 525 | p = A[b] + (2*pi - (A[b]-A[a])) / 2.0 |
| 526 | return (math.cos(p), math.sin(p)) |
| 527 | |
| 528 | # Returns the distance between points (x1,y1) and (x2,y2) |
| 529 | def distance((x1, y1), (x2, y2)): |
| 530 | return math.sqrt((x2-x1)**2 + (y2-y1)**2) |
| 531 | |
| 532 | # Returns the line (graph) going through points (x1,y1) and (x2,y2) |
| 533 | def line_to_points((x1, y1), (x2, y2), **plot_kwargs): |
| 534 | return plot((y2-y1) / (x2-x1) * (x-x1) + y1, (x,-3,3), **plot_kwargs) |
| 535 | |
| 536 | # Coordinates of the angles |
| 537 | a = map(lambda x : math.radians(float(x)), [a0, a1, a2]) |
| 538 | xy = [(math.cos(a[i]), math.sin(a[i])) for i in range(3)] |
| 539 | |
| 540 | # Labels of the angles drawn in a distance from points |
| 541 | a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) |
| 542 | b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) |
| 543 | c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) |
| 544 | labels = a_label + b_label + c_label |
| 545 | |
| 546 | C = circle((0, 0), 1, aspect_ratio=1) |
| 547 | |
| 548 | # Triangle |
| 549 | triangle = line([xy[0], xy[1], xy[2], xy[0]], rgbcolor="black") |
| 550 | triangle_points = point(xy, pointsize=30) |
| 551 | |
| 552 | # Side lengths (bc, ca, ab) corresponding to triangle vertices (a, b, c) |
| 553 | ad = [distance(xy[1], xy[2]), distance(xy[2], xy[0]), distance(xy[0], xy[1])] |
| 554 | |
| 555 | # Midpoints of edges (bc, ca, ab) |
| 556 | a_middle = [ |
| 557 | ((xy[1][0] + xy[2][0])/2.0, (xy[1][1] + xy[2][1])/2.0), |
| 558 | ((xy[2][0] + xy[0][0])/2.0, (xy[2][1] + xy[0][1])/2.0), |
| 559 | ((xy[0][0] + xy[1][0])/2.0, (xy[0][1] + xy[1][1])/2.0) |
| 560 | ] |
| 561 | |
| 562 | # Incircle |
| 563 | perimeter = float(ad[0] + ad[1] + ad[2]) |
| 564 | incircle_center = ( |
| 565 | (ad[0]*xy[0][0] + ad[1]*xy[1][0] + ad[2]*xy[2][0]) / perimeter, |
| 566 | (ad[0]*xy[0][1] + ad[1]*xy[1][1] + ad[2]*xy[2][1]) / perimeter |
| 567 | ) |
| 568 | |
| 569 | if show_incircle: |
| 570 | s = perimeter/2.0 |
| 571 | incircle_r = math.sqrt((s - ad[0]) * (s - ad[1]) * (s - ad[2]) / s) |
| 572 | incircle_graph = circle(incircle_center, incircle_r) + point(incircle_center) |
| 573 | else: |
| 574 | incircle_graph = Graphics() |
| 575 | |
| 576 | # Angle Bisectors |
| 577 | if show_ab: |
| 578 | a_ab = line([xy[0], half(a, 1, 2, 0)], rgbcolor="blue", alpha=0.6) |
| 579 | b_ab = line([xy[1], half(a, 2, 0, 1)], rgbcolor="blue", alpha=0.6) |
| 580 | c_ab = line([xy[2], half(a, 0, 1, 2)], rgbcolor="blue", alpha=0.6) |
| 581 | ab_point = point(incircle_center, rgbcolor="blue", pointsize=28) |
| 582 | ab_graph = a_ab + b_ab + c_ab + ab_point |
| 583 | else: |
| 584 | ab_graph = Graphics() |
| 585 | |
| 586 | # Medians |
| 587 | if show_median: |
| 588 | a_median = line([xy[0], a_middle[0]], rgbcolor="green", alpha=0.6) |
| 589 | b_median = line([xy[1], a_middle[1]], rgbcolor="green", alpha=0.6) |
| 590 | c_median = line([xy[2], a_middle[2]], rgbcolor="green", alpha=0.6) |
| 591 | median_point = point( |
| 592 | ( |
| 593 | (xy[0][0]+xy[1][0]+xy[2][0])/3.0, |
| 594 | (xy[0][1]+xy[1][1]+xy[2][1])/3.0 |
| 595 | ), rgbcolor="green", pointsize=28) |
| 596 | median_graph = a_median + b_median + c_median + median_point |
| 597 | else: |
| 598 | median_graph = Graphics() |
| 599 | |
| 600 | # Perpendicular Bisectors |
| 601 | if show_pb: |
| 602 | a_pb = line_to_points(a_middle[0], half(a, 1, 2, 0), rgbcolor="red", alpha=0.6) |
| 603 | b_pb = line_to_points(a_middle[1], half(a, 2, 0, 1), rgbcolor="red", alpha=0.6) |
| 604 | c_pb = line_to_points(a_middle[2], half(a, 0, 1, 2), rgbcolor="red", alpha=0.6) |
| 605 | pb_point = point((0, 0), rgbcolor="red", pointsize=28) |
| 606 | pb_graph = a_pb + b_pb + c_pb + pb_point |
| 607 | else: |
| 608 | pb_graph = Graphics() |
| 609 | |
| 610 | # Altitudes |
| 611 | if show_alt: |
| 612 | xA, xB, xC = xy[0][0], xy[1][0], xy[2][0] |
| 613 | yA, yB, yC = xy[0][1], xy[1][1], xy[2][1] |
| 614 | a_alt = plot(((xC-xB)*x+(xB-xC)*xA)/(yB-yC)+yA, (x,-3,3), rgbcolor="brown", alpha=0.6) |
| 615 | b_alt = plot(((xA-xC)*x+(xC-xA)*xB)/(yC-yA)+yB, (x,-3,3), rgbcolor="brown", alpha=0.6) |
| 616 | c_alt = plot(((xB-xA)*x+(xA-xB)*xC)/(yA-yB)+yC, (x,-3,3), rgbcolor="brown", alpha=0.6) |
| 617 | 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) |
| 618 | 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) |
| 619 | alt_intersection = point((alt_lx, alt_ly), rgbcolor="brown", pointsize=28) |
| 620 | alt_graph = a_alt + b_alt + c_alt + alt_intersection |
| 621 | else: |
| 622 | alt_graph = Graphics() |
| 623 | |
| 624 | # Euler's Line |
| 625 | if show_euler: |
| 626 | euler_graph = line_to_points( |
| 627 | (0, 0), |
| 628 | ( |
| 629 | (xy[0][0]+xy[1][0]+xy[2][0])/3.0, |
| 630 | (xy[0][1]+xy[1][1]+xy[2][1])/3.0 |
| 631 | ), |
| 632 | rgbcolor="purple", |
| 633 | thickness=2, |
| 634 | alpha=0.7 |
| 635 | ) |
| 636 | else: |
| 637 | euler_graph = Graphics() |
| 638 | |
| 639 | show( |
| 640 | C + triangle + triangle_points + labels + ab_graph + median_graph + |
| 641 | pb_graph + alt_graph + incircle_graph + euler_graph, |
| 642 | figsize=[5,5], xmin=-1, xmax=1, ymin=-1, ymax=1 |
| 643 | ) |
| 644 | |
| 645 | |
| 646 | @library_interact |
| 647 | 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)")): |
| 648 | """ |
| 649 | This interact demo simulates repeated tosses of a coin, |
| 650 | based on work by Lauri Ruotsalainen, 2010. |
| 651 | |
| 652 | INPUT: |
| 653 | |
| 654 | - ``n`` -- number of tosses |
| 655 | - ``interval`` -- plot range (y) |
| 656 | |
| 657 | EXAMPLES:: |
| 658 | |
| 659 | sage: interacts.statistics.coin() |
| 660 | <html>...</html> |
| 661 | """ |
| 662 | from random import random |
| 663 | c = [] |
| 664 | k = 0.0 |
| 665 | for i in range(1, n + 1): |
| 666 | k += random() |
| 667 | c.append((i, k/i)) |
| 668 | show(point(c[1:], gridlines=[None, [0.5]], pointsize=1), ymin=interval[0], ymax=interval[1]) |
| 669 | |
| 670 | |
| 671 | @library_interact |
| 672 | def bisection_method( |
| 673 | title = text_control('<h2>Bisection method</h2>'), |
| 674 | f = input_box("x^2-2", label='f(x)'), |
| 675 | interval = range_slider(-5,5,default=(0, 4), label="range"), |
| 676 | d = slider(1, 8, 1, 3, label="10^-d precision"), |
| 677 | maxn = slider(0,50,1,10, label="max iterations")): |
| 678 | """ |
| 679 | Interact explaining the bisection method, based on similar interact |
| 680 | explaining secant method and Wiliam Stein's example from wiki. |
| 681 | |
| 682 | INPUT: |
| 683 | |
| 684 | - ``f`` -- function |
| 685 | - ``interval`` -- range slider for the search interval |
| 686 | - ``d`` -- slider for the precision (10^-d) |
| 687 | - ``maxn`` -- max number of iterations |
| 688 | |
| 689 | EXAMPLES:: |
| 690 | |
| 691 | sage: interacts.calculus.secant_method() |
| 692 | <html>...</html> |
| 693 | """ |
| 694 | def _bisection_method(f, a, b, maxn, eps): |
| 695 | intervals = [(a,b)] |
| 696 | round = 1 |
| 697 | two = float(2) |
| 698 | while True: |
| 699 | c = (b+a)/two |
| 700 | if abs(f(c)) < h or round >= maxn: |
| 701 | break |
| 702 | fa = f(a); fb = f(b); fc = f(c) |
| 703 | if abs(fc) < eps: |
| 704 | return c, intervals |
| 705 | if fa*fc < 0: |
| 706 | a, b = a, c |
| 707 | elif fc*fb < 0: |
| 708 | a, b = c, b |
| 709 | else: |
| 710 | raise ValueError, "f must have a sign change in the interval (%s,%s)"%(a,b) |
| 711 | intervals.append((a,b)) |
| 712 | round += 1 |
| 713 | return c, intervals |
| 714 | |
| 715 | x = SR.var('x') |
| 716 | f = symbolic_expression(f).function(x) |
| 717 | a, b = interval |
| 718 | h = 10**(-d) |
| 719 | try: |
| 720 | c, intervals = _bisection_method(f, float(a), float(b), maxn, h) |
| 721 | except ValueError: |
| 722 | print "f must have opposite sign at the endpoints of the interval" |
| 723 | show(plot(f, a, b, color='red'), xmin=a, xmax=b) |
| 724 | else: |
| 725 | html(r"$\text{Precision }h = 10^{-d}=10^{-%s}=%.5f$"%(d, float(h))) |
| 726 | html(r"${c = }%s$"%latex(c)) |
| 727 | html(r"${f(c) = }%s"%latex(f(c))) |
| 728 | html(r"$%s \text{ iterations}"%len(intervals)) |
| 729 | P = plot(f, a, b, color='red') |
| 730 | k = (P.ymax() - P.ymin())/ (1.5*len(intervals)) |
| 731 | L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) |
| 732 | L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) |
| 733 | L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) |
| 734 | show(P + L, xmin=a, xmax=b) |
| 735 | |
| 736 | @library_interact |
| 737 | def secant_method( |
| 738 | title = text_control('<h2>Secant method</h2>'), |
| 739 | f = input_box("x^2-2", label='f(x)'), |
| 740 | interval = range_slider(-5,5,default=(0, 4), label="range"), |
| 741 | d = slider(1, 16, 1, 3, label="10^-d precision"), |
| 742 | maxn = slider(0,15,1,10, label="max iterations")): |
| 743 | """ |
| 744 | Interact explaining the secant method, based on work by |
| 745 | Lauri Ruotsalainen, 2010. |
| 746 | Originally this is based on work by William Stein. |
| 747 | |
| 748 | INPUT: |
| 749 | |
| 750 | - ``f`` -- function |
| 751 | - ``interval`` -- range slider for the search interval |
| 752 | - ``d`` -- slider for the precision (10^-d) |
| 753 | - ``maxn`` -- max number of iterations |
| 754 | |
| 755 | EXAMPLES:: |
| 756 | |
| 757 | sage: interacts.calculus.secant_method() |
| 758 | <html>...</html> |
| 759 | """ |
| 760 | def _secant_method(f, a, b, maxn, h): |
| 761 | intervals = [(a,b)] |
| 762 | round = 1 |
| 763 | while True: |
| 764 | c = b-(b-a)*f(b)/(f(b)-f(a)) |
| 765 | if abs(f(c)) < h or round >= maxn: |
| 766 | break |
| 767 | a, b = b, c |
| 768 | intervals.append((a,b)) |
| 769 | round += 1 |
| 770 | return c, intervals |
| 771 | |
| 772 | x = SR.var('x') |
| 773 | f = symbolic_expression(f).function(x) |
| 774 | a, b = interval |
| 775 | h = 10**(-d) |
| 776 | if float(f(a)*f(b)) > 0: |
| 777 | print "f must have opposite sign at the endpoints of the interval" |
| 778 | show(plot(f, a, b, color='red'), xmin=a, xmax=b) |
| 779 | else: |
| 780 | c, intervals = _secant_method(f, float(a), float(b), maxn, h) |
| 781 | html(r"$\text{Precision }h = 10^{-d}=10^{-%s}=%.5f$"%(d, float(h))) |
| 782 | html(r"${c = }%s$"%latex(c)) |
| 783 | html(r"${f(c) = }%s"%latex(f(c))) |
| 784 | html(r"$%s \text{ iterations}"%len(intervals)) |
| 785 | P = plot(f, a, b, color='red') |
| 786 | k = (P.ymax() - P.ymin())/ (1.5*len(intervals)) |
| 787 | L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) |
| 788 | L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) |
| 789 | L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) |
| 790 | 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) |
| 791 | show(P + L + S, xmin=a, xmax=b) |
| 792 | |
| 793 | @library_interact |
| 794 | def newton_method( |
| 795 | title = text_control('<h2>Newton method</h2>'), |
| 796 | f = input_box("x^2 - 2"), |
| 797 | c = slider(-10,10, default=6, label='Start (x)'), |
| 798 | d = slider(1, 16, 1, 3, label="10^-d precision"), |
| 799 | maxn = slider(0, 15, 1, 10, label="max iterations"), |
| 800 | interval = range_slider(-10,10, default = (0,6), label="Interval"), |
| 801 | list_steps = checkbox(default=False, label="List steps")): |
| 802 | """ |
| 803 | Interact explaining the newton method, based on work by |
| 804 | Lauri Ruotsalainen, 2010. |
| 805 | Originally this is based on work by William Stein. |
| 806 | |
| 807 | INPUT: |
| 808 | |
| 809 | - ``f`` -- function |
| 810 | - ``c`` -- starting position (x) |
| 811 | - ``d`` -- slider for the precision (10^-d) |
| 812 | - ``maxn`` -- max number of iterations |
| 813 | - ``interval`` -- range slider for the search interval |
| 814 | - ``list_steps`` -- checkbox, if true shows the steps numerically |
| 815 | |
| 816 | EXAMPLES:: |
| 817 | |
| 818 | sage: interacts.calculus.newton_method() |
| 819 | <html>...</html> |
| 820 | """ |
| 821 | def _newton_method(f, c, maxn, h): |
| 822 | midpoints = [c] |
| 823 | round = 1 |
| 824 | while True: |
| 825 | c = c-f(c)/f.derivative(x)(x=c) |
| 826 | midpoints.append(c) |
| 827 | if f(c-h)*f(c+h) < 0 or round == maxn: |
| 828 | break |
| 829 | round += 1 |
| 830 | return c, midpoints |
| 831 | |
| 832 | x = SR.var('x') |
| 833 | f = symbolic_expression(f).function(x) |
| 834 | a, b = interval |
| 835 | h = 10**(-d) |
| 836 | c, midpoints = _newton_method(f, float(c), maxn, h/2.0) |
| 837 | html(r"$\text{Precision } 2h = %s$"%latex(float(h))) |
| 838 | html(r"${c = }%s$"%c) |
| 839 | html(r"${f(c) = }%s"%latex(f(c))) |
| 840 | html(r"$%s \text{ iterations}"%len(midpoints)) |
| 841 | if list_steps: |
| 842 | s = [["$n$","$x_n$","$f(x_n)$", "$f(x_n-h)\,f(x_n+h)$"]] |
| 843 | for i, c in enumerate(midpoints): |
| 844 | s.append([i+1, c, f(c), (c-h)*f(c+h)]) |
| 845 | html.table(s,header=True) |
| 846 | else: |
| 847 | P = plot(f, x, interval, color="blue") |
| 848 | L = sum(line([(c, 0), (c, f(c))], color="green") for c in midpoints[:-1]) |
| 849 | for i in range(len(midpoints) - 1): |
| 850 | L += line([(midpoints[i], f(midpoints[i])), (midpoints[i+1], 0)], color="red") |
| 851 | show(P + L, xmin=interval[0], xmax=interval[1], ymin=P.ymin(), ymax=P.ymax()) |
| 852 | |
| 853 | @library_interact |
| 854 | def trapezoid_integration( |
| 855 | title = text_control('<h2>Trapeziod integration</h2>'), |
| 856 | f = input_box(default = "x^2-5*x + 10", label='$f(x)=$'), |
| 857 | n = slider(1,100,1,5, label='# divisions'), |
| 858 | interval_input = selector(['from slider','from keyboard'], label='Integration interval', buttons=True), |
| 859 | interval_s = range_slider(-10,10,default=(0,8), label="slider: "), |
| 860 | interval_g = input_grid(1,2,default=[[0,8]], label="keyboard: "), |
| 861 | output_form = selector(['traditional','table','none'], label='Computations form', buttons=True) |
| 862 | ): |
| 863 | """ |
| 864 | Interact explaining the trapezoid method for definite integrals, based on work by |
| 865 | Lauri Ruotsalainen, 2010 (based on the application "Numerical integrals with various rules" |
| 866 | by Marshall Hampton and Nick Alexander) |
| 867 | |
| 868 | INPUT: |
| 869 | |
| 870 | - ``f`` -- function of variable x to integrate |
| 871 | - ``n`` -- number of divisions |
| 872 | - ``interval_input`` -- swithes the input for interval between slider and keyboard |
| 873 | - ``interval_s`` -- slider for interval to integrate |
| 874 | - ``interval_g`` -- input grid for interval to integrate |
| 875 | - ``output_form`` -- the computation is formatted in a traditional form, in a table or missing |
| 876 | |
| 877 | EXAMPLES:: |
| 878 | |
| 879 | sage: interacts.calculus.trapezoid_integration() |
| 880 | <html>...</html> |
| 881 | """ |
| 882 | xs = [] |
| 883 | ys = [] |
| 884 | if interval_input == 'from slider': |
| 885 | interval = interval_s |
| 886 | else: |
| 887 | interval = interval_g[0] |
| 888 | h = float(interval[1]-interval[0])/n |
| 889 | x = SR.var('x') |
| 890 | f = symbolic_expression(f).function(x) |
| 891 | |
| 892 | trapezoids = Graphics() |
| 893 | |
| 894 | for i in range(n): |
| 895 | xi = interval[0] + i*h |
| 896 | yi = f(xi) |
| 897 | trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)],[xi + h, 0],[xi, 0]], rgbcolor = (1,0,0)) |
| 898 | xs.append(xi) |
| 899 | ys.append(yi) |
| 900 | xs.append(xi + h) |
| 901 | ys.append(f(xi + h)) |
| 902 | |
| 903 | html(r'Function $f(x)=%s$'%latex(f(x))) |
| 904 | show(plot(f, interval[0], interval[1]) + trapezoids, xmin = interval[0], xmax = interval[1]) |
| 905 | |
| 906 | numeric_value = integral_numerical(f, interval[0], interval[1])[0] |
| 907 | approx = h *(ys[0]/2 + sum([ys[i] for i in range(1,n)]) + ys[n]/2) |
| 908 | |
| 909 | html(r'$\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$'%( |
| 910 | interval[0], interval[1], N(numeric_value, digits=7)) |
| 911 | ) |
| 912 | |
| 913 | if output_form == 'traditional': |
| 914 | sum_formula_html = r"\frac {d}{2} \cdot \left[f(x_0) + %s + f(x_{%s})\right]" % ( |
| 915 | ' + '.join([ "2 f(x_{%s})"%i for i in range(1,n)]), |
| 916 | n |
| 917 | ) |
| 918 | sum_placement_html = r"\frac{%.2f}{2} \cdot \left[f(%.2f) + %s + f(%.2f)\right]" % ( |
| 919 | h, |
| 920 | N(xs[0], digits=5), |
| 921 | ' + '.join([ "2 f(%.2f)" %N(i, digits=5) for i in xs[1:-1]]), |
| 922 | N(xs[n], digits=5) |
| 923 | ) |
| 924 | sum_values_html = r"\frac{%.2f}{2} \cdot \left[%.2f + %s + %.2f\right]" % ( |
| 925 | h, |
| 926 | N(ys[0], digits=5), |
| 927 | ' + '.join([ "2\cdot %.2f" % N(i, digits=5) for i in ys[1:-1]]), |
| 928 | N(ys[n], digits=5) |
| 929 | ) |
| 930 | |
| 931 | html(r''' |
| 932 | <div class="math"> |
| 933 | \begin{align*} |
| 934 | \int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} |
| 935 | & \approx %s \\ |
| 936 | & = %s \\ |
| 937 | & = %s \\ |
| 938 | & = %s |
| 939 | \end{align*} |
| 940 | </div> |
| 941 | ''' % ( |
| 942 | interval[0], interval[1], |
| 943 | sum_formula_html, sum_placement_html, sum_values_html, |
| 944 | N(approx, digits=7) |
| 945 | )) |
| 946 | elif output_form == 'table': |
| 947 | s = [['$i$','$x_i$','$f(x_i)$','$m$','$m\cdot f(x_i)$']] |
| 948 | for i in range(0,n+1): |
| 949 | if i==0 or i==n: |
| 950 | j = 1 |
| 951 | else: |
| 952 | j = 2 |
| 953 | s.append([i, xs[i], ys[i],j,N(j*ys[i])]) |
| 954 | html.table(s,header=True) |
| 955 | |
| 956 | @library_interact |
| 957 | def simpson_integration( |
| 958 | title = text_control('<h2>Simpson integration</h2>'), |
| 959 | f = input_box(default = 'x*sin(x)+x+1', label='$f(x)=$'), |
| 960 | n = slider(2,100,2,6, label='# divisions'), |
| 961 | interval_input = selector(['from slider','from keyboard'], label='Integration interval', buttons=True), |
| 962 | interval_s = range_slider(-10,10,default=(0,10), label="slider: "), |
| 963 | interval_g = input_grid(1,2,default=[[0,10]], label="keyboard: "), |
| 964 | output_form = selector(['traditional','table','none'], label='Computations form', buttons=True)): |
| 965 | """ |
| 966 | Interact explaining the simpson method for definite integrals, based on work by |
| 967 | Lauri Ruotsalainen, 2010 (based on the application "Numerical integrals with various rules" |
| 968 | by Marshall Hampton and Nick Alexander) |
| 969 | |
| 970 | INPUT: |
| 971 | |
| 972 | - ``f`` -- function of variable x to integrate |
| 973 | - ``n`` -- number of divisions (mult. of 2) |
| 974 | - ``interval_input`` -- swithes the input for interval between slider and keyboard |
| 975 | - ``interval_s`` -- slider for interval to integrate |
| 976 | - ``interval_g`` -- input grid for interval to integrate |
| 977 | - ``output_form`` -- the computation is formatted in a traditional form, in a table or missing |
| 978 | |
| 979 | EXAMPLES:: |
| 980 | |
| 981 | sage: interacts.calculus.simpson_integration() |
| 982 | <html>...</html> |
| 983 | """ |
| 984 | x = SR.var('x') |
| 985 | f = symbolic_expression(f).function(x) |
| 986 | if interval_input == 'from slider': |
| 987 | interval = interval_s |
| 988 | else: |
| 989 | interval = interval_g[0] |
| 990 | def parabola(a, b, c): |
| 991 | from sage.all import solve |
| 992 | A, B, C = SR.var("A, B, C") |
| 993 | 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] |
| 994 | f = K[A]*x**2+K[B]*x+K[C] |
| 995 | return f |
| 996 | xs = []; ys = [] |
| 997 | dx = float(interval[1]-interval[0])/n |
| 998 | |
| 999 | for i in range(n+1): |
| 1000 | xs.append(interval[0] + i*dx) |
| 1001 | ys.append(f(x=xs[-1])) |
| 1002 | |
| 1003 | parabolas = Graphics() |
| 1004 | lines = Graphics() |
| 1005 | |
| 1006 | for i in range(0, n-1, 2): |
| 1007 | p = parabola((xs[i],ys[i]),(xs[i+1],ys[i+1]),(xs[i+2],ys[i+2])) |
| 1008 | parabolas += plot(p(x=x), (x, xs[i], xs[i+2]), color="red") |
| 1009 | lines += line([(xs[i],ys[i]), (xs[i],0), (xs[i+2],0)],color="red") |
| 1010 | lines += line([(xs[i+1],ys[i+1]), (xs[i+1],0)], linestyle="-.", color="red") |
| 1011 | |
| 1012 | lines += line([(xs[-1],ys[-1]), (xs[-1],0)], color="red") |
| 1013 | |
| 1014 | html(r'Function $f(x)=%s$'%latex(f(x))) |
| 1015 | |
| 1016 | show(plot(f(x),x,interval[0],interval[1]) + parabolas + lines, xmin = interval[0], xmax = interval[1]) |
| 1017 | |
| 1018 | numeric_value = integral_numerical(f,interval[0],interval[1])[0] |
| 1019 | 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]) |
| 1020 | |
| 1021 | html(r'$\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$'% |
| 1022 | (interval[0],interval[1], |
| 1023 | N(numeric_value,digits=7))) |
| 1024 | |
| 1025 | if output_form == 'traditional': |
| 1026 | sum_formula_html = r"\frac{d}{3} \cdot \left[ f(x_0) + %s + f(x_{%s})\right]" % ( |
| 1027 | ' + '.join([ r"%s \cdot f(x_{%s})" %(i%2*(-2)+4, i+1) for i in range(0,n-1)]), |
| 1028 | n |
| 1029 | ) |
| 1030 | |
| 1031 | sum_placement_html = r"\frac{%.2f}{3} \cdot \left[ f(%.2f) + %s + f(%.2f)\right]" % ( |
| 1032 | dx, |
| 1033 | N(xs[0],digits=5), |
| 1034 | ' + '.join([ r"%s \cdot f(%.2f)" %(i%2*(-2)+4, N(xk, digits=5)) for i, xk in enumerate(xs[1:-1])]), |
| 1035 | N(xs[n],digits=5) |
| 1036 | ) |
| 1037 | |
| 1038 | sum_values_html = r"\frac{%.2f}{3} \cdot \left[ %s %s %s\right]" %( |
| 1039 | dx, |
| 1040 | "%.2f + "%N(ys[0],digits=5), |
| 1041 | ' + '.join([ r"%s \cdot %.2f" %(i%2*(-2)+4, N(yk, digits=5)) for i, yk in enumerate(ys[1:-1])]), |
| 1042 | " + %.2f"%N(ys[n],digits=5) |
| 1043 | ) |
| 1044 | |
| 1045 | html(r''' |
| 1046 | <div class="math"> |
| 1047 | \begin{align*} |
| 1048 | \int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} |
| 1049 | & \approx %s \\ |
| 1050 | & = %s \\ |
| 1051 | & = %s \\ |
| 1052 | & = %.6f |
| 1053 | \end{align*} |
| 1054 | </div> |
| 1055 | ''' % ( |
| 1056 | interval[0], interval[1], |
| 1057 | sum_formula_html, sum_placement_html, sum_values_html, |
| 1058 | N(approx,digits=7) |
| 1059 | )) |
| 1060 | elif output_form == 'table': |
| 1061 | s = [['$i$','$x_i$','$f(x_i)$','$m$','$m\cdot f(x_i)$']] |
| 1062 | for i in range(0,n+1): |
| 1063 | if i==0 or i==n: |
| 1064 | j = 1 |
| 1065 | else: |
| 1066 | j = (i+1)%2*(-2)+4 |
| 1067 | s.append([i, xs[i], ys[i],j,N(j*ys[i])]) |
| 1068 | s.append(['','','','$\sum$','$%s$'%latex(3/dx*approx)]) |
| 1069 | html.table(s,header=True) |
| 1070 | html(r'$\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x}\approx\frac {%.2f}{3}\cdot %s=%s$'% |
| 1071 | (interval[0], interval[1],dx,latex(3/dx*approx),latex(approx))) |
| 1072 | |
| 1073 | @library_interact |
| 1074 | def riemann_sum( |
| 1075 | title = text_control('<h2>Riemann integral</h2>'), |
| 1076 | f = input_box("x^2+1", label = "$f(x)=$", width=40), |
| 1077 | n = slider(1,30,1,5, label='# divisions'), |
| 1078 | hr1 = text_control('<hr>'), |
| 1079 | interval_input = selector(['from slider','from keyboard'], label='Integration interval', buttons=True), |
| 1080 | interval_s = range_slider(-5,10,default=(0,2), label="slider: "), |
| 1081 | interval_g = input_grid(1,2,default=[[0,2]], label="keyboard: "), |
| 1082 | hr2 = text_control('<hr>'), |
| 1083 | list_table = checkbox(default=False, label="List table"), |
| 1084 | auto_update = False): |
| 1085 | """ |
| 1086 | Interact explaining the definition of Riemann integral |
| 1087 | |
| 1088 | INPUT: |
| 1089 | |
| 1090 | - ``f`` -- function of variable x to integrate |
| 1091 | - ``n`` -- number of divisions |
| 1092 | - ``interval_input`` -- swithes the input for interval between slider and keyboard |
| 1093 | - ``interval_s`` -- slider for interval to integrate |
| 1094 | - ``interval_g`` -- input grid for interval to integrate |
| 1095 | - ``list_table`` -- print table with values of the function |
| 1096 | |
| 1097 | EXAMPLES:: |
| 1098 | |
| 1099 | sage: interacts.calculus.riemann_sum() |
| 1100 | <html>...</html> |
| 1101 | |
| 1102 | AUTHORS: |
| 1103 | |
| 1104 | - Robert Marik (08-2010) |
| 1105 | """ |
| 1106 | x = SR.var('x') |
| 1107 | from random import random |
| 1108 | if interval_input == 'from slider': |
| 1109 | a = interval_s[0] |
| 1110 | b = interval_s[1] |
| 1111 | else: |
| 1112 | a = interval_g[0][0] |
| 1113 | b = interval_g[0][1] |
| 1114 | func = symbolic_expression(f).function(x) |
| 1115 | division = [a]+[a+random()*(b-a) for i in range(n-1)]+[b] |
| 1116 | division = [i for i in division] |
| 1117 | division.sort() |
| 1118 | xs = [division[i]+random()*(division[i+1]-division[i]) for i in range(n)] |
| 1119 | ys = [func(x_val) for x_val in xs] |
| 1120 | rects = Graphics() |
| 1121 | for i in range(n): |
| 1122 | body=[[division[i],0],[division[i],ys[i]],[division[i+1],ys[i]],[division[i+1],0]] |
| 1123 | if ys[i].n()>0: |
| 1124 | color_rect='green' |
| 1125 | else: |
| 1126 | color_rect='red' |
| 1127 | rects = rects +polygon2d(body, rgbcolor = color_rect,alpha=0.1)\ |
| 1128 | + point((xs[i],ys[i]), rgbcolor = (1,0,0))\ |
| 1129 | + line(body,rgbcolor='black',zorder=-1) |
| 1130 | html('<small>Adjust your data and click Update button. Click repeatedly for another random values.</small>') |
| 1131 | |
| 1132 | show(plot(func(x),(x,a,b),zorder=5) + rects) |
| 1133 | delka_intervalu=[division[i+1]-division[i] for i in range(n)] |
| 1134 | if list_table: |
| 1135 | html.table([["$i$","$[x_{i-1},x_i]$","$\eta_i$","$f(\eta_i)$","$x_{i}-x_{i-1}$"]]\ |
| 1136 | +[[i+1,[division[i],division[i+1]],xs[i],ys[i],delka_intervalu[i]] for i in range(n)],\ |
| 1137 | header=True) |
| 1138 | |
| 1139 | html('Riemann sum: $\displaystyle\sum_{i=1}^{%s} f(\eta_i)(x_i-x_{i-1})=%s$ '% |
| 1140 | (latex(n),latex(sum([ys[i]*delka_intervalu[i] for i in range(n)])))) |
| 1141 | html('Exact value of the integral $\displaystyle\int_{%s}^{%s}%s\,\mathrm{d}x=%s$'% |
| 1142 | (latex(a),latex(b),latex(func(x)),latex(integral_numerical(func(x),a,b)[0]))) |
| 1143 | |
| 1144 | |
| 1145 | x = SR.var('x') |
| 1146 | @library_interact |
| 1147 | def function_tool(f=sin(x), g=cos(x), xrange=range_slider(-3,3,default=(0,1),label='x-range'), |
| 1148 | yrange='auto', |
| 1149 | a=1, |
| 1150 | action=selector(['f', 'df/dx', 'int f', 'num f', 'den f', '1/f', 'finv', |
| 1151 | 'f+a', 'f-a', 'f*a', 'f/a', 'f^a', 'f(x+a)', 'f(x*a)', |
| 1152 | 'f+g', 'f-g', 'f*g', 'f/g', 'f(g)'], |
| 1153 | width=15, nrows=5, label="h = "), |
| 1154 | do_plot = ("Draw Plots", True)): |
| 1155 | """ |
| 1156 | `Function Plotting Tool <http://wiki.sagemath.org/interact/calculus#Functiontool>`_ |
| 1157 | (by William Stein (?)) |
| 1158 | |
| 1159 | INPUT: |
| 1160 | |
| 1161 | - ``f`` -- function f(x) |
| 1162 | - ``g`` -- function g(x) |
| 1163 | - ``xrange`` -- range for plotting (x) |
| 1164 | - ``yrange`` -- range for plotting ('auto' is default, otherwise a tuple) |
| 1165 | - ``a`` -- factor ``a`` |
| 1166 | - ``action`` -- select given operation on or combination of functions |
| 1167 | - ``do_plot`` -- if true, a plot is drawn |
| 1168 | |
| 1169 | EXAMPLE:: |
| 1170 | |
| 1171 | sage: interacts.calculus.function_tool() |
| 1172 | <html>...</html> |
| 1173 | """ |
| 1174 | x = SR.var('x') |
| 1175 | try: |
| 1176 | f = SR(f); g = SR(g); a = SR(a) |
| 1177 | except TypeError, msg: |
| 1178 | print msg[-200:] |
| 1179 | print "Unable to make sense of f,g, or a as symbolic expressions in single variable x." |
| 1180 | return |
| 1181 | if not (isinstance(xrange, tuple) and len(xrange) == 2): |
| 1182 | xrange = (0,1) |
| 1183 | h = 0; lbl = '' |
| 1184 | if action == 'f': |
| 1185 | h = f |
| 1186 | lbl = 'f' |
| 1187 | elif action == 'df/dx': |
| 1188 | h = f.derivative(x) |
| 1189 | lbl = r'\frac{\mathrm{d}f}{\mathrm{d}x}' |
| 1190 | elif action == 'int f': |
| 1191 | h = f.integrate(x) |
| 1192 | lbl = r'\int f \,\mathrm{d}x' |
| 1193 | elif action == 'num f': |
| 1194 | h = f.numerator() |
| 1195 | lbl = r'\text{numer(f)}' |
| 1196 | elif action == 'den f': |
| 1197 | h = f.denominator() |
| 1198 | lbl = r'\text{denom(f)}' |
| 1199 | elif action == '1/f': |
| 1200 | h = 1/f |
| 1201 | lbl = r'\frac{1}{f}' |
| 1202 | elif action == 'finv': |
| 1203 | h = solve(f == var('y'), x)[0].rhs() |
| 1204 | lbl = 'f^{-1}(y)' |
| 1205 | elif action == 'f+a': |
| 1206 | h = f+a |
| 1207 | lbl = 'f + a' |
| 1208 | elif action == 'f-a': |
| 1209 | h = f-a |
| 1210 | lbl = 'f - a' |
| 1211 | elif action == 'f*a': |
| 1212 | h = f*a |
| 1213 | lbl = r'f \times a' |
| 1214 | elif action == 'f/a': |
| 1215 | h = f/a |
| 1216 | lbl = r'\frac{f}{a}' |
| 1217 | elif action == 'f^a': |
| 1218 | h = f**a |
| 1219 | lbl = 'f^a' |
| 1220 | elif action == 'f^a': |
| 1221 | h = f**a |
| 1222 | lbl = 'f^a' |
| 1223 | elif action == 'f(x+a)': |
| 1224 | h = f(x+a) |
| 1225 | lbl = 'f(x+a)' |
| 1226 | elif action == 'f(x*a)': |
| 1227 | h = f(x*a) |
| 1228 | lbl = 'f(xa)' |
| 1229 | elif action == 'f+g': |
| 1230 | h = f+g |
| 1231 | lbl = 'f + g' |
| 1232 | elif action == 'f-g': |
| 1233 | h = f-g |
| 1234 | lbl = 'f - g' |
| 1235 | elif action == 'f*g': |
| 1236 | h = f*g |
| 1237 | lbl = r'f \times g' |
| 1238 | elif action == 'f/g': |
| 1239 | h = f/g |
| 1240 | lbl = r'\frac{f}{g}' |
| 1241 | elif action == 'f(g)': |
| 1242 | h = f(g) |
| 1243 | lbl = 'f(g)' |
| 1244 | html('<center><font color="red">$f = %s$</font></center>'%latex(f)) |
| 1245 | html('<center><font color="green">$g = %s$</font></center>'%latex(g)) |
| 1246 | html('<center><font color="blue"><b>$h = %s = %s$</b></font></center>'%(lbl, latex(h))) |
| 1247 | if do_plot: |
| 1248 | P = plot(f, xrange, color='red', thickness=2) + \ |
| 1249 | plot(g, xrange, color='green', thickness=2) + \ |
| 1250 | plot(h, xrange, color='blue', thickness=2) |
| 1251 | if yrange == 'auto': |
| 1252 | show(P, xmin=xrange[0], xmax=xrange[1]) |
| 1253 | else: |
| 1254 | yrange = sage_eval(yrange) |
| 1255 | show(P, xmin=xrange[0], xmax=xrange[1], ymin=yrange[0], ymax=yrange[1]) |
| 1256 | |
| 1257 | @library_interact |
| 1258 | def julia(expo = slider(-10,10,0.1,2), |
| 1259 | c_real = slider(-2,2,0.01,0.5, label='real part const.'), |
| 1260 | c_imag = slider(-2,2,0.01,0.5, label='imag part const.'), |
| 1261 | iterations=slider(1,100,1,20, label='# iterations'), |
| 1262 | zoom_x = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom X'), |
| 1263 | zoom_y = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom Y'), |
| 1264 | plot_points = slider(20,400,20, default=150, label='plot points'), |
| 1265 | dpi = slider(20, 200, 10, default=80, label='dpi')): |
| 1266 | """ |
| 1267 | Julia Fractal, based on |
| 1268 | `Julia by Harald Schilly <http://wiki.sagemath.org/interact/fractal#Julia>`_. |
| 1269 | |
| 1270 | INPUT: |
| 1271 | |
| 1272 | - ``exponent`` -- exponent ``e`` in $z^e+c$ |
| 1273 | - ``c_real`` -- real part of the constant ``c`` |
| 1274 | - ``c_imag`` -- imaginary part of the constant ``c`` |
| 1275 | - ``iterations`` -- number of iterations |
| 1276 | - ``zoom_x`` -- range slider for zoom in x direction |
| 1277 | - ``zoom_y`` -- range slider for zoom in y direction |
| 1278 | - ``plot_points`` -- number of points to plot |
| 1279 | - ``dpi`` -- dots-per-inch parameter for the plot |
| 1280 | |
| 1281 | EXAMPLE:: |
| 1282 | |
| 1283 | sage: interacts.fractals.julia() |
| 1284 | <html>...</html> |
| 1285 | """ |
| 1286 | z = SR.var('z') |
| 1287 | I = CDF.gen() |
| 1288 | f = symbolic_expression(z**expo + c_real + c_imag*I).function(z) |
| 1289 | ff_j = fast_callable(f, vars=[z], domain=CDF) |
| 1290 | |
| 1291 | from sage.interacts.library_cython import julia |
| 1292 | |
| 1293 | html('<h2>Julia Fractal</h2>') |
| 1294 | html(r'Recursive Formula: $z \leftarrow z^{%.2f} + (%.2f+%.2f*\mathbb{I})$' % (expo, c_real, c_imag)) |
| 1295 | 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) |
| 1296 | |
| 1297 | @library_interact |
| 1298 | def mandelbrot(expo = slider(-10,10,0.1,2), |
| 1299 | iterations=slider(1,100,1,20, label='# iterations'), |
| 1300 | zoom_x = range_slider(-2,2,0.01,(-2,1), label='Zoom X'), |
| 1301 | zoom_y = range_slider(-2,2,0.01,(-1.5,1.5), label='Zoom Y'), |
| 1302 | plot_points = slider(20,400,20, default=150, label='plot points'), |
| 1303 | dpi = slider(20, 200, 10, default=80, label='dpi')): |
| 1304 | """ |
| 1305 | Mandelbrot Fractal, based on |
| 1306 | `Mandelbrot by Harald Schilly <http://wiki.sagemath.org/interact/fractal#Mandelbrot>`_. |
| 1307 | |
| 1308 | INPUT: |
| 1309 | |
| 1310 | - ``exponent`` -- exponent ``e`` in `z^e+c` |
| 1311 | - ``iterations`` -- number of iterations |
| 1312 | - ``zoom_x`` -- range slider for zoom in x direction |
| 1313 | - ``zoom_y`` -- range slider for zoom in y direction |
| 1314 | - ``plot_points`` -- number of points to plot |
| 1315 | - ``dpi`` -- dots-per-inch parameter for the plot |
| 1316 | |
| 1317 | EXAMPLE:: |
| 1318 | |
| 1319 | sage: interacts.fractals.mandelbrot() |
| 1320 | <html>...</html> |
| 1321 | """ |
| 1322 | x, z, c = SR.var('x, z, c') |
| 1323 | f = symbolic_expression(z**expo + c).function(z, c) |
| 1324 | ff_m = fast_callable(f, vars=[z,c], domain=CDF) |
| 1325 | |
| 1326 | from sage.interacts.library_cython import mandel |
| 1327 | |
| 1328 | html('<h2>Mandelbrot Fractal</h2>') |
| 1329 | html(r'Recursive Formula: $z \leftarrow z^{%.2f} + c$ for $c \in \mathbb{C}$' % expo) |
| 1330 | 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) |
| 1331 | |
| 1332 | |
| 1333 | @library_interact |
| 1334 | def cellular_automaton( |
| 1335 | N=slider(1,500,1,label='Number of iterations',default=100), |
| 1336 | rule_number=slider(0, 255, 1, default=110, label='Rule number'), |
| 1337 | size = slider(1, 11, step_size=1, default=6, label='size')): |
| 1338 | """ |
| 1339 | Yields a matrix showing the evolution of a |
| 1340 | `Wolfram's cellular automaton <http://mathworld.wolfram.com/CellularAutomaton.html>`_. |
| 1341 | |
| 1342 | `Based on work by Pablo Angulo <http://wiki.sagemath.org/interact/misc#CellularAutomata>`_. |
| 1343 | |
| 1344 | INPUT: |
| 1345 | |
| 1346 | - ``N`` -- iterations |
| 1347 | - ``rule_number`` -- rule number (0 to 255) |
| 1348 | - ``size`` -- size of the shown picture |
| 1349 | |
| 1350 | EXAMPLE:: |
| 1351 | |
| 1352 | sage: interacts.fractals.cellular_automaton() |
| 1353 | <html>...</html> |
| 1354 | """ |
| 1355 | from sage.all import Integer |
| 1356 | if not 0 <= rule_number <= 255: |
| 1357 | raise Exception('Invalid rule number') |
| 1358 | binary_digits = Integer(rule_number).digits(base=2) |
| 1359 | rule = binary_digits + [0]*(8-len(binary_digits)) |
| 1360 | |
| 1361 | html('<h2>Cellular Automaton</h2>'+ |
| 1362 | '<div style="white-space: normal;">"A cellular automaton is a collection of "colored" cells \ |
| 1363 | on a grid of specified shape that evolves through a number of \ |
| 1364 | discrete time steps according to a set of rules based on the \ |
| 1365 | states of neighboring cells." — \ |
| 1366 | <a target="_blank" href="http://mathworld.wolfram.com/CellularAutomaton.html">Mathworld,\ |
| 1367 | Cellular Automaton</a></div>\ |
| 1368 | <div>Rule %s expands to %s</div>' % (rule_number, ''.join(map(str,rule))) |
| 1369 | ) |
| 1370 | |
| 1371 | from sage.interacts.library_cython import cellular |
| 1372 | M = cellular(rule, N) |
| 1373 | plot_M = matrix_plot(M) |
| 1374 | plot_M.show(figsize=[size,size]) |
| 1375 | |
| 1376 | |
| 1377 | @library_interact |
| 1378 | def polar_prime_spiral( |
| 1379 | interval = range_slider(1, 4000, 10, default=(1, 1000), label="range"), |
| 1380 | show_factors = True, |
| 1381 | highlight_primes = True, |
| 1382 | show_curves = True, |
| 1383 | n = slider(1,200, 1, default=89, label="number n"), |
| 1384 | dpi = slider(10,300, 10, default=100, label="dpi")): |
| 1385 | """ |
| 1386 | Polar Prime Spiral interact, based on work by David Runde. |
| 1387 | |
| 1388 | For more information about the factors in the spiral, |
| 1389 | `visit John Williams website <http://www.dcs.gla.ac.uk/~jhw/spirals/index.html>`_. |
| 1390 | |
| 1391 | INPUT: |
| 1392 | |
| 1393 | - ``interval`` -- range slider to specify start and end |
| 1394 | - ``show_factors`` -- if true, show factors |
| 1395 | - ``highlight_primes`` -- if true, prime numbers are highlighted |
| 1396 | - ``show_curves`` -- if true, curves are plotted |
| 1397 | - ``n`` -- number n |
| 1398 | - ``dpi`` -- dots per inch resolution for plotting |
| 1399 | |
| 1400 | EXAMPLE:: |
| 1401 | |
| 1402 | sage: sage.interacts.algebra.polar_prime_spiral() |
| 1403 | <html>...</html> |
| 1404 | |
| 1405 | """ |
| 1406 | |
| 1407 | html('<h2>Polar Prime Spiral</h2> \ |
| 1408 | <div style="white-space: normal;">\ |
| 1409 | For more information about the factors in the spiral, visit \ |
| 1410 | <a href="http://www.dcs.gla.ac.uk/~jhw/spirals/index.html" target="_blank">\ |
| 1411 | Number Spirals by John Williamson</a>.</div>' |
| 1412 | ) |
| 1413 | |
| 1414 | start, end = interval |
| 1415 | from sage.ext.fast_eval import fast_float |
| 1416 | from math import floor, ceil |
| 1417 | from sage.plot.colors import hue |
| 1418 | |
| 1419 | if start < 1 or end <= start: |
| 1420 | print "invalid start or end value" |
| 1421 | return |
| 1422 | if n > end: |
| 1423 | print "WARNING: n is greater than end value" |
| 1424 | return |
| 1425 | if n < start: |
| 1426 | print "n < start value" |
| 1427 | return |
| 1428 | nn = SR.var('nn') |
| 1429 | f1 = fast_float(sqrt(nn)*cos(2*pi*sqrt(nn)), 'nn') |
| 1430 | f2 = fast_float(sqrt(nn)*sin(2*pi*sqrt(nn)), 'nn') |
| 1431 | f = lambda x: (f1(x), f2(x)) |
| 1432 | |
| 1433 | list =[] |
| 1434 | list2=[] |
| 1435 | if show_factors == False: |
| 1436 | for i in srange(start, end, include_endpoint = True): |
| 1437 | if Integer(i).is_pseudoprime(): list.append(f(i-start+1)) #Primes list |
| 1438 | else: list2.append(f(i-start+1)) #Composites list |
| 1439 | P = points(list) |
| 1440 | R = points(list2, alpha = .1) #Faded Composites |
| 1441 | else: |
| 1442 | for i in srange(start, end, include_endpoint = True): |
| 1443 | 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 |
| 1444 | if Integer(i).is_pseudoprime() and highlight_primes: list2.append(f(i-start+1)) |
| 1445 | P = plot(list) |
| 1446 | p_size = 5 #the orange dot size of the prime markers |
| 1447 | if not highlight_primes: list2 = [(f(n-start+1))] |
| 1448 | R = points(list2, hue = .1, pointsize = p_size) |
| 1449 | |
| 1450 | if n > 0: |
| 1451 | html('n = %s' % factor(n)) |
| 1452 | |
| 1453 | p = 1 |
| 1454 | #The X which marks the given n |
| 1455 | W1 = disk((f(n-start+1)), p, (pi/6, 2*pi/6)) |
| 1456 | W2 = disk((f(n-start+1)), p, (4*pi/6, 5*pi/6)) |
| 1457 | W3 = disk((f(n-start+1)), p, (7*pi/6, 8*pi/6)) |
| 1458 | W4 = disk((f(n-start+1)), p, (10*pi/6, 11*pi/6)) |
| 1459 | Q = plot(W1 + W2 + W3 + W4, alpha = .1) |
| 1460 | |
| 1461 | n = n - start +1 #offsets the n for different start values to ensure accurate plotting |
| 1462 | if show_curves: |
| 1463 | begin_curve = 0 |
| 1464 | t = SR.var('t') |
| 1465 | a=1.0 |
| 1466 | b=0.0 |
| 1467 | if n > (floor(sqrt(n)))**2 and n <= (floor(sqrt(n)))**2 + floor(sqrt(n)): |
| 1468 | c = -((floor(sqrt(n)))**2 - n) |
| 1469 | c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) |
| 1470 | else: |
| 1471 | c = -((ceil(sqrt(n)))**2 - n) |
| 1472 | c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) |
| 1473 | html('Pink Curve: $n^2 + %s$' % c) |
| 1474 | html('Green Curve: $n^2 + n + %s$' % c2) |
| 1475 | m = SR.var('m') |
| 1476 | g = symbolic_expression(a*m**2+b*m+c).function(m) |
| 1477 | r = symbolic_expression(sqrt(g(m))).function(m) |
| 1478 | theta = symbolic_expression(r(m)- m*sqrt(a)).function(m) |
| 1479 | S1 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), |
| 1480 | (begin_curve, ceil(sqrt(end-start))), color=hue(0.8), thickness = .3) #Pink Line |
| 1481 | |
| 1482 | b = 1 |
| 1483 | c = c2; |
| 1484 | g = symbolic_expression(a*m**2+b*m+c).function(m) |
| 1485 | r = symbolic_expression(sqrt(g(m))).function(m) |
| 1486 | theta = symbolic_expression(r(m)- m*sqrt(a)).function(m) |
| 1487 | S2 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), |
| 1488 | (begin_curve, ceil(sqrt(end-start))), color=hue(0.6), thickness = .3) #Green Line |
| 1489 | |
| 1490 | show(R+P+S1+S2+Q, aspect_ratio = 1, axes = False, dpi = dpi) |
| 1491 | else: show(R+P+Q, aspect_ratio = 1, axes = False, dpi = dpi) |
| 1492 | else: show(R+P, aspect_ratio = 1, axes = False, dpi = dpi) |
| 1493 | |
| 1494 | |
| 1495 | |