File size: 2,678 Bytes
e048104
779968d
 
e048104
60943f3
779968d
e048104
779968d
 
 
 
 
 
 
60943f3
779968d
e048104
 
 
60943f3
e048104
 
 
 
779968d
e048104
 
 
779968d
 
 
e048104
 
 
779968d
 
9292daf
 
 
 
 
 
 
 
 
ab2e84f
 
b26246b
 
 
60943f3
779968d
3f34e78
b26246b
3adb9d3
b26246b
3adb9d3
 
3f34e78
b26246b
 
4f4a1ca
b26246b
 
 
 
 
 
 
 
 
779968d
b26246b
 
 
 
 
 
 
 
779968d
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { useState, useRef } from "react";
import OptimizationPlot from "./OptimizationPlot.tsx";
import Sidebar from "./Sidebar.tsx";
import type { SettingsUi } from "./types.ts";
import usePyodide from "./usePyodide.ts";

const INITIAL_SETTINGS_UI: SettingsUi = {
    mode: "Univariate",
    functionExpr: "x^2",
    algorithm: "Gradient Descent",
    x0: "0.5",
    y0: "0.5",
    learningRate: "0.1",
    momentum: "0.0",
};

const INITIAL_XLIM: [number, number] = [-1, 1];
const INITIAL_YLIM: [number, number] = [-1, 1];

export default function App() {
  const [settingsUi, setSettingsUi] = useState<SettingsUi>(INITIAL_SETTINGS_UI);
  const xlimRef = useRef<[number, number]>(INITIAL_XLIM);
  const ylimRef = useRef<[number, number]>(INITIAL_YLIM);
  const settings = { ...settingsUi, xlim: xlimRef.current, ylim: ylimRef.current };

  function handleSettingsUiChange(newSettings: SettingsUi) {
    setSettingsUi(newSettings);
    api.sendInit({ ...newSettings, xlim: xlimRef.current, ylim: ylimRef.current });
  }

  function setAxisLimits(xlim: [number, number], ylim: [number, number]) {
    xlimRef.current = xlim;
    ylimRef.current = ylim;
    api.sendInit({ ...settingsUi, xlim, ylim });
  }

  function handleRandomInitialPoint() {
    const xRange = xlimRef.current[1] - xlimRef.current[0];
    const yRange = ylimRef.current[1] - ylimRef.current[0];
    const newX0 = (xlimRef.current[0] + Math.random() * xRange * 0.95).toFixed(2);
    const newY0 = (ylimRef.current[0] + Math.random() * yRange * 0.95).toFixed(2);
    const newSettings = { ...settingsUi, x0: newX0, y0: newY0 };
    handleSettingsUiChange(newSettings);
  }

  const api = usePyodide(settings);

  //if (api.isLoading) {
    //return <LoadingScreen message="Loading" />;
  //}

  return (
		<div className="grid grid-cols-[1fr_12fr_1fr] lg:h-dvh bg-stone-50">
			<div/>
			<div className="flex flex-col gap-6 p-6 min-h-0">
				<div className="title">Optimization Trajectory Visualizer</div>
				{/* <div className="desc"></div> */}

				<div className="grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-12 flex-1 min-h-0 overflow-auto">
					<OptimizationPlot 
						data={api.plotData}
						isLoading={api.isLoading}
						xlim={xlimRef.current}
						ylim={ylimRef.current}
						setAxisLimits={setAxisLimits}
					/>
					<Sidebar 
						settings={settingsUi} 
						setSettings={handleSettingsUiChange} 
						onRandomInitialPoint={handleRandomInitialPoint}
						trajectoryValues={api.plotData.trajectoryValues}

						onReset={() => api.sendReset()}
						onNextStep={() => api.sendNextStep()}
						onPrevStep={() => api.sendPrevStep()}
					/>
				</div>
    </div>
		<div/>
	</div>
  );
}