skip to content
==> src/infer.c <==
1/* ui.rs's "5 infer" section, ported. */
2#include "mesh/top_ui_infer.h"
3
4#include "tui/chart.h"
5
6#include <math.h>
7
8typedef struct {
9    const char *name;
10    tui_color color;
11    tui_point *pts;
12    size_t n;
13} curve;
14
15/* The finite points of an f32 (x, y) series at two view offsets. */
16static size_t finite_pts(mt_frame *f, const mt_section *p, uint32_t xo, uint32_t yo, size_t count, tui_point **out) {
17    tui_point *pts = tui_arena_alloc(f->a, count * sizeof *pts);
18    size_t n = 0;
19    for (size_t i = 0; i < count; i++) {
20        float x = mt_section_view_f32(p, xo + 4 * i), y = mt_section_view_f32(p, yo + 4 * i);
21        if (isfinite(x) && isfinite(y)) pts[n++] = (tui_point){(double)x, (double)y};
22    }
23    *out = pts;
24    return n;
25}
26
27void mt_draw_infer(mt_frame *f, tui_rect area, const mt_app *app) {
28    const mt_machine *m = mt_app_focused(app);
29    tui_color color;
30    tui_line title = mt_machine_title(f, m, true, "infer: model vs sin(pi x)", &color);
31    tui_block block = mt_panel(f, title, color);
32    tui_rect inner = tui_block_inner(&block, area);
33    mt_block(f, &block, area);
34    const mt_section *inf = mt_bound(f, inner, m, "infer");
35    if (!inf) return;
36    tui_rect hs[2];
37    tui_hsplit(inner, 2, (tui_constraint[]){TUI_FILL(1), TUI_LENGTH(30)}, hs);
38    /* The target samples live in train's view (infer reads train's params the same way). */
39    const mt_section *train = mt_machine_program(m, "train");
40    tui_point *target = NULL;
41    size_t ntarget = train ? finite_pts(f, train, MESH_TRAIN_T_X, MESH_TRAIN_T_Y, 256, &target) : 0;
42    curve *curves = tui_arena_alloc(f->a, (app->nmachines + 1) * sizeof *curves);
43    size_t nc = 0;
44    curves[nc].name = mt_name(f, m);
45    curves[nc].color = MT_MACHINE[app->focus % 8];
46    curves[nc].n = finite_pts(f, inf, MESH_INFER_I_X, MESH_INFER_I_Y, MESH_INFER_POINTS, &curves[nc].pts);
47    nc++;
48    for (size_t i = 0; i < app->nmachines; i++) {
49        const mt_section *op;
50        if (i == app->focus || !(op = mt_machine_program(&app->machines[i], "infer"))) continue;
51        curves[nc].name = mt_name(f, &app->machines[i]);
52        curves[nc].color = MT_MACHINE[i % 8];
53        curves[nc].n = finite_pts(f, op, MESH_INFER_I_X, MESH_INFER_I_Y, MESH_INFER_POINTS, &curves[nc].pts);
54        nc++;
55    }
56    double x0 = INFINITY, x1 = -INFINITY, y0 = INFINITY, y1 = -INFINITY;
57    for (size_t i = 0; i < ntarget; i++) {
58        x0 = fmin(x0, target[i].x);
59        x1 = fmax(x1, target[i].x);
60        y0 = fmin(y0, target[i].y);
61        y1 = fmax(y1, target[i].y);
62    }
63    for (size_t c = 0; c < nc; c++)
64        for (size_t i = 0; i < curves[c].n; i++) {
65            x0 = fmin(x0, curves[c].pts[i].x);
66            x1 = fmax(x1, curves[c].pts[i].x);
67            y0 = fmin(y0, curves[c].pts[i].y);
68            y1 = fmax(y1, curves[c].pts[i].y);
69        }
70    if (!isfinite(x0) || x1 <= x0) {
71        x0 = -1.0;
72        x1 = 1.0;
73    }
74    if (!isfinite(y0) || y1 <= y0) {
75        y0 = -1.0;
76        y1 = 1.0;
77    }
78    double pad = (y1 - y0) * 0.08;
79    y0 -= pad;
80    y1 += pad;
81    tui_dataset *sets = tui_arena_alloc(f->a, (nc + 1) * sizeof *sets);
82    sets[0] = tui_dataset_new();
83    sets[0].has_name = true;
84    sets[0].name = tui_line_from_str(f->a, "target sin(pi x)");
85    sets[0].marker = TUI_MARKER_DOT;
86    sets[0].graph_type = TUI_GRAPH_SCATTER;
87    sets[0].style = tui_fg(MT_DIM);
88    sets[0].data = target;
89    sets[0].n = ntarget;
90    /* Draw the other machines first so the focused curve stays on top. */
91    for (size_t c = 0; c < nc; c++) {
92        const curve *cv = &curves[nc - 1 - c];
93        tui_dataset *d = &sets[1 + c];
94        *d = tui_dataset_new();
95        d->has_name = true;
96        d->name = tui_line_from_str(f->a, cv->name);
97        d->marker = TUI_MARKER_BRAILLE;
98        d->graph_type = TUI_GRAPH_LINE;
99        d->style = tui_fg(cv->color);
100        d->data = cv->pts;
101        d->n = cv->n;
102    }
103    tui_line *xl = tui_arena_alloc(f->a, 2 * sizeof *xl), *yl = tui_arena_alloc(f->a, 2 * sizeof *yl);
104    xl[0] = tui_line_from_str(f->a, mt_ff(f, x0, 2));
105    xl[1] = tui_line_from_str(f->a, MT_FMT(f, "x %s", mt_ff(f, x1, 2)));
106    yl[0] = tui_line_from_str(f->a, mt_ff(f, y0, 2));
107    yl[1] = tui_line_from_str(f->a, mt_ff(f, y1, 2));
108    tui_chart chart = tui_chart_new(sets, nc + 1);
109    chart.x_axis = tui_axis_new();
110    chart.x_axis.style = tui_fg(MT_DIM);
111    chart.x_axis.bounds[0] = x0;
112    chart.x_axis.bounds[1] = x1;
113    chart.x_axis.labels = xl;
114    chart.x_axis.nlabels = 2;
115    chart.y_axis = tui_axis_new();
116    chart.y_axis.style = tui_fg(MT_DIM);
117    chart.y_axis.bounds[0] = y0;
118    chart.y_axis.bounds[1] = y1;
119    chart.y_axis.labels = yl;
120    chart.y_axis.nlabels = 2;
121    chart.has_legend = true;
122    chart.legend_position = TUI_LEGEND_BOTTOM_RIGHT;
123    chart.style = tui_style_bg(tui_style_new(), MT_BG);
124    tui_chart_render(f->a, &chart, hs[0], f->buf);
125
126    mt_lines lines = {0};
127    mt_lines_push(f, &lines, MT_LINE(f, mt_label("infer "), mt_styled(mt_section_state_name(inf), mt_state_style(inf))));
128    mt_lines_push(f, &lines, MT_LINE(f, mt_label("points "), mt_val(MT_FMT(f, "%u", MESH_INFER_POINTS))));
129    mt_lines_push(f, &lines, tui_line_span(f->a, mt_label("y = a + bx + cx² + dx³")));
130    /* The params infer's last run read from train's view, and train's step then. */
131    static const char *const pn[4] = {"a", "b", "c", "d"};
132    for (size_t k = 0; k < 4; k++)
133        mt_lines_push(f, &lines,
134                      MT_LINE(f, mt_label(MT_FMT(f, "%s  ", pn[k])), mt_val(mt_ffp(f, mt_section_view_f32(inf, MESH_INFER_I_PARAMS + 4 * k), 6))));
135    mt_lines_push(f, &lines, MT_LINE(f, mt_label("runs "), mt_val(MT_FMT(f, "%u", mt_section_view_u32(inf, MESH_INFER_I_RUNS)))));
136    mt_lines_push(f, &lines, MT_LINE(f, mt_label("train step "), mt_val(MT_FMT(f, "%u", mt_section_view_u32(inf, MESH_INFER_I_TRAIN_STEP)))));
137    if (!train) mt_lines_push(f, &lines, tui_line_span(f->a, mt_fgs("train is not loaded", MT_WARN)));
138    tui_block b = tui_block_new();
139    b.borders = TUI_BORDER_LEFT;
140    b.border_style = tui_fg(MT_FAINT);
141    tui_paragraph p = tui_paragraph_new(mt_text(f, &lines));
142    p.block = &b;
143    tui_paragraph_render(f->a, &p, hs[1], f->buf);
144}