| 3417 | | plot_points -- the number of points to initially plot before |
|---|
| 3418 | | doing adaptive refinement |
|---|
| 3419 | | plot_division -- the maximum number of subdivisions to |
|---|
| 3420 | | introduce in adaptive refinement. |
|---|
| 3421 | | max_bend -- parameter that affects adaptive refinement |
|---|
| | 3417 | plot_points -- (default: 200) the number of points to initially plot |
|---|
| | 3418 | before the adaptive refinement. |
|---|
| | 3419 | adaptive_recursion -- (default: 5) how many levels of recursion to go |
|---|
| | 3420 | before giving up when doing adaptive refinement. |
|---|
| | 3421 | Setting this to 0 disables adaptive refinement. |
|---|
| | 3422 | adaptive_tolerance -- how large a difference should be before the |
|---|
| | 3423 | adaptive refinement code considers it significant. |
|---|
| | 3424 | This depends on the interval you use by default. |
|---|
| 3476 | | might insert other points, however, unless plot_division=0. |
|---|
| 3477 | | sage: p=plot(lambda x: 1, (x,0,3), plot_points=4, randomize=False, plot_division=0) |
|---|
| | 3479 | might insert other points, however, unless adaptive_recursion=0. |
|---|
| | 3480 | sage: p=plot(lambda x: 1, (x,0,3), plot_points=4, randomize=False, adaptive_recursion=0) |
|---|
| 3502 | | sage: plot(sin(1/x), (-1, 1), plot_points=1000) |
|---|
| | 3500 | sage: plot(sin(1/x), (-1, 1)) |
|---|
| | 3501 | |
|---|
| | 3502 | The algorithm used to insert extra points is actually pretty simple. On |
|---|
| | 3503 | the picture drawn by the lines below: |
|---|
| | 3504 | sage: p = plot(x^2, (-0.5, 1.4)) + line([(0,0), (1,1)], rgbcolor='green') |
|---|
| | 3505 | sage: p += line([(0.5, 0.5), (0.5, 0.5^2)], rgbcolor='purple') |
|---|
| | 3506 | sage: p += point(((0, 0), (0.5, 0.5), (0.5, 0.5^2), (1, 1)), rgbcolor='red', pointsize=20) |
|---|
| | 3507 | sage: p += text('A', (-0.05, 0.1), rgbcolor='red') |
|---|
| | 3508 | sage: p += text('B', (1.01, 1.1), rgbcolor='red') |
|---|
| | 3509 | sage: p += text('C', (0.48, 0.57), rgbcolor='red') |
|---|
| | 3510 | sage: p += text('D', (0.53, 0.18), rgbcolor='red') |
|---|
| | 3511 | sage: p.show(axes=False, xmin=-0.5, xmax=1.4, ymin=0, ymax=2) |
|---|
| | 3512 | |
|---|
| | 3513 | You have the function (in blue) and its approximation (in green) passing |
|---|
| | 3514 | through the points A and B. The algorithm finds the midpoint C of AB and |
|---|
| | 3515 | computes the distance between C and D. The point D is added the curve if |
|---|
| | 3516 | it exceeds the (nonzero) adaptive_tolerance threshold. If D is added to |
|---|
| | 3517 | the curve, then the algorithm is applied recursively to the points A and D, |
|---|
| | 3518 | and D and B. It is repeated adaptive_recursion times (10, by default). |
|---|
| 3651 | | exceptions += 1 |
|---|
| 3652 | | exception_indices.append(i) |
|---|
| | 3667 | if i == 0: |
|---|
| | 3668 | for j in range(1, 99): |
|---|
| | 3669 | xj = xi + delta*j/100.0 |
|---|
| | 3670 | try: |
|---|
| | 3671 | data[i] = (float(xj), float(f(xj))) |
|---|
| | 3672 | if data[i][1] != data[i][1]: |
|---|
| | 3673 | raise ValueError, "nan result" |
|---|
| | 3674 | break |
|---|
| | 3675 | except (ZeroDivisionError, TypeError, ValueError, OverflowError), msg: |
|---|
| | 3676 | pass |
|---|
| | 3677 | elif i == plot_points-1: |
|---|
| | 3678 | for j in range(1, 99): |
|---|
| | 3679 | xj = xi - delta*j/100.0 |
|---|
| | 3680 | try: |
|---|
| | 3681 | data[i] = (float(xj), float(f(xj))) |
|---|
| | 3682 | if data[i][1] != data[i][1]: |
|---|
| | 3683 | raise ValueError, "nan result" |
|---|
| | 3684 | break |
|---|
| | 3685 | except (ZeroDivisionError, TypeError, ValueError, OverflowError), msg: |
|---|
| | 3686 | pass |
|---|
| | 3687 | else: |
|---|
| | 3688 | exceptions += 1 |
|---|
| | 3689 | exception_indices.append(i) |
|---|
| | 4489 | |
|---|
| | 4490 | def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=10, level=0): |
|---|
| | 4491 | r""" |
|---|
| | 4492 | The adaptive refinement algorithm for plotting a function f. See the |
|---|
| | 4493 | docstring for plot or PlotFactory for a description of the algorithm. |
|---|
| | 4494 | |
|---|
| | 4495 | INPUT: |
|---|
| | 4496 | f -- a function of one variable |
|---|
| | 4497 | p1, p2 -- two points to refine between |
|---|
| | 4498 | adaptive_recursion -- (default: 10) how many levels of recursion to go |
|---|
| | 4499 | before giving up when doing adaptive refinement. |
|---|
| | 4500 | Setting this to 0 disables adaptive refinement. |
|---|
| | 4501 | adaptive_tolerance -- (default 0.01) how large a difference should be |
|---|
| | 4502 | before the adaptive refinement code considers |
|---|
| | 4503 | it significant. |
|---|
| | 4504 | |
|---|
| | 4505 | OUTPUT: |
|---|
| | 4506 | list -- a list of points to insert between p1 and p2 to get |
|---|
| | 4507 | a better linear approximation between them |
|---|
| | 4508 | |
|---|
| | 4509 | TESTS: |
|---|
| | 4510 | sage: from sage.plot.plot import adaptive_refinement |
|---|
| | 4511 | sage: adaptive_refinement(sin, (0,0), (pi,0), 0.01, level=10) |
|---|
| | 4512 | [] |
|---|
| | 4513 | sage: adaptive_refinement(sin, (0,0), (pi,0), 0.01) |
|---|
| | 4514 | [(0.125000000000000*pi, 0.38268343236508978), (0.187500000000000*pi, 0.55557023301960218), (0.250000000000000*pi, 0.70710678118654757), (0.312500000000000*pi, 0.83146961230254524), (0.375000000000000*pi, 0.92387953251128674), (0.437500000000000*pi, 0.98078528040323043), (0.500000000000000*pi, 1.0), (0.562500000000000*pi, 0.98078528040323043), (0.625000000000000*pi, 0.92387953251128674), (0.687500000000000*pi, 0.83146961230254546), (0.750000000000000*pi, 0.70710678118654757), (0.812500000000000*pi, 0.55557023301960218), (0.875000000000000*pi, 0.38268343236508989)] |
|---|
| | 4515 | """ |
|---|
| | 4516 | if level >= adaptive_recursion: |
|---|
| | 4517 | return [] |
|---|
| | 4518 | x = (p1[0] + p2[0])/2.0 |
|---|
| | 4519 | try: |
|---|
| | 4520 | y = float(f(x)) |
|---|
| | 4521 | except (ZeroDivisionError, TypeError, ValueError, OverflowError), msg: |
|---|
| | 4522 | sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x), 1) |
|---|
| | 4523 | # give up for this branch |
|---|
| | 4524 | return [] |
|---|
| | 4525 | # this distance calculation is not perfect. |
|---|
| | 4526 | if abs((p1[1] + p2[1])/2.0 - y) > adaptive_tolerance: |
|---|
| | 4527 | return adaptive_refinement(f, p1, (x, y), |
|---|
| | 4528 | adaptive_tolerance=adaptive_tolerance, |
|---|
| | 4529 | adaptive_recursion=adaptive_recursion, |
|---|
| | 4530 | level=level+1) \ |
|---|
| | 4531 | + [(x, y)] + \ |
|---|
| | 4532 | adaptive_refinement(f, (x, y), p2, |
|---|
| | 4533 | adaptive_tolerance=adaptive_tolerance, |
|---|
| | 4534 | adaptive_recursion=adaptive_recursion, |
|---|
| | 4535 | level=level+1) |
|---|
| | 4536 | else: |
|---|
| | 4537 | return [] |