Skip to content

Instantly share code, notes, and snippets.

@alexgian
Last active June 3, 2024 19:52
Show Gist options
  • Select an option

  • Save alexgian/1242a602e0f75766ca6cf6cbf000308c to your computer and use it in GitHub Desktop.

Select an option

Save alexgian/1242a602e0f75766ca6cf6cbf000308c to your computer and use it in GitHub Desktop.
;; ## 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