+
+
PICT model
+
+
+
+ {showOptions && (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ {editorMode === "full" ? (
+
+ ) : (
+
+ )}
+
+
+ {model.issues.length > 0 &&
}
+
+ {/* Parsed metadata */}
+
+
Parsed factors ({factorKeys.length})
+ {factorKeys.length === 0 ? (
+
No parameters parsed yet.
+ ) : (
+
+
+
+ | Factor |
+ Values |
+
+
+
+ {factorEntries.map(([key, values]) => (
+
+
+ {key}
+ |
+ {values.join(", ")} |
+
+ ))}
+
+
+ )}
+
+ {model.subModels.length > 0 && (
+ <>
+
Sub-models ({model.subModels.length})
+
+
+
+ | Keys |
+ Strength |
+
+
+
+ {model.subModels.map((sm, i) => (
+
+ | {sm.fields.join(", ")} |
+ {sm.strength} |
+
+ ))}
+
+
+ >
+ )}
+
+ {negativeEntries.length > 0 && (
+ <>
+
Negative values
+
+
+
+ | Factor |
+ Values |
+
+
+
+ {negativeEntries.map(([key, set]) => (
+
+
+ {key}
+ |
+ {Array.from(set).join(", ")} |
+
+ ))}
+
+
+ >
+ )}
+
+ {weightEntries.length > 0 && (
+ <>
+
Weights
+
+
+
+ | Factor |
+ Value β Weight |
+
+
+
+ {weightEntries.map(([key, weights]: [string, any]) => {
+ const values = model.parameters[key] ?? [];
+ return (
+
+
+ {key}
+ |
+
+ {Object.entries(weights as Record).map(
+ ([idx, w], i, arr) => (
+
+ {String(values[Number(idx)] ?? idx)}={w}
+ {i < arr.length - 1 ? ", " : ""}
+
+ )
+ )}
+ |
+
+ );
+ })}
+
+
+ >
+ )}
+
+ {model.constraints.length > 0 && (
+ <>
+
Constraints ({model.constraints.length})
+
+ {model.constraints.filter((c) => c != null).length} compiled,{" "}
+ {model.constraints.filter((c) => c == null).length} failed
+
+ >
+ )}
+
+
+
+
Combinations{isDirty && *}
+
+ setOutputView("table")}>
+ Table
+
+ setOutputView("tsv")}>
+ TSV
+
+ setOutputView("json")}>
+ JSON
+
+
+
+
+
+ {generatedKeys.length === 0 ? (
+
+ Click Generate to produce combinations.
+
+ ) : outputView === "table" ? (
+
+
+
+
+ | # |
+ {generatedKeys.map((key) => (
+ {key} |
+ ))}
+
+
+
+ {rows.map((row, i) => (
+
+ | {i + 1} |
+ {generatedKeys.map((key) => (
+ {String(row[key])} |
+ ))}
+
+ ))}
+
+
+
+ ) : outputView === "tsv" ? (
+
{rowsToTsv(rows, generatedKeys)}
+ ) : (
+
{JSON.stringify(rows, null, 2)}
+ )}
+ {outputFull ? (
+
+ ) : generatedKeys.length > 0 && (
+
+ )}
+
+
+ {/* Progress bar (visible while generating) */}
+ {isGenerating && (
+
+
+
+
+ {statusMessage
+ ? statusMessage
+ : `Generatingβ¦ ${rows.length} rows (${Math.round(Math.sqrt(progress) * 100)}%)${eta !== null && eta > 0 ? ` β ~${eta}s left` : ""}`}
+
+
+
+ ?
+
+ Preparing⦠Building pair combinations and pruning infeasible pairs via constraint propagation. Can take a few seconds for large models or higher strengths.
+ Generating⦠Greedy row construction in progress. The percentage reflects pairs consumed or pruned out of total.
+
+
+
+ )}
+
+ {/* Copy / Download */}
+ {rows.length > 0 && (
+
+
+
+
+ )}
+
+ {/* Stats below the grid */}
+ {generatedKeys.length > 0 && (
+
+
+
+
+ 0 ? `${reduction}%` : "β"}
+ sub={total > 0 ? `vs ${total >= 1e6 ? total.toExponential(1) : total.toLocaleString()} total` : undefined}
+ />
+
+
+ {generatedStats && (
+
+
+
+
+ = 1 ? "success" : "warning"}
+ />
+
+ )}
+ {generatedStats && generatedStats.completions && Object.keys(generatedStats.completions).length > 0 && (
+
+ Completions (factors filled by backtracking)
+
+ {Object.entries(generatedStats.completions)
+ .map(([k, v]) => [k, Object.values(v).reduce((a, b) => a + b, 0)] as [string, number])
+ .sort((a, b) => b[1] - a[1])
+ .map(([factor, count]) => (
+
+
+
+
+ {factor}
+ {count}
+
+ ))}
+
+
+ )}
+
+ )}
+