File size: 3,049 Bytes
b89c27d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
84
85
86
87
88
import { useState, useEffect } from 'react'
import Plot from 'react-plotly.js'
import { getLandscape } from '../lib/api.js'

const TEMPLATES = [
  'quadratic', 'rosenbrock', 'styblinski_tang', 'huber',
  'gaussian_mix', 'himmelblau', 'plateau', 'cliff',
]

export function LandscapeExplorer() {
  const [template, setTemplate] = useState('rosenbrock')
  const [dim, setDim] = useState(2)
  const [seed, setSeed] = useState(0)
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(false)

  async function build() {
    setLoading(true)
    try {
      const d = await getLandscape({ template, dim, seed })
      setData(d)
    } finally { setLoading(false) }
  }
  useEffect(() => { build() /* initial load */ // eslint-disable-next-line
  }, [])

  return (
    <div className="grid grid-cols-[320px_1fr] gap-5">
      <aside className="card space-y-4 h-fit">
        <div>
          <h3 className="mb-1">Landscape explorer</h3>
          <p className="text-xs text-muted">
            Pick a template and see what the agent sees at reset.
          </p>
        </div>
        <div>
          <label className="label">Template</label>
          <select className="input" value={template}
                  onChange={e => setTemplate(e.target.value)}>
            {TEMPLATES.map(t => <option key={t}>{t}</option>)}
          </select>
        </div>
        <div>
          <label className="label">Dim: {dim}</label>
          <input type="range" min={2} max={10} step={1} value={dim}
                 onChange={e => setDim(Number(e.target.value))}
                 className="w-full accent-accent" />
        </div>
        <div>
          <label className="label">Seed: {seed}</label>
          <input type="range" min={0} max={100} step={1} value={seed}
                 onChange={e => setSeed(Number(e.target.value))}
                 className="w-full accent-accent" />
        </div>
        <button className="btn-primary w-full"
                onClick={build} disabled={loading}>
          {loading ? 'Building…' : 'Build landscape'}
        </button>
      </aside>

      <div className="space-y-4">
        {data?.contour && (
          <div className="card">
            <Plot data={data.contour.data} layout={data.contour.layout}
                  config={{ displayModeBar: false, responsive: true }}
                  style={{ width: '100%' }} useResizeHandler />
          </div>
        )}
        {data?.hints && (
          <div className="card">
            <h3 className="mb-2">Structural hints</h3>
            <table className="w-full text-sm">
              <tbody>
                {data.hints.map(([k, v], i) => (
                  <tr key={i} className="border-b border-border-soft">
                    <td className="py-2 pr-3 text-muted font-mono text-xs">{k}</td>
                    <td className="py-2 text-ink font-mono text-xs">{v}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  )
}