Last active
June 3, 2024 19:52
-
-
Save alexgian/1242a602e0f75766ca6cf6cbf000308c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;; ## Visual Debugging! | |
| ;; | |
| ;; This notebook is a visual debugger for [this GitHub issue](https://github.com/mentat-collective/emmy/issues/174) in Emmy. | |
| (ns param.example | |
| (:require [emmy.complex :as complex] | |
| [emmy.env :as e :refer :all] | |
| [emmy.mafs :as mafs] | |
| [emmy.mathbox.plot :as plot] | |
| [emmy.viewer :as ev])) | |
| ;; Here’s the function under consideration: | |
| (defn fparam [t] | |
| [(* 6 (cos t)) | |
| (* 3 (sin t))]) | |
| ;; The issue had to do with finding the point on this parametric function that’s the closest to some given free point. | |
| ;; | |
| ;; We can make a distance-computing function like this: | |
| (defn dist-from [f [x y]] | |
| (fn [t] (abs (- [x y] (f t))))) | |
| (defn constrain [f [x y]] | |
| (emmy.env/brent-min (dist-from f [x y]) 0 (* 2 pi) | |
| {:absolute-threshold 1.5e-8 | |
| :relative-threshold 1.0e-5})) | |
| ;; And then use some emmy-viewers magic to plot both | |
| ;; | |
| ;; * `fparam` | |
| ;; | |
| ;; * `dist-from` as a function of a movable point | |
| ;; | |
| ;; * The closest point on the ellipse | |
| ;; | |
| ;; * The minimum that Brent finds | |
| ;; | |
| ;; Here’s a function we can use to generate a debugging visualizer: | |
| (defn debug [f] | |
| (ev/with-let [!point [1 2]] | |
| (let [path (ev/with-params | |
| {:atom !point :params [0 1]} | |
| (fn [x y] | |
| (up identity (dist-from f [x y]))))] | |
| (mafs/mafs {:zoom {:min 0.1 :max 2} | |
| :view-box {:x [-7 7] :y [-4 7]}} | |
| (mafs/cartesian) | |
| (mafs/movable-point {:atom !point}) | |
| `(let [~'result (constrain ~f @~!point) | |
| ~'pt (~f (:result ~'result))] | |
| [:<> | |
| ~(mafs/text | |
| "Minimum" | |
| {:x `(:result ~'result) | |
| :y `(:value ~'result) | |
| :attach "e" | |
| :attach-distance 10}) | |
| ~(mafs/point | |
| {:x `(:result ~'result) | |
| :y `(:value ~'result)}) | |
| ~(mafs/text | |
| "Point" | |
| {:x `(first ~'pt) | |
| :y `(second ~'pt) | |
| :color :yellow | |
| :attach-distance 30 | |
| :attach "n"}) | |
| ~(mafs/point | |
| {:x `(first ~'pt) | |
| :y `(second ~'pt) | |
| :color :yellow})]) | |
| (mafs/parametric {:xy path :t [0 (* 2 pi)]}) | |
| (mafs/parametric | |
| {:color :green | |
| :xy f | |
| :t [0 (* 2 pi)]}) | |
| )))) | |
| ;; Now use it on `fparam`: | |
| (debug fparam) | |
| ;; Move the point around and notice that there are multiple minima. Brent only guarantees that it will find *one* of them, not the global minimum. | |
| ;; | |
| ;; [This PR](https://github.com/mentat-collective/emmy/pull/114) will do what you want and use Brent + a grid search to find the global minimum. | |
| ;; | |
| ;; Try it again on an arbitrary function: | |
| (debug (fn [t] | |
| [(* 3 (cos (* 3 t))) | |
| (* 3 (sin t))])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment