| 3514 | | You have the function (in blue) its approximation (in green) passing by the |
|---|
| 3515 | | points A and B. The algorithm find the middle point in x of A and B, which |
|---|
| 3516 | | is C. It then computes the distance in y between C and D and adds D |
|---|
| 3517 | | to the curve points if it exceeds some treshold. |
|---|
| 3518 | | |
|---|
| 3519 | | If D was added, it recursivly applies the same algorithm between A and D, |
|---|
| 3520 | | and D and B. It does this up to 10 levels deep by default. |
|---|
| 3521 | | |
|---|
| | 3514 | You have the function (in blue) and its approximation (in green) passing |
|---|
| | 3515 | through the points A and B. The algorithm finds the midpoint C of AB and |
|---|
| | 3516 | computes the distance between C and D. The point D is added the curve if |
|---|
| | 3517 | it exceeds the (nonzero) adaptive_tolerance threshold. If D is added to |
|---|
| | 3518 | the curve, then the algorithm is applied recursively to the points A and D, |
|---|
| | 3519 | and D and B. It is repeated adaptive_recursion times (10, by default). |
|---|
| 3683 | | def refine(f, p1, p2, level=0): |
|---|
| 3684 | | if level >= adaptive_recursion: |
|---|
| 3685 | | return [] |
|---|
| 3686 | | x = float((p1[0] + p2[0])/2) |
|---|
| 3687 | | try: |
|---|
| 3688 | | y = float(f(x)) |
|---|
| 3689 | | except (ZeroDivisionError, TypeError, ValueError), msg: |
|---|
| 3690 | | sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x), 1) |
|---|
| 3691 | | # give up for this branch |
|---|
| 3692 | | return [] |
|---|
| 3693 | | # this distance calculation is not perfect. |
|---|
| 3694 | | if abs((p1[1] + p2[1])/2 - y) > adaptive_tolerance: |
|---|
| 3695 | | return refine(f, p1, (x, y), level+1) + [(x, y)] +\ |
|---|
| 3696 | | refine(f, (x, y), p2, level+1) |
|---|
| 3697 | | else: |
|---|
| 3698 | | return [] |
|---|
| 3699 | | |
|---|
| | 4463 | |
|---|
| | 4464 | def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=10, level=0): |
|---|
| | 4465 | r""" |
|---|
| | 4466 | The adaptive refinement algorithm for plotting a function f. See the |
|---|
| | 4467 | docstring for plot or PlotFactory for a description of the algorithm. |
|---|
| | 4468 | |
|---|
| | 4469 | INPUT: |
|---|
| | 4470 | f -- a function of one variable |
|---|
| | 4471 | p1, p2 -- two points to compare |
|---|
| | 4472 | adaptive_recursion -- (default: 10) how many levels of recursion to go |
|---|
| | 4473 | before giving up when doing adaptive refinement. |
|---|
| | 4474 | Setting this to 0 disables adaptive refinement. |
|---|
| | 4475 | adaptive_tolerance -- how large a difference should be before the |
|---|
| | 4476 | adaptive refinement code considers it significant. |
|---|
| | 4477 | This depends on the interval you use by default. |
|---|
| | 4478 | |
|---|
| | 4479 | TESTS: |
|---|
| | 4480 | sage: from sage.plot.plot import adaptive_refinement |
|---|
| | 4481 | sage: adaptive_refinement(sin, (0,0), (pi,0), 0.01, level=10) |
|---|
| | 4482 | [] |
|---|
| | 4483 | sage: adaptive_refinement(sin, (0,0), (pi,0), 0.01) |
|---|
| | 4484 | [(pi/8, 0.38268343236508978), (3*pi/16, 0.55557023301960218), (pi/4, 0.70710678118654746), (5*pi/16, 0.83146961230254524), (3*pi/8, 0.92387953251128674), (7*pi/16, 0.98078528040323043), (pi/2, 1.0), (9*pi/16, 0.98078528040323043), (5*pi/8, 0.92387953251128674), (11*pi/16, 0.83146961230254546), (3*pi/4, 0.70710678118654757), (13*pi/16, 0.55557023301960218), (7*pi/8, 0.38268343236508989)] |
|---|
| | 4485 | """ |
|---|
| | 4486 | if level >= adaptive_recursion: |
|---|
| | 4487 | return [] |
|---|
| | 4488 | x = (p1[0] + p2[0])/2 |
|---|
| | 4489 | try: |
|---|
| | 4490 | y = float(f(x)) |
|---|
| | 4491 | except (ZeroDivisionError, TypeError, ValueError), msg: |
|---|
| | 4492 | sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x), 1) |
|---|
| | 4493 | # give up for this branch |
|---|
| | 4494 | return [] |
|---|
| | 4495 | # this distance calculation is not perfect. |
|---|
| | 4496 | if abs((p1[1] + p2[1])/2 - y) > adaptive_tolerance: |
|---|
| | 4497 | return adaptive_refinement(f, p1, (x, y), |
|---|
| | 4498 | adaptive_tolerance=adaptive_tolerance, |
|---|
| | 4499 | adaptive_recursion=adaptive_recursion, |
|---|
| | 4500 | level=level+1) \ |
|---|
| | 4501 | + [(x, y)] + \ |
|---|
| | 4502 | adaptive_refinement(f, (x, y), p2, |
|---|
| | 4503 | adaptive_tolerance=adaptive_tolerance, |
|---|
| | 4504 | adaptive_recursion=adaptive_recursion, |
|---|
| | 4505 | level=level+1) |
|---|
| | 4506 | else: |
|---|
| | 4507 | return [] |