@bike4mind/cli 0.17.2 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/{BackgroundAgentManager-DQjlUwRw.mjs → BackgroundAgentManager-BEPNKfmi.mjs} +2647 -231
- package/dist/{ConfigStore-7kcIJ-ux.mjs → ConfigStore-BbTg-UaE.mjs} +245 -15
- package/dist/commands/apiCommand.mjs +4 -3
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/envCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +2 -2
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +7 -6
- package/dist/{package-DLM23Ze7.mjs → package-CSa_ad8r.mjs} +1 -1
- package/package.json +8 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as PermissionDeniedError, $t as extractSnippetMeta, A as FriendshipEvents, At as XAI_IMAGE_MODELS, B as InboxEvents, Bt as isZodError, C as CorruptedFileError, Ct as TransferCreditTransaction, D as FeedbackEvents, Dt as VIDEO_SIZE_CONSTRAINTS, E as FavoriteDocumentType, Et as UnprocessableEntityError, F as HTTPError, Ft as getViewById, G as LLMEvents, Gt as sanitizeTelemetryError, H as InviteEvents, Ht as obfuscateApiKey, I as HttpStatus, It as isGPTImage2Model, J as ModelBackend, Jt as substituteArguments$1, K as MiscEvents, Kt as secureParameters, L as ImageEditUsageTransaction, Lt as isGPTImageModel, M as GenerateImageToolCallSchema, Mt as dayjsConfig_default, N as GenericCreditAddTransaction, Nt as getAccessibleDataLakes, O as FileEvents, Ot as VideoGenerationUsageTransaction, P as GenericCreditDeductTransaction, Pt as getMcpProviderMetadata, Q as Permission, Qt as buildRateLimitLogEntry, R as ImageGenerationUsageTransaction, Rt as isModelAccessible, S as CompletionApiUsageTransaction, St as ToolUsageTransaction, T as ElabsEvents, Tt as UnauthorizedError, U as InviteType, Ut as parseSkillArguments, V as InternalServerError, Vt as mapMimeTypeToArtifactType, W as KnowledgeType, Wt as resolveNavigationIntents, X as OpenAIEmbeddingModel, Y as NotFoundError, Yt as toDataLakeConfig, Z as OpenAIImageGenerationInput, _ as BadRequestError, _t as SupportedFabFileMimeTypes, at as QuestMasterParamsSchema, b as ChatModels, bt as TextGenerationUsageTransaction, c as AiEvents, ct as RechartsChartTypeList, d as ApiKeyType, dt as ResearchTaskExecutionType, en as isNearLimit, et as ProfileEvents, f as AppFileEvents, ft as ResearchTaskPeriodicFrequencyType, g as BFL_SAFETY_TOLERANCE, gt as SubscriptionCreditTransaction, h as BFL_IMAGE_MODELS, ht as SpeechToTextUsageTransaction, it as PurchaseTransaction, j as GEMINI_IMAGE_MODELS, jt as b4mLLMTools, k as ForbiddenError, kt as VideoModels, l as ApiKeyEvents, lt as RegInviteEvents, m as AuthEvents, mt as SessionEvents, n as logger, nn as CollectionType, nt as PromptIntentSchema, ot as RealtimeVoiceUsageTransaction, p as ArtifactTypeSchema, pt as ResearchTaskType, q as ModalEvents, qt as settingsMap, rt as PromptMetaZodSchema, s as ALERT_THRESHOLDS, st as ReceivedCreditTransaction, t as ConfigStore, tn as parseRateLimitHeaders, tt as ProjectEvents, u as ApiKeyScope, ut as ResearchModeParamsSchema, vt as TagType, w as DashboardParamsSchema, wt as UiNavigationEvents, x as ClaudeArtifactMimeTypes, xt as TooManyRequestsError, y as ChatCompletionCreateInputSchema, yt as TaskScheduleHandler, z as ImageModels, zt as isSupportedEmbeddingModel } from "./ConfigStore-BbTg-UaE.mjs";
|
|
3
3
|
import { a as isUserLockedOut, c as userCanDisableMFA, d as userRequiresMFA, f as verifyBackupCode, i as getLockoutTimeRemaining, l as userEligibleForMFA, n as generateBackupCodes, o as recordFailedAttempt, p as verifyTOTPToken, r as generateTOTPSetup, s as shouldResetFailedAttempts, t as clearFailedAttempts, u as userHasMFAConfigured } from "./utils-fqhJmuB8.mjs";
|
|
4
4
|
import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-D8tjkQXE-1HwvsuYT.mjs";
|
|
5
|
-
import { t as version } from "./package-
|
|
5
|
+
import { t as version } from "./package-CSa_ad8r.mjs";
|
|
6
6
|
import { execFile, execFileSync, spawn } from "child_process";
|
|
7
7
|
import crypto, { createHash, randomBytes, randomUUID } from "crypto";
|
|
8
8
|
import { existsSync, promises, readFileSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -8843,25 +8843,55 @@ function sanitizeJsonStringWithMeta(jsonStr, options) {
|
|
|
8843
8843
|
}
|
|
8844
8844
|
//#endregion
|
|
8845
8845
|
//#region ../../b4m-core/quantum/dist/index.mjs
|
|
8846
|
+
/**
|
|
8847
|
+
* Scheduling's objective is makespan (lower is better), rendered in time units.
|
|
8848
|
+
* This is the `ObjectiveMeta` every scheduling `SolverResult` carries so that
|
|
8849
|
+
* shared, family-agnostic UI can render scheduling results too.
|
|
8850
|
+
*/
|
|
8851
|
+
const SCHEDULING_OBJECTIVE_META = {
|
|
8852
|
+
label: "makespan",
|
|
8853
|
+
unit: "t",
|
|
8854
|
+
direction: "min",
|
|
8855
|
+
format: { suffix: "t" }
|
|
8856
|
+
};
|
|
8857
|
+
/**
|
|
8858
|
+
* Build a scheduling `SolverResult` from the domain-native quantities a solver
|
|
8859
|
+
* produces (a schedule + its makespan), filling in the shared-contract fields.
|
|
8860
|
+
* Keeps the makespan→objective mapping in one place across all 11 solvers.
|
|
8861
|
+
*/
|
|
8862
|
+
function makeSchedulingResult(args) {
|
|
8863
|
+
return {
|
|
8864
|
+
solverId: args.solverId,
|
|
8865
|
+
solverName: args.solverName,
|
|
8866
|
+
objective: args.makespan,
|
|
8867
|
+
internalCost: args.makespan,
|
|
8868
|
+
objectiveMeta: SCHEDULING_OBJECTIVE_META,
|
|
8869
|
+
solution: args.schedule,
|
|
8870
|
+
elapsedMs: args.elapsedMs,
|
|
8871
|
+
iterations: args.iterations,
|
|
8872
|
+
trace: args.trace,
|
|
8873
|
+
metadata: args.metadata
|
|
8874
|
+
};
|
|
8875
|
+
}
|
|
8846
8876
|
const OperationSchema = z.object({
|
|
8847
8877
|
jobId: z.number(),
|
|
8848
8878
|
machineId: z.number(),
|
|
8849
|
-
duration: z.number().positive()
|
|
8879
|
+
duration: z.number().positive().max(1e6)
|
|
8850
8880
|
});
|
|
8851
8881
|
const JobSchema = z.object({
|
|
8852
8882
|
id: z.number(),
|
|
8853
|
-
name: z.string(),
|
|
8854
|
-
operations: z.array(OperationSchema)
|
|
8883
|
+
name: z.string().max(200),
|
|
8884
|
+
operations: z.array(OperationSchema).max(1e3)
|
|
8855
8885
|
});
|
|
8856
8886
|
const MachineSchema = z.object({
|
|
8857
8887
|
id: z.number(),
|
|
8858
|
-
name: z.string()
|
|
8888
|
+
name: z.string().max(200)
|
|
8859
8889
|
});
|
|
8860
8890
|
const SchedulingProblemSchema = z.object({
|
|
8861
|
-
name: z.string(),
|
|
8862
|
-
description: z.string().optional(),
|
|
8863
|
-
jobs: z.array(JobSchema),
|
|
8864
|
-
machines: z.array(MachineSchema),
|
|
8891
|
+
name: z.string().max(200),
|
|
8892
|
+
description: z.string().max(2e3).optional(),
|
|
8893
|
+
jobs: z.array(JobSchema).max(1e3),
|
|
8894
|
+
machines: z.array(MachineSchema).max(1e3),
|
|
8865
8895
|
solvedJobUrl: z.string().url().optional()
|
|
8866
8896
|
});
|
|
8867
8897
|
const SolverIdSchema = z.enum([
|
|
@@ -8920,19 +8950,24 @@ const greedySolver = {
|
|
|
8920
8950
|
if (options?.onProgress) options.onProgress({
|
|
8921
8951
|
solverId: "greedy",
|
|
8922
8952
|
percentage: Math.round(opsScheduled / totalOps * 100),
|
|
8923
|
-
|
|
8953
|
+
bestObjective: opEnd,
|
|
8924
8954
|
currentIteration: opsScheduled,
|
|
8925
8955
|
totalIterations: totalOps
|
|
8926
8956
|
});
|
|
8927
8957
|
}
|
|
8928
|
-
|
|
8958
|
+
const makespan = Math.max(...schedule.map((op) => op.endTime));
|
|
8959
|
+
return makeSchedulingResult({
|
|
8929
8960
|
solverId: "greedy",
|
|
8930
8961
|
solverName: "Greedy (Earliest Start)",
|
|
8931
|
-
makespan
|
|
8962
|
+
makespan,
|
|
8932
8963
|
schedule,
|
|
8933
8964
|
elapsedMs: performance.now() - startTime,
|
|
8934
|
-
iterations: totalOps
|
|
8935
|
-
|
|
8965
|
+
iterations: totalOps,
|
|
8966
|
+
trace: [{
|
|
8967
|
+
solution: schedule,
|
|
8968
|
+
objective: makespan
|
|
8969
|
+
}]
|
|
8970
|
+
});
|
|
8936
8971
|
}
|
|
8937
8972
|
};
|
|
8938
8973
|
/**
|
|
@@ -9062,6 +9097,34 @@ function validateScheduleFeasibility(schedule) {
|
|
|
9062
9097
|
return true;
|
|
9063
9098
|
}
|
|
9064
9099
|
/**
|
|
9100
|
+
* Append a best-so-far snapshot, thinning the early history when over cap so the
|
|
9101
|
+
* trace stays bounded while preserving the first point and recent progress.
|
|
9102
|
+
* (Same thinning policy as the family engine's pushTrace.)
|
|
9103
|
+
*/
|
|
9104
|
+
function pushScheduleTrace(trace, schedule, makespan) {
|
|
9105
|
+
trace.push({
|
|
9106
|
+
solution: schedule,
|
|
9107
|
+
objective: makespan
|
|
9108
|
+
});
|
|
9109
|
+
if (trace.length > 48) {
|
|
9110
|
+
const first = trace[0];
|
|
9111
|
+
const rest = trace.slice(1).filter((_, i) => i % 2 === 1);
|
|
9112
|
+
trace.length = 0;
|
|
9113
|
+
trace.push(first, ...rest);
|
|
9114
|
+
}
|
|
9115
|
+
}
|
|
9116
|
+
const nowMs = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
9117
|
+
/**
|
|
9118
|
+
* Combine the timeoutMs budget with cooperative cancellation into one stop check
|
|
9119
|
+
* that iterative solvers poll between moves — so a UI cancel or a timeout actually
|
|
9120
|
+
* halts a long run instead of being decorative. `defaultTimeoutMs` preserves each
|
|
9121
|
+
* solver's historical default when the caller omits timeoutMs.
|
|
9122
|
+
*/
|
|
9123
|
+
function makeScheduleStopper(options, startTime, defaultTimeoutMs) {
|
|
9124
|
+
const deadline = startTime + (options?.timeoutMs ?? defaultTimeoutMs);
|
|
9125
|
+
return () => (options?.shouldCancel?.() ?? false) || nowMs() > deadline;
|
|
9126
|
+
}
|
|
9127
|
+
/**
|
|
9065
9128
|
* Simple seeded pseudo-random number generator (mulberry32).
|
|
9066
9129
|
*/
|
|
9067
9130
|
function createRng$1(seed) {
|
|
@@ -9097,25 +9160,31 @@ const naiveSolver = {
|
|
|
9097
9160
|
description: "Evaluates all permutations to find the optimal schedule. Only feasible for small problems.",
|
|
9098
9161
|
async solve(problem, options) {
|
|
9099
9162
|
const startTime = performance.now();
|
|
9163
|
+
const stop = makeScheduleStopper(options, startTime, 15e3);
|
|
9100
9164
|
const ops = buildOperationList(problem);
|
|
9101
9165
|
const totalPerms = factorial(ops.length);
|
|
9102
9166
|
const cappedTotal = Math.min(totalPerms, MAX_PERMUTATIONS);
|
|
9103
|
-
let bestMakespan = Infinity;
|
|
9104
9167
|
let bestSchedule = decodePermutation(ops, problem);
|
|
9168
|
+
let bestMakespan = computeMakespan(bestSchedule);
|
|
9105
9169
|
let count = 0;
|
|
9170
|
+
const trace = [{
|
|
9171
|
+
solution: bestSchedule,
|
|
9172
|
+
objective: bestMakespan
|
|
9173
|
+
}];
|
|
9106
9174
|
for (const perm of permutations(ops)) {
|
|
9107
|
-
if (count >= MAX_PERMUTATIONS) break;
|
|
9175
|
+
if (count >= MAX_PERMUTATIONS || stop()) break;
|
|
9108
9176
|
const schedule = decodePermutation(perm, problem);
|
|
9109
9177
|
const makespan = computeMakespan(schedule);
|
|
9110
9178
|
if (makespan < bestMakespan) {
|
|
9111
9179
|
bestMakespan = makespan;
|
|
9112
9180
|
bestSchedule = schedule;
|
|
9181
|
+
pushScheduleTrace(trace, bestSchedule, bestMakespan);
|
|
9113
9182
|
}
|
|
9114
9183
|
count++;
|
|
9115
9184
|
if (options?.onProgress && count % 100 === 0) options.onProgress({
|
|
9116
9185
|
solverId: "naive",
|
|
9117
9186
|
percentage: Math.min(99, Math.round(count / cappedTotal * 100)),
|
|
9118
|
-
bestMakespan,
|
|
9187
|
+
bestObjective: bestMakespan,
|
|
9119
9188
|
currentIteration: count,
|
|
9120
9189
|
totalIterations: cappedTotal
|
|
9121
9190
|
});
|
|
@@ -9123,18 +9192,19 @@ const naiveSolver = {
|
|
|
9123
9192
|
options?.onProgress?.({
|
|
9124
9193
|
solverId: "naive",
|
|
9125
9194
|
percentage: 100,
|
|
9126
|
-
bestMakespan,
|
|
9195
|
+
bestObjective: bestMakespan,
|
|
9127
9196
|
currentIteration: count,
|
|
9128
9197
|
totalIterations: cappedTotal
|
|
9129
9198
|
});
|
|
9130
|
-
return {
|
|
9199
|
+
return makeSchedulingResult({
|
|
9131
9200
|
solverId: "naive",
|
|
9132
9201
|
solverName: "Naive (Brute Force)",
|
|
9133
9202
|
makespan: bestMakespan,
|
|
9134
9203
|
schedule: bestSchedule,
|
|
9135
9204
|
elapsedMs: performance.now() - startTime,
|
|
9136
|
-
iterations: count
|
|
9137
|
-
|
|
9205
|
+
iterations: count,
|
|
9206
|
+
trace
|
|
9207
|
+
});
|
|
9138
9208
|
}
|
|
9139
9209
|
};
|
|
9140
9210
|
function factorial(n) {
|
|
@@ -9158,18 +9228,22 @@ const randomRestartSolver = {
|
|
|
9158
9228
|
description: "Multiple random starts with local search improvement via operation swaps.",
|
|
9159
9229
|
async solve(problem, options) {
|
|
9160
9230
|
const startTime = performance.now();
|
|
9161
|
-
const
|
|
9231
|
+
const stop = makeScheduleStopper(options, startTime, 1e4);
|
|
9162
9232
|
const rng = createRng$1(42);
|
|
9163
|
-
let globalBestMakespan = Infinity;
|
|
9164
9233
|
let globalBestSchedule = decodePermutation(randomPermutation(problem, rng), problem);
|
|
9234
|
+
let globalBestMakespan = computeMakespan(globalBestSchedule);
|
|
9165
9235
|
let totalIterations = 0;
|
|
9236
|
+
const trace = [{
|
|
9237
|
+
solution: globalBestSchedule,
|
|
9238
|
+
objective: globalBestMakespan
|
|
9239
|
+
}];
|
|
9166
9240
|
for (let restart = 0; restart < RESTARTS; restart++) {
|
|
9167
|
-
if (
|
|
9241
|
+
if (stop()) break;
|
|
9168
9242
|
let currentPerm = randomPermutation(problem, rng);
|
|
9169
9243
|
let currentSchedule = decodePermutation(currentPerm, problem);
|
|
9170
9244
|
let currentMakespan = computeMakespan(currentSchedule);
|
|
9171
9245
|
for (let i = 0; i < HILL_CLIMB_ITERATIONS; i++) {
|
|
9172
|
-
if (
|
|
9246
|
+
if (stop()) break;
|
|
9173
9247
|
const neighborPerm = swapNeighbor(currentPerm, rng);
|
|
9174
9248
|
const neighborSchedule = decodePermutation(neighborPerm, problem);
|
|
9175
9249
|
const neighborMakespan = computeMakespan(neighborSchedule);
|
|
@@ -9183,23 +9257,25 @@ const randomRestartSolver = {
|
|
|
9183
9257
|
if (currentMakespan < globalBestMakespan) {
|
|
9184
9258
|
globalBestMakespan = currentMakespan;
|
|
9185
9259
|
globalBestSchedule = currentSchedule;
|
|
9260
|
+
pushScheduleTrace(trace, globalBestSchedule, globalBestMakespan);
|
|
9186
9261
|
}
|
|
9187
9262
|
options?.onProgress?.({
|
|
9188
9263
|
solverId: "random-restart",
|
|
9189
9264
|
percentage: Math.round((restart + 1) / RESTARTS * 100),
|
|
9190
|
-
|
|
9265
|
+
bestObjective: globalBestMakespan,
|
|
9191
9266
|
currentIteration: restart + 1,
|
|
9192
9267
|
totalIterations: RESTARTS
|
|
9193
9268
|
});
|
|
9194
9269
|
}
|
|
9195
|
-
return {
|
|
9270
|
+
return makeSchedulingResult({
|
|
9196
9271
|
solverId: "random-restart",
|
|
9197
9272
|
solverName: "Random Restart Hill Climbing",
|
|
9198
9273
|
makespan: globalBestMakespan,
|
|
9199
9274
|
schedule: globalBestSchedule,
|
|
9200
9275
|
elapsedMs: performance.now() - startTime,
|
|
9201
|
-
iterations: totalIterations
|
|
9202
|
-
|
|
9276
|
+
iterations: totalIterations,
|
|
9277
|
+
trace
|
|
9278
|
+
});
|
|
9203
9279
|
}
|
|
9204
9280
|
};
|
|
9205
9281
|
const SA_CONFIGS = [
|
|
@@ -9235,17 +9311,21 @@ function createSASolver(config) {
|
|
|
9235
9311
|
description: config.description,
|
|
9236
9312
|
async solve(problem, options) {
|
|
9237
9313
|
const startTime = performance.now();
|
|
9238
|
-
const
|
|
9314
|
+
const stop = makeScheduleStopper(options, startTime, 3e4);
|
|
9239
9315
|
const rng = createRng$1(42);
|
|
9240
9316
|
let currentPerm = randomPermutation(problem, rng);
|
|
9241
9317
|
let currentSchedule = decodePermutation(currentPerm, problem);
|
|
9242
9318
|
let currentMakespan = computeMakespan(currentSchedule);
|
|
9243
9319
|
let bestSchedule = currentSchedule;
|
|
9244
9320
|
let bestMakespan = currentMakespan;
|
|
9321
|
+
const trace = [{
|
|
9322
|
+
solution: bestSchedule,
|
|
9323
|
+
objective: bestMakespan
|
|
9324
|
+
}];
|
|
9245
9325
|
let temperature = config.initialTemp;
|
|
9246
9326
|
const progressInterval = Math.max(1, Math.floor(config.iterations / 100));
|
|
9247
9327
|
for (let i = 0; i < config.iterations; i++) {
|
|
9248
|
-
if (
|
|
9328
|
+
if (stop()) break;
|
|
9249
9329
|
const neighborPerm = swapNeighbor(currentPerm, rng);
|
|
9250
9330
|
const neighborSchedule = decodePermutation(neighborPerm, problem);
|
|
9251
9331
|
const neighborMakespan = computeMakespan(neighborSchedule);
|
|
@@ -9257,13 +9337,14 @@ function createSASolver(config) {
|
|
|
9257
9337
|
if (currentMakespan < bestMakespan) {
|
|
9258
9338
|
bestSchedule = currentSchedule;
|
|
9259
9339
|
bestMakespan = currentMakespan;
|
|
9340
|
+
pushScheduleTrace(trace, bestSchedule, bestMakespan);
|
|
9260
9341
|
}
|
|
9261
9342
|
}
|
|
9262
9343
|
temperature *= config.coolingRate;
|
|
9263
9344
|
if (options?.onProgress && i % progressInterval === 0) options.onProgress({
|
|
9264
9345
|
solverId: config.id,
|
|
9265
9346
|
percentage: Math.round(i / config.iterations * 100),
|
|
9266
|
-
bestMakespan,
|
|
9347
|
+
bestObjective: bestMakespan,
|
|
9267
9348
|
currentIteration: i,
|
|
9268
9349
|
totalIterations: config.iterations
|
|
9269
9350
|
});
|
|
@@ -9271,18 +9352,19 @@ function createSASolver(config) {
|
|
|
9271
9352
|
options?.onProgress?.({
|
|
9272
9353
|
solverId: config.id,
|
|
9273
9354
|
percentage: 100,
|
|
9274
|
-
bestMakespan,
|
|
9355
|
+
bestObjective: bestMakespan,
|
|
9275
9356
|
currentIteration: config.iterations,
|
|
9276
9357
|
totalIterations: config.iterations
|
|
9277
9358
|
});
|
|
9278
|
-
return {
|
|
9359
|
+
return makeSchedulingResult({
|
|
9279
9360
|
solverId: config.id,
|
|
9280
9361
|
solverName: config.name,
|
|
9281
9362
|
makespan: bestMakespan,
|
|
9282
9363
|
schedule: bestSchedule,
|
|
9283
9364
|
elapsedMs: performance.now() - startTime,
|
|
9284
|
-
iterations: config.iterations
|
|
9285
|
-
|
|
9365
|
+
iterations: config.iterations,
|
|
9366
|
+
trace
|
|
9367
|
+
});
|
|
9286
9368
|
}
|
|
9287
9369
|
};
|
|
9288
9370
|
}
|
|
@@ -9296,7 +9378,7 @@ const simulatedAnnealingLargeSolver = createSASolver(SA_CONFIGS[2]);
|
|
|
9296
9378
|
* forbidden for a period. This prevents cycling and forces exploration
|
|
9297
9379
|
* of new regions of the solution space.
|
|
9298
9380
|
*/
|
|
9299
|
-
const ITERATIONS$
|
|
9381
|
+
const ITERATIONS$2 = 1e4;
|
|
9300
9382
|
const TABU_TENURE = 15;
|
|
9301
9383
|
const NEIGHBORHOOD_SIZE = 20;
|
|
9302
9384
|
const tabuSolver = {
|
|
@@ -9305,17 +9387,21 @@ const tabuSolver = {
|
|
|
9305
9387
|
description: "Hill climbing with short-term memory to avoid revisiting recent solutions.",
|
|
9306
9388
|
async solve(problem, options) {
|
|
9307
9389
|
const startTime = performance.now();
|
|
9308
|
-
const
|
|
9390
|
+
const stop = makeScheduleStopper(options, startTime, 15e3);
|
|
9309
9391
|
const rng = createRng$1(42);
|
|
9310
9392
|
let currentPerm = randomPermutation(problem, rng);
|
|
9311
9393
|
let currentSchedule = decodePermutation(currentPerm, problem);
|
|
9312
9394
|
let currentMakespan = computeMakespan(currentSchedule);
|
|
9313
9395
|
let bestSchedule = currentSchedule;
|
|
9314
9396
|
let bestMakespan = currentMakespan;
|
|
9397
|
+
const trace = [{
|
|
9398
|
+
solution: bestSchedule,
|
|
9399
|
+
objective: bestMakespan
|
|
9400
|
+
}];
|
|
9315
9401
|
const tabuList = /* @__PURE__ */ new Map();
|
|
9316
|
-
const progressInterval = Math.max(1, Math.floor(ITERATIONS$
|
|
9317
|
-
for (let iter = 0; iter < ITERATIONS$
|
|
9318
|
-
if (
|
|
9402
|
+
const progressInterval = Math.max(1, Math.floor(ITERATIONS$2 / 100));
|
|
9403
|
+
for (let iter = 0; iter < ITERATIONS$2; iter++) {
|
|
9404
|
+
if (stop()) break;
|
|
9319
9405
|
let bestNeighborPerm = null;
|
|
9320
9406
|
let bestNeighborMakespan = Infinity;
|
|
9321
9407
|
let bestSwapKey = "";
|
|
@@ -9341,6 +9427,7 @@ const tabuSolver = {
|
|
|
9341
9427
|
if (currentMakespan < bestMakespan) {
|
|
9342
9428
|
bestMakespan = currentMakespan;
|
|
9343
9429
|
bestSchedule = currentSchedule;
|
|
9430
|
+
pushScheduleTrace(trace, bestSchedule, bestMakespan);
|
|
9344
9431
|
}
|
|
9345
9432
|
}
|
|
9346
9433
|
if (iter % 100 === 0) {
|
|
@@ -9348,27 +9435,28 @@ const tabuSolver = {
|
|
|
9348
9435
|
}
|
|
9349
9436
|
if (options?.onProgress && iter % progressInterval === 0) options.onProgress({
|
|
9350
9437
|
solverId: "tabu",
|
|
9351
|
-
percentage: Math.round(iter / ITERATIONS$
|
|
9352
|
-
bestMakespan,
|
|
9438
|
+
percentage: Math.round(iter / ITERATIONS$2 * 100),
|
|
9439
|
+
bestObjective: bestMakespan,
|
|
9353
9440
|
currentIteration: iter,
|
|
9354
|
-
totalIterations: ITERATIONS$
|
|
9441
|
+
totalIterations: ITERATIONS$2
|
|
9355
9442
|
});
|
|
9356
9443
|
}
|
|
9357
9444
|
options?.onProgress?.({
|
|
9358
9445
|
solverId: "tabu",
|
|
9359
9446
|
percentage: 100,
|
|
9360
|
-
bestMakespan,
|
|
9361
|
-
currentIteration: ITERATIONS$
|
|
9362
|
-
totalIterations: ITERATIONS$
|
|
9447
|
+
bestObjective: bestMakespan,
|
|
9448
|
+
currentIteration: ITERATIONS$2,
|
|
9449
|
+
totalIterations: ITERATIONS$2
|
|
9363
9450
|
});
|
|
9364
|
-
return {
|
|
9451
|
+
return makeSchedulingResult({
|
|
9365
9452
|
solverId: "tabu",
|
|
9366
9453
|
solverName: "Tabu Search",
|
|
9367
9454
|
makespan: bestMakespan,
|
|
9368
9455
|
schedule: bestSchedule,
|
|
9369
9456
|
elapsedMs: performance.now() - startTime,
|
|
9370
|
-
iterations: ITERATIONS$
|
|
9371
|
-
|
|
9457
|
+
iterations: ITERATIONS$2,
|
|
9458
|
+
trace
|
|
9459
|
+
});
|
|
9372
9460
|
}
|
|
9373
9461
|
};
|
|
9374
9462
|
/**
|
|
@@ -9387,7 +9475,7 @@ const geneticAlgorithmSolver = {
|
|
|
9387
9475
|
description: "Population-based search with tournament selection, crossover, and mutation.",
|
|
9388
9476
|
async solve(problem, options) {
|
|
9389
9477
|
const startTime = performance.now();
|
|
9390
|
-
const
|
|
9478
|
+
const stop = makeScheduleStopper(options, startTime, 2e4);
|
|
9391
9479
|
const rng = createRng$1(42);
|
|
9392
9480
|
let population = [];
|
|
9393
9481
|
for (let i = 0; i < POPULATION_SIZE; i++) {
|
|
@@ -9399,8 +9487,12 @@ const geneticAlgorithmSolver = {
|
|
|
9399
9487
|
});
|
|
9400
9488
|
}
|
|
9401
9489
|
let bestIndividual = population.reduce((best, ind) => ind.makespan < best.makespan ? ind : best);
|
|
9490
|
+
const trace = [{
|
|
9491
|
+
solution: decodePermutation(bestIndividual.perm, problem),
|
|
9492
|
+
objective: bestIndividual.makespan
|
|
9493
|
+
}];
|
|
9402
9494
|
for (let gen = 0; gen < GENERATIONS; gen++) {
|
|
9403
|
-
if (
|
|
9495
|
+
if (stop()) break;
|
|
9404
9496
|
const newPopulation = [];
|
|
9405
9497
|
newPopulation.push({ ...bestIndividual });
|
|
9406
9498
|
while (newPopulation.length < POPULATION_SIZE) {
|
|
@@ -9416,24 +9508,28 @@ const geneticAlgorithmSolver = {
|
|
|
9416
9508
|
}
|
|
9417
9509
|
population = newPopulation;
|
|
9418
9510
|
const genBest = population.reduce((best, ind) => ind.makespan < best.makespan ? ind : best);
|
|
9419
|
-
if (genBest.makespan < bestIndividual.makespan)
|
|
9511
|
+
if (genBest.makespan < bestIndividual.makespan) {
|
|
9512
|
+
bestIndividual = genBest;
|
|
9513
|
+
pushScheduleTrace(trace, decodePermutation(bestIndividual.perm, problem), bestIndividual.makespan);
|
|
9514
|
+
}
|
|
9420
9515
|
options?.onProgress?.({
|
|
9421
9516
|
solverId: "genetic-algorithm",
|
|
9422
9517
|
percentage: Math.round((gen + 1) / GENERATIONS * 100),
|
|
9423
|
-
|
|
9518
|
+
bestObjective: bestIndividual.makespan,
|
|
9424
9519
|
currentIteration: gen + 1,
|
|
9425
9520
|
totalIterations: GENERATIONS
|
|
9426
9521
|
});
|
|
9427
9522
|
}
|
|
9428
9523
|
const bestSchedule = decodePermutation(bestIndividual.perm, problem);
|
|
9429
|
-
return {
|
|
9524
|
+
return makeSchedulingResult({
|
|
9430
9525
|
solverId: "genetic-algorithm",
|
|
9431
9526
|
solverName: "Genetic Algorithm",
|
|
9432
9527
|
makespan: bestIndividual.makespan,
|
|
9433
9528
|
schedule: bestSchedule,
|
|
9434
9529
|
elapsedMs: performance.now() - startTime,
|
|
9435
|
-
iterations: GENERATIONS * POPULATION_SIZE
|
|
9436
|
-
|
|
9530
|
+
iterations: GENERATIONS * POPULATION_SIZE,
|
|
9531
|
+
trace
|
|
9532
|
+
});
|
|
9437
9533
|
}
|
|
9438
9534
|
};
|
|
9439
9535
|
function tournamentSelect(population, size, rng) {
|
|
@@ -9477,10 +9573,10 @@ function crossover(parent1, parent2, rng) {
|
|
|
9477
9573
|
* assignments) that appear in good solutions and evaporate over time.
|
|
9478
9574
|
*/
|
|
9479
9575
|
const NUM_ANTS = 20;
|
|
9480
|
-
const ITERATIONS = 100;
|
|
9576
|
+
const ITERATIONS$1 = 100;
|
|
9481
9577
|
const ALPHA = 1;
|
|
9482
9578
|
const BETA = 2;
|
|
9483
|
-
const EVAPORATION = .1;
|
|
9579
|
+
const EVAPORATION$1 = .1;
|
|
9484
9580
|
const Q = 100;
|
|
9485
9581
|
const antColonySolver = {
|
|
9486
9582
|
id: "ant-colony",
|
|
@@ -9488,7 +9584,7 @@ const antColonySolver = {
|
|
|
9488
9584
|
description: "Swarm intelligence using pheromone trails to guide solution construction.",
|
|
9489
9585
|
async solve(problem, options) {
|
|
9490
9586
|
const startTime = performance.now();
|
|
9491
|
-
const
|
|
9587
|
+
const stop = makeScheduleStopper(options, startTime, 2e4);
|
|
9492
9588
|
const rng = createRng$1(42);
|
|
9493
9589
|
const allOps = buildOperationList(problem);
|
|
9494
9590
|
const numOps = allOps.length;
|
|
@@ -9496,10 +9592,14 @@ const antColonySolver = {
|
|
|
9496
9592
|
const heuristic = allOps.map((ref) => {
|
|
9497
9593
|
return 1 / problem.jobs.find((j) => j.id === ref.jobId).operations[ref.opIndex].duration;
|
|
9498
9594
|
});
|
|
9499
|
-
let bestMakespan = Infinity;
|
|
9500
9595
|
let bestSchedule = decodePermutation(allOps, problem);
|
|
9501
|
-
|
|
9502
|
-
|
|
9596
|
+
let bestMakespan = computeMakespan(bestSchedule);
|
|
9597
|
+
const trace = [{
|
|
9598
|
+
solution: bestSchedule,
|
|
9599
|
+
objective: bestMakespan
|
|
9600
|
+
}];
|
|
9601
|
+
for (let iter = 0; iter < ITERATIONS$1; iter++) {
|
|
9602
|
+
if (stop()) break;
|
|
9503
9603
|
const antSolutions = [];
|
|
9504
9604
|
for (let ant = 0; ant < NUM_ANTS; ant++) {
|
|
9505
9605
|
const perm = constructSolution(allOps, pheromone, heuristic, rng);
|
|
@@ -9512,9 +9612,10 @@ const antColonySolver = {
|
|
|
9512
9612
|
if (makespan < bestMakespan) {
|
|
9513
9613
|
bestMakespan = makespan;
|
|
9514
9614
|
bestSchedule = schedule;
|
|
9615
|
+
pushScheduleTrace(trace, bestSchedule, bestMakespan);
|
|
9515
9616
|
}
|
|
9516
9617
|
}
|
|
9517
|
-
for (let i = 0; i < numOps; i++) for (let j = 0; j < numOps; j++) pheromone[i][j] *= 1 - EVAPORATION;
|
|
9618
|
+
for (let i = 0; i < numOps; i++) for (let j = 0; j < numOps; j++) pheromone[i][j] *= 1 - EVAPORATION$1;
|
|
9518
9619
|
for (const solution of antSolutions) {
|
|
9519
9620
|
const deposit = Q / solution.makespan;
|
|
9520
9621
|
for (let pos = 0; pos < solution.perm.length; pos++) {
|
|
@@ -9524,20 +9625,21 @@ const antColonySolver = {
|
|
|
9524
9625
|
}
|
|
9525
9626
|
options?.onProgress?.({
|
|
9526
9627
|
solverId: "ant-colony",
|
|
9527
|
-
percentage: Math.round((iter + 1) / ITERATIONS * 100),
|
|
9528
|
-
bestMakespan,
|
|
9628
|
+
percentage: Math.round((iter + 1) / ITERATIONS$1 * 100),
|
|
9629
|
+
bestObjective: bestMakespan,
|
|
9529
9630
|
currentIteration: iter + 1,
|
|
9530
|
-
totalIterations: ITERATIONS
|
|
9631
|
+
totalIterations: ITERATIONS$1
|
|
9531
9632
|
});
|
|
9532
9633
|
}
|
|
9533
|
-
return {
|
|
9634
|
+
return makeSchedulingResult({
|
|
9534
9635
|
solverId: "ant-colony",
|
|
9535
9636
|
solverName: "Ant Colony Optimization",
|
|
9536
9637
|
makespan: bestMakespan,
|
|
9537
9638
|
schedule: bestSchedule,
|
|
9538
9639
|
elapsedMs: performance.now() - startTime,
|
|
9539
|
-
iterations: ITERATIONS * NUM_ANTS
|
|
9540
|
-
|
|
9640
|
+
iterations: ITERATIONS$1 * NUM_ANTS,
|
|
9641
|
+
trace
|
|
9642
|
+
});
|
|
9541
9643
|
}
|
|
9542
9644
|
};
|
|
9543
9645
|
/**
|
|
@@ -9783,23 +9885,18 @@ function validateSchedule(problem, schedule) {
|
|
|
9783
9885
|
errors
|
|
9784
9886
|
};
|
|
9785
9887
|
}
|
|
9786
|
-
|
|
9787
|
-
const MAX_TOTAL_OPS = 80;
|
|
9788
|
-
const MAX_OPS_PER_MACHINE = 8;
|
|
9789
|
-
/**
|
|
9790
|
-
* Load HiGHS - creates FRESH instance each time.
|
|
9791
|
-
*
|
|
9792
|
-
* We intentionally do NOT cache the HiGHS instance.
|
|
9793
|
-
* Caching causes WASM corruption errors.
|
|
9794
|
-
*/
|
|
9888
|
+
/** Load a fresh HiGHS WASM instance (never cache it — see file header). */
|
|
9795
9889
|
async function loadHiGHS() {
|
|
9796
9890
|
const highsLoader = (await import("highs")).default;
|
|
9797
|
-
return
|
|
9891
|
+
return highsLoader({ locateFile: (file) => {
|
|
9798
9892
|
const globalSelf = globalThis;
|
|
9799
9893
|
if (globalSelf.location?.origin) return `${globalSelf.location.origin}/${file}`;
|
|
9800
9894
|
return file;
|
|
9801
9895
|
} });
|
|
9802
9896
|
}
|
|
9897
|
+
const MAX_BINARY_VARS = 150;
|
|
9898
|
+
const MAX_TOTAL_OPS = 80;
|
|
9899
|
+
const MAX_OPS_PER_MACHINE = 8;
|
|
9803
9900
|
function elapsed(startTime) {
|
|
9804
9901
|
return typeof performance !== "undefined" ? performance.now() - startTime : Date.now() - startTime;
|
|
9805
9902
|
}
|
|
@@ -9813,7 +9910,7 @@ const highsSolver = {
|
|
|
9813
9910
|
options?.onProgress?.({
|
|
9814
9911
|
solverId: "highs",
|
|
9815
9912
|
percentage,
|
|
9816
|
-
bestMakespan
|
|
9913
|
+
bestObjective: bestMakespan
|
|
9817
9914
|
});
|
|
9818
9915
|
};
|
|
9819
9916
|
reportProgress(0);
|
|
@@ -9831,6 +9928,21 @@ const highsSolver = {
|
|
|
9831
9928
|
const lpString = generateLPFormulation(problem);
|
|
9832
9929
|
if (!lpString.includes("Subject To") || !lpString.includes("Bounds")) throw new Error("Invalid LP formulation - missing required sections");
|
|
9833
9930
|
reportProgress(20);
|
|
9931
|
+
if (options?.shouldCancel?.()) {
|
|
9932
|
+
const g = await greedySolver.solve(problem, {});
|
|
9933
|
+
return makeSchedulingResult({
|
|
9934
|
+
solverId: "highs",
|
|
9935
|
+
solverName: "HiGHS (WASM)",
|
|
9936
|
+
makespan: g.objective,
|
|
9937
|
+
schedule: g.solution,
|
|
9938
|
+
elapsedMs: elapsed(startTime),
|
|
9939
|
+
iterations: 0,
|
|
9940
|
+
metadata: {
|
|
9941
|
+
usedFallback: true,
|
|
9942
|
+
reason: "cancelled before HiGHS solve"
|
|
9943
|
+
}
|
|
9944
|
+
});
|
|
9945
|
+
}
|
|
9834
9946
|
let solution;
|
|
9835
9947
|
try {
|
|
9836
9948
|
solution = highs.solve(lpString, {
|
|
@@ -9863,14 +9975,18 @@ const highsSolver = {
|
|
|
9863
9975
|
throw new Error(`[HiGHS] Solution validation failed: ${errorDetails}`);
|
|
9864
9976
|
}
|
|
9865
9977
|
reportProgress(100, makespan);
|
|
9866
|
-
return {
|
|
9978
|
+
return makeSchedulingResult({
|
|
9867
9979
|
solverId: "highs",
|
|
9868
9980
|
solverName: "HiGHS (WASM)",
|
|
9869
9981
|
makespan,
|
|
9870
9982
|
schedule,
|
|
9871
9983
|
elapsedMs: elapsed(startTime),
|
|
9872
|
-
iterations: 1
|
|
9873
|
-
|
|
9984
|
+
iterations: 1,
|
|
9985
|
+
trace: [{
|
|
9986
|
+
solution: schedule,
|
|
9987
|
+
objective: makespan
|
|
9988
|
+
}]
|
|
9989
|
+
});
|
|
9874
9990
|
} catch (error) {
|
|
9875
9991
|
reportProgress(0);
|
|
9876
9992
|
throw error;
|
|
@@ -10514,30 +10630,39 @@ const allSolvers = [
|
|
|
10514
10630
|
solverId: "qaoa-local",
|
|
10515
10631
|
percentage: pct
|
|
10516
10632
|
});
|
|
10633
|
+
const cancelled = () => options.shouldCancel?.() ?? false;
|
|
10517
10634
|
progress(0);
|
|
10518
10635
|
const greedyResult = await greedySolver.solve(problem, {});
|
|
10519
10636
|
progress(10);
|
|
10520
|
-
const
|
|
10521
|
-
const
|
|
10637
|
+
const greedyMakespan = greedyResult.objective;
|
|
10638
|
+
const greedySchedule = greedyResult.solution;
|
|
10639
|
+
const greedyFallback = (reason) => makeSchedulingResult({
|
|
10640
|
+
solverId: "qaoa-local",
|
|
10641
|
+
solverName: "QAOA (Local)",
|
|
10642
|
+
makespan: greedyMakespan,
|
|
10643
|
+
schedule: greedySchedule,
|
|
10644
|
+
elapsedMs: elapsed(),
|
|
10645
|
+
trace: [{
|
|
10646
|
+
solution: greedySchedule,
|
|
10647
|
+
objective: greedyMakespan
|
|
10648
|
+
}],
|
|
10649
|
+
metadata: {
|
|
10650
|
+
layers: LAYERS$1,
|
|
10651
|
+
shots: 0,
|
|
10652
|
+
gamma: 0,
|
|
10653
|
+
beta: 0,
|
|
10654
|
+
rawMakespan: greedyMakespan,
|
|
10655
|
+
usedFallback: true,
|
|
10656
|
+
reason
|
|
10657
|
+
}
|
|
10658
|
+
});
|
|
10659
|
+
const encoded = encodeSchedulingWithMetadata(problem, greedyMakespan);
|
|
10522
10660
|
const numQubits = encoded.qubo.size;
|
|
10523
10661
|
if (numQubits > MAX_QUBITS || numQubits === 0) {
|
|
10524
10662
|
progress(100);
|
|
10525
|
-
return {
|
|
10526
|
-
solverId: "qaoa-local",
|
|
10527
|
-
solverName: "QAOA (Local)",
|
|
10528
|
-
makespan: greedyResult.makespan,
|
|
10529
|
-
schedule: greedyResult.schedule,
|
|
10530
|
-
elapsedMs: elapsed(),
|
|
10531
|
-
metadata: {
|
|
10532
|
-
layers: LAYERS$1,
|
|
10533
|
-
shots: 0,
|
|
10534
|
-
gamma: 0,
|
|
10535
|
-
beta: 0,
|
|
10536
|
-
rawMakespan: greedyResult.makespan,
|
|
10537
|
-
usedFallback: true
|
|
10538
|
-
}
|
|
10539
|
-
};
|
|
10663
|
+
return greedyFallback(numQubits === 0 ? "no qubits to encode" : `instance needs ${numQubits} qubits (cap ${MAX_QUBITS})`);
|
|
10540
10664
|
}
|
|
10665
|
+
if (cancelled()) return greedyFallback("cancelled");
|
|
10541
10666
|
const ising = quboToIsing(encoded.qubo);
|
|
10542
10667
|
const backend = new LocalSimBackend();
|
|
10543
10668
|
progress(20);
|
|
@@ -10547,30 +10672,39 @@ const allSolvers = [
|
|
|
10547
10672
|
p: LAYERS$1
|
|
10548
10673
|
});
|
|
10549
10674
|
progress(75);
|
|
10675
|
+
if (cancelled()) return greedyFallback("cancelled");
|
|
10550
10676
|
const gates = buildQAOACircuit(numQubits, ising, [gamma], [beta], LAYERS$1);
|
|
10551
10677
|
const { probabilities } = await backend.run(numQubits, gates);
|
|
10552
10678
|
const samples = sampleFromProbabilities(probabilities, FINAL_SHOTS$1);
|
|
10553
10679
|
progress(90);
|
|
10554
|
-
const candidates = [decodeFromArgmax(problem, encoded.variables, probabilities,
|
|
10680
|
+
const candidates = [decodeFromArgmax(problem, encoded.variables, probabilities, greedySchedule), decodeSamples(problem, encoded.variables, samples)].filter((d) => d !== null);
|
|
10555
10681
|
const bestQuantum = candidates.length > 0 ? candidates.reduce((a, b) => b.makespan < a.makespan ? b : a) : null;
|
|
10556
|
-
const usedFallback = bestQuantum === null || bestQuantum.makespan >=
|
|
10557
|
-
const
|
|
10682
|
+
const usedFallback = bestQuantum === null || bestQuantum.makespan >= greedyMakespan;
|
|
10683
|
+
const winnerMakespan = usedFallback ? greedyMakespan : bestQuantum.makespan;
|
|
10684
|
+
const winnerSchedule = usedFallback ? greedySchedule : bestQuantum.schedule;
|
|
10558
10685
|
progress(100);
|
|
10559
|
-
return {
|
|
10686
|
+
return makeSchedulingResult({
|
|
10560
10687
|
solverId: "qaoa-local",
|
|
10561
10688
|
solverName: "QAOA (Local)",
|
|
10562
|
-
makespan:
|
|
10563
|
-
schedule:
|
|
10689
|
+
makespan: winnerMakespan,
|
|
10690
|
+
schedule: winnerSchedule,
|
|
10564
10691
|
elapsedMs: elapsed(),
|
|
10692
|
+
trace: [{
|
|
10693
|
+
solution: greedySchedule,
|
|
10694
|
+
objective: greedyMakespan
|
|
10695
|
+
}, {
|
|
10696
|
+
solution: winnerSchedule,
|
|
10697
|
+
objective: winnerMakespan
|
|
10698
|
+
}],
|
|
10565
10699
|
metadata: {
|
|
10566
10700
|
layers: LAYERS$1,
|
|
10567
10701
|
shots: FINAL_SHOTS$1,
|
|
10568
10702
|
gamma,
|
|
10569
10703
|
beta,
|
|
10570
|
-
rawMakespan: bestQuantum?.makespan ??
|
|
10704
|
+
rawMakespan: bestQuantum?.makespan ?? greedyMakespan,
|
|
10571
10705
|
usedFallback
|
|
10572
10706
|
}
|
|
10573
|
-
};
|
|
10707
|
+
});
|
|
10574
10708
|
}
|
|
10575
10709
|
}
|
|
10576
10710
|
];
|
|
@@ -10869,54 +11003,1966 @@ No markdown, no explanation, no code blocks — just the raw JSON object.`;
|
|
|
10869
11003
|
" \\/ <- fit here",
|
|
10870
11004
|
"Minimize: sum(error^2)"
|
|
10871
11005
|
].join("\n");
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
11006
|
+
const routingSampleProblems = [
|
|
11007
|
+
{
|
|
11008
|
+
family: "routing",
|
|
11009
|
+
name: "Austin Food Truck Circuit",
|
|
11010
|
+
description: "A food truck owner wants the shortest nightly loop hitting ten Austin hotspots, starting and ending at the South Lamar commissary.",
|
|
11011
|
+
nodes: [
|
|
11012
|
+
{
|
|
11013
|
+
id: 0,
|
|
11014
|
+
name: "Commissary (S Lamar)",
|
|
11015
|
+
x: 38,
|
|
11016
|
+
y: 72
|
|
11017
|
+
},
|
|
11018
|
+
{
|
|
11019
|
+
id: 1,
|
|
11020
|
+
name: "Zilker Park",
|
|
11021
|
+
x: 30,
|
|
11022
|
+
y: 58
|
|
11023
|
+
},
|
|
11024
|
+
{
|
|
11025
|
+
id: 2,
|
|
11026
|
+
name: "Rainey St",
|
|
11027
|
+
x: 56,
|
|
11028
|
+
y: 60
|
|
11029
|
+
},
|
|
11030
|
+
{
|
|
11031
|
+
id: 3,
|
|
11032
|
+
name: "6th & Red River",
|
|
11033
|
+
x: 54,
|
|
11034
|
+
y: 48
|
|
11035
|
+
},
|
|
11036
|
+
{
|
|
11037
|
+
id: 4,
|
|
11038
|
+
name: "UT Campus",
|
|
11039
|
+
x: 52,
|
|
11040
|
+
y: 32
|
|
11041
|
+
},
|
|
11042
|
+
{
|
|
11043
|
+
id: 5,
|
|
11044
|
+
name: "Mueller Market",
|
|
11045
|
+
x: 72,
|
|
11046
|
+
y: 30
|
|
11047
|
+
},
|
|
11048
|
+
{
|
|
11049
|
+
id: 6,
|
|
11050
|
+
name: "East Cesar Chavez",
|
|
11051
|
+
x: 70,
|
|
11052
|
+
y: 56
|
|
11053
|
+
},
|
|
11054
|
+
{
|
|
11055
|
+
id: 7,
|
|
11056
|
+
name: "Barton Springs",
|
|
11057
|
+
x: 34,
|
|
11058
|
+
y: 64
|
|
11059
|
+
},
|
|
11060
|
+
{
|
|
11061
|
+
id: 8,
|
|
11062
|
+
name: "The Domain",
|
|
11063
|
+
x: 44,
|
|
11064
|
+
y: 8
|
|
11065
|
+
},
|
|
11066
|
+
{
|
|
11067
|
+
id: 9,
|
|
11068
|
+
name: "Oak Hill",
|
|
11069
|
+
x: 12,
|
|
11070
|
+
y: 86
|
|
11071
|
+
}
|
|
11072
|
+
]
|
|
11073
|
+
},
|
|
11074
|
+
{
|
|
11075
|
+
family: "routing",
|
|
11076
|
+
name: "Kyiv Drone Resupply Run",
|
|
11077
|
+
description: "A logistics drone must visit twelve forward supply caches and return to base on one battery. Every wasted kilometer is flight time the battery does not have.",
|
|
11078
|
+
nodes: [
|
|
11079
|
+
{
|
|
11080
|
+
id: 0,
|
|
11081
|
+
name: "Base",
|
|
11082
|
+
x: 50,
|
|
11083
|
+
y: 92
|
|
11084
|
+
},
|
|
11085
|
+
{
|
|
11086
|
+
id: 1,
|
|
11087
|
+
name: "Cache Alpha",
|
|
11088
|
+
x: 18,
|
|
11089
|
+
y: 74
|
|
11090
|
+
},
|
|
11091
|
+
{
|
|
11092
|
+
id: 2,
|
|
11093
|
+
name: "Cache Bravo",
|
|
11094
|
+
x: 10,
|
|
11095
|
+
y: 48
|
|
11096
|
+
},
|
|
11097
|
+
{
|
|
11098
|
+
id: 3,
|
|
11099
|
+
name: "Cache Charlie",
|
|
11100
|
+
x: 24,
|
|
11101
|
+
y: 22
|
|
11102
|
+
},
|
|
11103
|
+
{
|
|
11104
|
+
id: 4,
|
|
11105
|
+
name: "Cache Delta",
|
|
11106
|
+
x: 44,
|
|
11107
|
+
y: 10
|
|
11108
|
+
},
|
|
11109
|
+
{
|
|
11110
|
+
id: 5,
|
|
11111
|
+
name: "Cache Echo",
|
|
11112
|
+
x: 66,
|
|
11113
|
+
y: 14
|
|
11114
|
+
},
|
|
11115
|
+
{
|
|
11116
|
+
id: 6,
|
|
11117
|
+
name: "Cache Foxtrot",
|
|
11118
|
+
x: 86,
|
|
11119
|
+
y: 26
|
|
11120
|
+
},
|
|
11121
|
+
{
|
|
11122
|
+
id: 7,
|
|
11123
|
+
name: "Cache Golf",
|
|
11124
|
+
x: 92,
|
|
11125
|
+
y: 52
|
|
11126
|
+
},
|
|
11127
|
+
{
|
|
11128
|
+
id: 8,
|
|
11129
|
+
name: "Cache Hotel",
|
|
11130
|
+
x: 80,
|
|
11131
|
+
y: 72
|
|
11132
|
+
},
|
|
11133
|
+
{
|
|
11134
|
+
id: 9,
|
|
11135
|
+
name: "Cache India",
|
|
11136
|
+
x: 62,
|
|
11137
|
+
y: 56
|
|
11138
|
+
},
|
|
11139
|
+
{
|
|
11140
|
+
id: 10,
|
|
11141
|
+
name: "Cache Juliet",
|
|
11142
|
+
x: 38,
|
|
11143
|
+
y: 44
|
|
11144
|
+
},
|
|
11145
|
+
{
|
|
11146
|
+
id: 11,
|
|
11147
|
+
name: "Cache Kilo",
|
|
11148
|
+
x: 30,
|
|
11149
|
+
y: 60
|
|
11150
|
+
}
|
|
11151
|
+
]
|
|
11152
|
+
},
|
|
11153
|
+
{
|
|
11154
|
+
family: "routing",
|
|
11155
|
+
name: "Hill Country Brewery Tour",
|
|
11156
|
+
description: "Eight breweries, one designated-driver van, and a hard rule: end where you started. Minimize the drive so there is more time for the beer.",
|
|
11157
|
+
nodes: [
|
|
11158
|
+
{
|
|
11159
|
+
id: 0,
|
|
11160
|
+
name: "Depot (Dripping Springs)",
|
|
11161
|
+
x: 20,
|
|
11162
|
+
y: 60
|
|
11163
|
+
},
|
|
11164
|
+
{
|
|
11165
|
+
id: 1,
|
|
11166
|
+
name: "Jester King",
|
|
11167
|
+
x: 32,
|
|
11168
|
+
y: 48
|
|
11169
|
+
},
|
|
11170
|
+
{
|
|
11171
|
+
id: 2,
|
|
11172
|
+
name: "Vista Brewing",
|
|
11173
|
+
x: 16,
|
|
11174
|
+
y: 78
|
|
11175
|
+
},
|
|
11176
|
+
{
|
|
11177
|
+
id: 3,
|
|
11178
|
+
name: "Treaty Oak",
|
|
11179
|
+
x: 28,
|
|
11180
|
+
y: 70
|
|
11181
|
+
},
|
|
11182
|
+
{
|
|
11183
|
+
id: 4,
|
|
11184
|
+
name: "Last Stand",
|
|
11185
|
+
x: 46,
|
|
11186
|
+
y: 38
|
|
11187
|
+
},
|
|
11188
|
+
{
|
|
11189
|
+
id: 5,
|
|
11190
|
+
name: "Fitzhugh Brewing",
|
|
11191
|
+
x: 40,
|
|
11192
|
+
y: 56
|
|
11193
|
+
},
|
|
11194
|
+
{
|
|
11195
|
+
id: 6,
|
|
11196
|
+
name: "Family Business",
|
|
11197
|
+
x: 60,
|
|
11198
|
+
y: 30
|
|
11199
|
+
},
|
|
11200
|
+
{
|
|
11201
|
+
id: 7,
|
|
11202
|
+
name: "Suds Monkey",
|
|
11203
|
+
x: 24,
|
|
11204
|
+
y: 52
|
|
11205
|
+
}
|
|
11206
|
+
]
|
|
11207
|
+
}
|
|
11208
|
+
];
|
|
11209
|
+
const packingSampleProblems = [
|
|
11210
|
+
{
|
|
11211
|
+
family: "packing",
|
|
11212
|
+
name: "Mars Cargo Manifest",
|
|
11213
|
+
description: "Fourteen payload modules must ride to orbit in standardized cargo pods. Every pod you do not launch saves nine figures.",
|
|
11214
|
+
binCapacity: 100,
|
|
11215
|
+
binLabel: "pod",
|
|
11216
|
+
items: [
|
|
11217
|
+
{
|
|
11218
|
+
id: 0,
|
|
11219
|
+
name: "Habitat Frame",
|
|
11220
|
+
size: 62
|
|
11221
|
+
},
|
|
11222
|
+
{
|
|
11223
|
+
id: 1,
|
|
11224
|
+
name: "Water Recycler",
|
|
11225
|
+
size: 48
|
|
11226
|
+
},
|
|
11227
|
+
{
|
|
11228
|
+
id: 2,
|
|
11229
|
+
name: "Solar Array A",
|
|
11230
|
+
size: 55
|
|
11231
|
+
},
|
|
11232
|
+
{
|
|
11233
|
+
id: 3,
|
|
11234
|
+
name: "Solar Array B",
|
|
11235
|
+
size: 55
|
|
11236
|
+
},
|
|
11237
|
+
{
|
|
11238
|
+
id: 4,
|
|
11239
|
+
name: "Rover Chassis",
|
|
11240
|
+
size: 70
|
|
11241
|
+
},
|
|
11242
|
+
{
|
|
11243
|
+
id: 5,
|
|
11244
|
+
name: "Lab Module",
|
|
11245
|
+
size: 38
|
|
11246
|
+
},
|
|
11247
|
+
{
|
|
11248
|
+
id: 6,
|
|
11249
|
+
name: "Greenhouse Kit",
|
|
11250
|
+
size: 42
|
|
11251
|
+
},
|
|
11252
|
+
{
|
|
11253
|
+
id: 7,
|
|
11254
|
+
name: "Battery Bank",
|
|
11255
|
+
size: 30
|
|
11256
|
+
},
|
|
11257
|
+
{
|
|
11258
|
+
id: 8,
|
|
11259
|
+
name: "Antenna Mast",
|
|
11260
|
+
size: 22
|
|
11261
|
+
},
|
|
11262
|
+
{
|
|
11263
|
+
id: 9,
|
|
11264
|
+
name: "Med Bay Kit",
|
|
11265
|
+
size: 26
|
|
11266
|
+
},
|
|
11267
|
+
{
|
|
11268
|
+
id: 10,
|
|
11269
|
+
name: "Spare Parts Crate",
|
|
11270
|
+
size: 18
|
|
11271
|
+
},
|
|
11272
|
+
{
|
|
11273
|
+
id: 11,
|
|
11274
|
+
name: "Food Stores",
|
|
11275
|
+
size: 44
|
|
11276
|
+
},
|
|
11277
|
+
{
|
|
11278
|
+
id: 12,
|
|
11279
|
+
name: "Drill Assembly",
|
|
11280
|
+
size: 34
|
|
11281
|
+
},
|
|
11282
|
+
{
|
|
11283
|
+
id: 13,
|
|
11284
|
+
name: "3D Printer",
|
|
11285
|
+
size: 16
|
|
11286
|
+
}
|
|
11287
|
+
]
|
|
11288
|
+
},
|
|
11289
|
+
{
|
|
11290
|
+
family: "packing",
|
|
11291
|
+
name: "Moving Day — Oak Hill",
|
|
11292
|
+
description: "Everything Erik owns has to fit into rented trucks. Each truck costs $180 a day, so the optimizer IS the budget.",
|
|
11293
|
+
binCapacity: 80,
|
|
11294
|
+
binLabel: "truck",
|
|
11295
|
+
items: [
|
|
11296
|
+
{
|
|
11297
|
+
id: 0,
|
|
11298
|
+
name: "Couch",
|
|
11299
|
+
size: 40
|
|
11300
|
+
},
|
|
11301
|
+
{
|
|
11302
|
+
id: 1,
|
|
11303
|
+
name: "Bed Frame",
|
|
11304
|
+
size: 32
|
|
11305
|
+
},
|
|
11306
|
+
{
|
|
11307
|
+
id: 2,
|
|
11308
|
+
name: "Mattress",
|
|
11309
|
+
size: 28
|
|
11310
|
+
},
|
|
11311
|
+
{
|
|
11312
|
+
id: 3,
|
|
11313
|
+
name: "Dining Table",
|
|
11314
|
+
size: 30
|
|
11315
|
+
},
|
|
11316
|
+
{
|
|
11317
|
+
id: 4,
|
|
11318
|
+
name: "Bookshelves",
|
|
11319
|
+
size: 24
|
|
11320
|
+
},
|
|
11321
|
+
{
|
|
11322
|
+
id: 5,
|
|
11323
|
+
name: "Desk Battlestation",
|
|
11324
|
+
size: 36
|
|
11325
|
+
},
|
|
11326
|
+
{
|
|
11327
|
+
id: 6,
|
|
11328
|
+
name: "Arcade Cabinet",
|
|
11329
|
+
size: 44
|
|
11330
|
+
},
|
|
11331
|
+
{
|
|
11332
|
+
id: 7,
|
|
11333
|
+
name: "Kitchen Boxes",
|
|
11334
|
+
size: 20
|
|
11335
|
+
},
|
|
11336
|
+
{
|
|
11337
|
+
id: 8,
|
|
11338
|
+
name: "Book Boxes",
|
|
11339
|
+
size: 26
|
|
11340
|
+
},
|
|
11341
|
+
{
|
|
11342
|
+
id: 9,
|
|
11343
|
+
name: "Garage Tools",
|
|
11344
|
+
size: 18
|
|
11345
|
+
},
|
|
11346
|
+
{
|
|
11347
|
+
id: 10,
|
|
11348
|
+
name: "Bikes",
|
|
11349
|
+
size: 16
|
|
11350
|
+
},
|
|
11351
|
+
{
|
|
11352
|
+
id: 11,
|
|
11353
|
+
name: "Server Rack",
|
|
11354
|
+
size: 22
|
|
11355
|
+
}
|
|
11356
|
+
]
|
|
11357
|
+
},
|
|
11358
|
+
{
|
|
11359
|
+
family: "packing",
|
|
11360
|
+
name: "Server Rack Tetris",
|
|
11361
|
+
description: "Thirteen VM workloads need hosts. Each host burns power whether it is full or idle — consolidate or pay.",
|
|
11362
|
+
binCapacity: 64,
|
|
11363
|
+
binLabel: "host",
|
|
11364
|
+
items: [
|
|
11365
|
+
{
|
|
11366
|
+
id: 0,
|
|
11367
|
+
name: "Postgres Primary",
|
|
11368
|
+
size: 32
|
|
11369
|
+
},
|
|
11370
|
+
{
|
|
11371
|
+
id: 1,
|
|
11372
|
+
name: "Postgres Replica",
|
|
11373
|
+
size: 24
|
|
11374
|
+
},
|
|
11375
|
+
{
|
|
11376
|
+
id: 2,
|
|
11377
|
+
name: "Web Frontend x4",
|
|
11378
|
+
size: 16
|
|
11379
|
+
},
|
|
11380
|
+
{
|
|
11381
|
+
id: 3,
|
|
11382
|
+
name: "API Cluster",
|
|
11383
|
+
size: 28
|
|
11384
|
+
},
|
|
11385
|
+
{
|
|
11386
|
+
id: 4,
|
|
11387
|
+
name: "Redis Cache",
|
|
11388
|
+
size: 12
|
|
11389
|
+
},
|
|
11390
|
+
{
|
|
11391
|
+
id: 5,
|
|
11392
|
+
name: "ML Inference",
|
|
11393
|
+
size: 48
|
|
11394
|
+
},
|
|
11395
|
+
{
|
|
11396
|
+
id: 6,
|
|
11397
|
+
name: "CI Runners",
|
|
11398
|
+
size: 20
|
|
11399
|
+
},
|
|
11400
|
+
{
|
|
11401
|
+
id: 7,
|
|
11402
|
+
name: "Log Pipeline",
|
|
11403
|
+
size: 14
|
|
11404
|
+
},
|
|
11405
|
+
{
|
|
11406
|
+
id: 8,
|
|
11407
|
+
name: "Metrics Stack",
|
|
11408
|
+
size: 18
|
|
11409
|
+
},
|
|
11410
|
+
{
|
|
11411
|
+
id: 9,
|
|
11412
|
+
name: "Batch ETL",
|
|
11413
|
+
size: 26
|
|
11414
|
+
},
|
|
11415
|
+
{
|
|
11416
|
+
id: 10,
|
|
11417
|
+
name: "Search Index",
|
|
11418
|
+
size: 22
|
|
11419
|
+
},
|
|
11420
|
+
{
|
|
11421
|
+
id: 11,
|
|
11422
|
+
name: "Mail Service",
|
|
11423
|
+
size: 8
|
|
11424
|
+
},
|
|
11425
|
+
{
|
|
11426
|
+
id: 12,
|
|
11427
|
+
name: "Backup Agent",
|
|
11428
|
+
size: 10
|
|
11429
|
+
}
|
|
11430
|
+
]
|
|
11431
|
+
}
|
|
11432
|
+
];
|
|
11433
|
+
const assignmentSampleProblems = [
|
|
11434
|
+
{
|
|
11435
|
+
family: "assignment",
|
|
11436
|
+
name: "Raid Roster",
|
|
11437
|
+
description: "Eight raiders, eight roles, one progression night. The cost matrix is each player's discomfort in each role — minimize total grumbling.",
|
|
11438
|
+
agents: [
|
|
11439
|
+
{
|
|
11440
|
+
id: 0,
|
|
11441
|
+
name: "Thorgrim"
|
|
11442
|
+
},
|
|
11443
|
+
{
|
|
11444
|
+
id: 1,
|
|
11445
|
+
name: "Lyralei"
|
|
11446
|
+
},
|
|
11447
|
+
{
|
|
11448
|
+
id: 2,
|
|
11449
|
+
name: "Mogrash"
|
|
11450
|
+
},
|
|
11451
|
+
{
|
|
11452
|
+
id: 3,
|
|
11453
|
+
name: "Seraphine"
|
|
11454
|
+
},
|
|
11455
|
+
{
|
|
11456
|
+
id: 4,
|
|
11457
|
+
name: "Kettle"
|
|
11458
|
+
},
|
|
11459
|
+
{
|
|
11460
|
+
id: 5,
|
|
11461
|
+
name: "Vexx"
|
|
11462
|
+
},
|
|
11463
|
+
{
|
|
11464
|
+
id: 6,
|
|
11465
|
+
name: "Oakenheart"
|
|
11466
|
+
},
|
|
11467
|
+
{
|
|
11468
|
+
id: 7,
|
|
11469
|
+
name: "Zinnia"
|
|
11470
|
+
}
|
|
11471
|
+
],
|
|
11472
|
+
tasks: [
|
|
11473
|
+
{
|
|
11474
|
+
id: 0,
|
|
11475
|
+
name: "Main Tank"
|
|
11476
|
+
},
|
|
11477
|
+
{
|
|
11478
|
+
id: 1,
|
|
11479
|
+
name: "Off Tank"
|
|
11480
|
+
},
|
|
11481
|
+
{
|
|
11482
|
+
id: 2,
|
|
11483
|
+
name: "Healer 1"
|
|
11484
|
+
},
|
|
11485
|
+
{
|
|
11486
|
+
id: 3,
|
|
11487
|
+
name: "Healer 2"
|
|
11488
|
+
},
|
|
11489
|
+
{
|
|
11490
|
+
id: 4,
|
|
11491
|
+
name: "Melee DPS"
|
|
11492
|
+
},
|
|
11493
|
+
{
|
|
11494
|
+
id: 5,
|
|
11495
|
+
name: "Ranged DPS"
|
|
11496
|
+
},
|
|
11497
|
+
{
|
|
11498
|
+
id: 6,
|
|
11499
|
+
name: "Raid Lead"
|
|
11500
|
+
},
|
|
11501
|
+
{
|
|
11502
|
+
id: 7,
|
|
11503
|
+
name: "Loot Council"
|
|
11504
|
+
}
|
|
11505
|
+
],
|
|
11506
|
+
cost: [
|
|
11507
|
+
[
|
|
11508
|
+
2,
|
|
11509
|
+
4,
|
|
11510
|
+
9,
|
|
11511
|
+
9,
|
|
11512
|
+
5,
|
|
11513
|
+
7,
|
|
11514
|
+
6,
|
|
11515
|
+
8
|
|
11516
|
+
],
|
|
11517
|
+
[
|
|
11518
|
+
9,
|
|
11519
|
+
8,
|
|
11520
|
+
2,
|
|
11521
|
+
3,
|
|
11522
|
+
7,
|
|
11523
|
+
5,
|
|
11524
|
+
6,
|
|
11525
|
+
4
|
|
11526
|
+
],
|
|
11527
|
+
[
|
|
11528
|
+
3,
|
|
11529
|
+
2,
|
|
11530
|
+
9,
|
|
11531
|
+
8,
|
|
11532
|
+
4,
|
|
11533
|
+
6,
|
|
11534
|
+
7,
|
|
11535
|
+
9
|
|
11536
|
+
],
|
|
11537
|
+
[
|
|
11538
|
+
8,
|
|
11539
|
+
9,
|
|
11540
|
+
3,
|
|
11541
|
+
2,
|
|
11542
|
+
6,
|
|
11543
|
+
4,
|
|
11544
|
+
5,
|
|
11545
|
+
6
|
|
11546
|
+
],
|
|
11547
|
+
[
|
|
11548
|
+
7,
|
|
11549
|
+
6,
|
|
11550
|
+
5,
|
|
11551
|
+
5,
|
|
11552
|
+
2,
|
|
11553
|
+
3,
|
|
11554
|
+
8,
|
|
11555
|
+
7
|
|
11556
|
+
],
|
|
11557
|
+
[
|
|
11558
|
+
6,
|
|
11559
|
+
7,
|
|
11560
|
+
6,
|
|
11561
|
+
6,
|
|
11562
|
+
3,
|
|
11563
|
+
2,
|
|
11564
|
+
4,
|
|
11565
|
+
5
|
|
11566
|
+
],
|
|
11567
|
+
[
|
|
11568
|
+
4,
|
|
11569
|
+
3,
|
|
11570
|
+
7,
|
|
11571
|
+
7,
|
|
11572
|
+
5,
|
|
11573
|
+
6,
|
|
11574
|
+
2,
|
|
11575
|
+
3
|
|
11576
|
+
],
|
|
11577
|
+
[
|
|
11578
|
+
9,
|
|
11579
|
+
8,
|
|
11580
|
+
4,
|
|
11581
|
+
4,
|
|
11582
|
+
6,
|
|
11583
|
+
5,
|
|
11584
|
+
3,
|
|
11585
|
+
2
|
|
11586
|
+
]
|
|
11587
|
+
]
|
|
11588
|
+
},
|
|
11589
|
+
{
|
|
11590
|
+
family: "assignment",
|
|
11591
|
+
name: "Surgery Suite Staffing",
|
|
11592
|
+
description: "Six surgeons, six operating rooms with different specialties on the board today. Cost = mismatch between surgeon expertise and case type.",
|
|
11593
|
+
agents: [
|
|
11594
|
+
{
|
|
11595
|
+
id: 0,
|
|
11596
|
+
name: "Dr. Asante"
|
|
11597
|
+
},
|
|
11598
|
+
{
|
|
11599
|
+
id: 1,
|
|
11600
|
+
name: "Dr. Brook"
|
|
11601
|
+
},
|
|
11602
|
+
{
|
|
11603
|
+
id: 2,
|
|
11604
|
+
name: "Dr. Chen"
|
|
11605
|
+
},
|
|
11606
|
+
{
|
|
11607
|
+
id: 3,
|
|
11608
|
+
name: "Dr. Duarte"
|
|
11609
|
+
},
|
|
11610
|
+
{
|
|
11611
|
+
id: 4,
|
|
11612
|
+
name: "Dr. Eze"
|
|
11613
|
+
},
|
|
11614
|
+
{
|
|
11615
|
+
id: 5,
|
|
11616
|
+
name: "Dr. Farrow"
|
|
11617
|
+
}
|
|
11618
|
+
],
|
|
11619
|
+
tasks: [
|
|
11620
|
+
{
|
|
11621
|
+
id: 0,
|
|
11622
|
+
name: "OR-1 Cardiac"
|
|
11623
|
+
},
|
|
11624
|
+
{
|
|
11625
|
+
id: 1,
|
|
11626
|
+
name: "OR-2 Ortho"
|
|
11627
|
+
},
|
|
11628
|
+
{
|
|
11629
|
+
id: 2,
|
|
11630
|
+
name: "OR-3 Neuro"
|
|
11631
|
+
},
|
|
11632
|
+
{
|
|
11633
|
+
id: 3,
|
|
11634
|
+
name: "OR-4 General"
|
|
11635
|
+
},
|
|
11636
|
+
{
|
|
11637
|
+
id: 4,
|
|
11638
|
+
name: "OR-5 Pediatric"
|
|
11639
|
+
},
|
|
11640
|
+
{
|
|
11641
|
+
id: 5,
|
|
11642
|
+
name: "OR-6 Trauma"
|
|
11643
|
+
}
|
|
11644
|
+
],
|
|
11645
|
+
cost: [
|
|
11646
|
+
[
|
|
11647
|
+
1,
|
|
11648
|
+
8,
|
|
11649
|
+
9,
|
|
11650
|
+
4,
|
|
11651
|
+
7,
|
|
11652
|
+
5
|
|
11653
|
+
],
|
|
11654
|
+
[
|
|
11655
|
+
9,
|
|
11656
|
+
1,
|
|
11657
|
+
8,
|
|
11658
|
+
5,
|
|
11659
|
+
6,
|
|
11660
|
+
3
|
|
11661
|
+
],
|
|
11662
|
+
[
|
|
11663
|
+
8,
|
|
11664
|
+
9,
|
|
11665
|
+
1,
|
|
11666
|
+
6,
|
|
11667
|
+
5,
|
|
11668
|
+
7
|
|
11669
|
+
],
|
|
11670
|
+
[
|
|
11671
|
+
5,
|
|
11672
|
+
4,
|
|
11673
|
+
7,
|
|
11674
|
+
1,
|
|
11675
|
+
3,
|
|
11676
|
+
2
|
|
11677
|
+
],
|
|
11678
|
+
[
|
|
11679
|
+
7,
|
|
11680
|
+
6,
|
|
11681
|
+
5,
|
|
11682
|
+
3,
|
|
11683
|
+
1,
|
|
11684
|
+
4
|
|
11685
|
+
],
|
|
11686
|
+
[
|
|
11687
|
+
4,
|
|
11688
|
+
3,
|
|
11689
|
+
6,
|
|
11690
|
+
2,
|
|
11691
|
+
4,
|
|
11692
|
+
1
|
|
11693
|
+
]
|
|
11694
|
+
]
|
|
11695
|
+
},
|
|
11696
|
+
{
|
|
11697
|
+
family: "assignment",
|
|
11698
|
+
name: "Support Ticket Triage",
|
|
11699
|
+
description: "Seven engineers, nine open escalations — two will wait. Cost = estimated hours for each engineer on each ticket given their domain depth.",
|
|
11700
|
+
agents: [
|
|
11701
|
+
{
|
|
11702
|
+
id: 0,
|
|
11703
|
+
name: "Imani"
|
|
11704
|
+
},
|
|
11705
|
+
{
|
|
11706
|
+
id: 1,
|
|
11707
|
+
name: "Jonas"
|
|
11708
|
+
},
|
|
11709
|
+
{
|
|
11710
|
+
id: 2,
|
|
11711
|
+
name: "Kai"
|
|
11712
|
+
},
|
|
11713
|
+
{
|
|
11714
|
+
id: 3,
|
|
11715
|
+
name: "Lena"
|
|
11716
|
+
},
|
|
11717
|
+
{
|
|
11718
|
+
id: 4,
|
|
11719
|
+
name: "Marcus"
|
|
11720
|
+
},
|
|
11721
|
+
{
|
|
11722
|
+
id: 5,
|
|
11723
|
+
name: "Noor"
|
|
11724
|
+
},
|
|
11725
|
+
{
|
|
11726
|
+
id: 6,
|
|
11727
|
+
name: "Owen"
|
|
11728
|
+
}
|
|
11729
|
+
],
|
|
11730
|
+
tasks: [
|
|
11731
|
+
{
|
|
11732
|
+
id: 0,
|
|
11733
|
+
name: "Auth outage"
|
|
11734
|
+
},
|
|
11735
|
+
{
|
|
11736
|
+
id: 1,
|
|
11737
|
+
name: "Billing drift"
|
|
11738
|
+
},
|
|
11739
|
+
{
|
|
11740
|
+
id: 2,
|
|
11741
|
+
name: "Mobile crash"
|
|
11742
|
+
},
|
|
11743
|
+
{
|
|
11744
|
+
id: 3,
|
|
11745
|
+
name: "Search latency"
|
|
11746
|
+
},
|
|
11747
|
+
{
|
|
11748
|
+
id: 4,
|
|
11749
|
+
name: "Data export"
|
|
11750
|
+
},
|
|
11751
|
+
{
|
|
11752
|
+
id: 5,
|
|
11753
|
+
name: "Webhook storm"
|
|
11754
|
+
},
|
|
11755
|
+
{
|
|
11756
|
+
id: 6,
|
|
11757
|
+
name: "SSO config"
|
|
11758
|
+
},
|
|
11759
|
+
{
|
|
11760
|
+
id: 7,
|
|
11761
|
+
name: "Rate limiter"
|
|
11762
|
+
},
|
|
11763
|
+
{
|
|
11764
|
+
id: 8,
|
|
11765
|
+
name: "PDF renderer"
|
|
11766
|
+
}
|
|
11767
|
+
],
|
|
11768
|
+
cost: [
|
|
11769
|
+
[
|
|
11770
|
+
2,
|
|
11771
|
+
7,
|
|
11772
|
+
9,
|
|
11773
|
+
6,
|
|
11774
|
+
5,
|
|
11775
|
+
4,
|
|
11776
|
+
3,
|
|
11777
|
+
5,
|
|
11778
|
+
8
|
|
11779
|
+
],
|
|
11780
|
+
[
|
|
11781
|
+
8,
|
|
11782
|
+
2,
|
|
11783
|
+
7,
|
|
11784
|
+
5,
|
|
11785
|
+
3,
|
|
11786
|
+
6,
|
|
11787
|
+
7,
|
|
11788
|
+
6,
|
|
11789
|
+
4
|
|
11790
|
+
],
|
|
11791
|
+
[
|
|
11792
|
+
9,
|
|
11793
|
+
6,
|
|
11794
|
+
2,
|
|
11795
|
+
7,
|
|
11796
|
+
6,
|
|
11797
|
+
5,
|
|
11798
|
+
8,
|
|
11799
|
+
7,
|
|
11800
|
+
3
|
|
11801
|
+
],
|
|
11802
|
+
[
|
|
11803
|
+
4,
|
|
11804
|
+
5,
|
|
11805
|
+
6,
|
|
11806
|
+
2,
|
|
11807
|
+
4,
|
|
11808
|
+
3,
|
|
11809
|
+
5,
|
|
11810
|
+
2,
|
|
11811
|
+
7
|
|
11812
|
+
],
|
|
11813
|
+
[
|
|
11814
|
+
6,
|
|
11815
|
+
3,
|
|
11816
|
+
8,
|
|
11817
|
+
4,
|
|
11818
|
+
2,
|
|
11819
|
+
7,
|
|
11820
|
+
6,
|
|
11821
|
+
5,
|
|
11822
|
+
5
|
|
11823
|
+
],
|
|
11824
|
+
[
|
|
11825
|
+
3,
|
|
11826
|
+
6,
|
|
11827
|
+
5,
|
|
11828
|
+
3,
|
|
11829
|
+
7,
|
|
11830
|
+
2,
|
|
11831
|
+
2,
|
|
11832
|
+
4,
|
|
11833
|
+
6
|
|
11834
|
+
],
|
|
11835
|
+
[
|
|
11836
|
+
7,
|
|
11837
|
+
4,
|
|
11838
|
+
4,
|
|
11839
|
+
8,
|
|
11840
|
+
5,
|
|
11841
|
+
6,
|
|
11842
|
+
4,
|
|
11843
|
+
3,
|
|
11844
|
+
2
|
|
11845
|
+
]
|
|
11846
|
+
]
|
|
11847
|
+
}
|
|
11848
|
+
];
|
|
11849
|
+
const networkSampleProblems = [
|
|
11850
|
+
{
|
|
11851
|
+
family: "network",
|
|
11852
|
+
name: "Office Seating Feud",
|
|
11853
|
+
description: "Ten coworkers, weighted rivalry edges (1 = mild eye-rolls, 5 = open warfare). Split them across two floors so the maximum total rivalry crosses the staircase.",
|
|
11854
|
+
nodes: [
|
|
11855
|
+
{
|
|
11856
|
+
id: 0,
|
|
11857
|
+
name: "Ava",
|
|
11858
|
+
x: 20,
|
|
11859
|
+
y: 20
|
|
11860
|
+
},
|
|
11861
|
+
{
|
|
11862
|
+
id: 1,
|
|
11863
|
+
name: "Ben",
|
|
11864
|
+
x: 50,
|
|
11865
|
+
y: 12
|
|
11866
|
+
},
|
|
11867
|
+
{
|
|
11868
|
+
id: 2,
|
|
11869
|
+
name: "Cleo",
|
|
11870
|
+
x: 80,
|
|
11871
|
+
y: 22
|
|
11872
|
+
},
|
|
11873
|
+
{
|
|
11874
|
+
id: 3,
|
|
11875
|
+
name: "Dex",
|
|
11876
|
+
x: 12,
|
|
11877
|
+
y: 50
|
|
11878
|
+
},
|
|
11879
|
+
{
|
|
11880
|
+
id: 4,
|
|
11881
|
+
name: "Elle",
|
|
11882
|
+
x: 42,
|
|
11883
|
+
y: 42
|
|
11884
|
+
},
|
|
11885
|
+
{
|
|
11886
|
+
id: 5,
|
|
11887
|
+
name: "Finn",
|
|
11888
|
+
x: 70,
|
|
11889
|
+
y: 48
|
|
11890
|
+
},
|
|
11891
|
+
{
|
|
11892
|
+
id: 6,
|
|
11893
|
+
name: "Gus",
|
|
11894
|
+
x: 92,
|
|
11895
|
+
y: 55
|
|
11896
|
+
},
|
|
11897
|
+
{
|
|
11898
|
+
id: 7,
|
|
11899
|
+
name: "Hana",
|
|
11900
|
+
x: 25,
|
|
11901
|
+
y: 80
|
|
11902
|
+
},
|
|
11903
|
+
{
|
|
11904
|
+
id: 8,
|
|
11905
|
+
name: "Iggy",
|
|
11906
|
+
x: 55,
|
|
11907
|
+
y: 84
|
|
11908
|
+
},
|
|
11909
|
+
{
|
|
11910
|
+
id: 9,
|
|
11911
|
+
name: "June",
|
|
11912
|
+
x: 82,
|
|
11913
|
+
y: 80
|
|
11914
|
+
}
|
|
11915
|
+
],
|
|
11916
|
+
edges: [
|
|
11917
|
+
{
|
|
11918
|
+
a: 0,
|
|
11919
|
+
b: 1,
|
|
11920
|
+
w: 3
|
|
11921
|
+
},
|
|
11922
|
+
{
|
|
11923
|
+
a: 0,
|
|
11924
|
+
b: 3,
|
|
11925
|
+
w: 1
|
|
11926
|
+
},
|
|
11927
|
+
{
|
|
11928
|
+
a: 0,
|
|
11929
|
+
b: 4,
|
|
11930
|
+
w: 4
|
|
11931
|
+
},
|
|
11932
|
+
{
|
|
11933
|
+
a: 1,
|
|
11934
|
+
b: 2,
|
|
11935
|
+
w: 2
|
|
11936
|
+
},
|
|
11937
|
+
{
|
|
11938
|
+
a: 1,
|
|
11939
|
+
b: 4,
|
|
11940
|
+
w: 5
|
|
11941
|
+
},
|
|
11942
|
+
{
|
|
11943
|
+
a: 2,
|
|
11944
|
+
b: 5,
|
|
11945
|
+
w: 3
|
|
11946
|
+
},
|
|
11947
|
+
{
|
|
11948
|
+
a: 2,
|
|
11949
|
+
b: 6,
|
|
11950
|
+
w: 1
|
|
11951
|
+
},
|
|
11952
|
+
{
|
|
11953
|
+
a: 3,
|
|
11954
|
+
b: 4,
|
|
11955
|
+
w: 2
|
|
11956
|
+
},
|
|
11957
|
+
{
|
|
11958
|
+
a: 3,
|
|
11959
|
+
b: 7,
|
|
11960
|
+
w: 4
|
|
11961
|
+
},
|
|
11962
|
+
{
|
|
11963
|
+
a: 4,
|
|
11964
|
+
b: 5,
|
|
11965
|
+
w: 1
|
|
11966
|
+
},
|
|
11967
|
+
{
|
|
11968
|
+
a: 4,
|
|
11969
|
+
b: 8,
|
|
11970
|
+
w: 3
|
|
11971
|
+
},
|
|
11972
|
+
{
|
|
11973
|
+
a: 5,
|
|
11974
|
+
b: 6,
|
|
11975
|
+
w: 4
|
|
11976
|
+
},
|
|
11977
|
+
{
|
|
11978
|
+
a: 5,
|
|
11979
|
+
b: 9,
|
|
11980
|
+
w: 2
|
|
11981
|
+
},
|
|
11982
|
+
{
|
|
11983
|
+
a: 6,
|
|
11984
|
+
b: 9,
|
|
11985
|
+
w: 5
|
|
11986
|
+
},
|
|
11987
|
+
{
|
|
11988
|
+
a: 7,
|
|
11989
|
+
b: 8,
|
|
11990
|
+
w: 2
|
|
11991
|
+
},
|
|
11992
|
+
{
|
|
11993
|
+
a: 8,
|
|
11994
|
+
b: 9,
|
|
11995
|
+
w: 1
|
|
11996
|
+
}
|
|
11997
|
+
]
|
|
11998
|
+
},
|
|
11999
|
+
{
|
|
12000
|
+
family: "network",
|
|
12001
|
+
name: "Microservice Fault Domains",
|
|
12002
|
+
description: "Twelve services, edges weighted by cross-talk volume. Split across two availability zones so the heaviest traffic crosses zones — forcing the chattiest pairs to prove they tolerate partition.",
|
|
12003
|
+
nodes: [
|
|
12004
|
+
{
|
|
12005
|
+
id: 0,
|
|
12006
|
+
name: "gateway",
|
|
12007
|
+
x: 50,
|
|
12008
|
+
y: 8
|
|
12009
|
+
},
|
|
12010
|
+
{
|
|
12011
|
+
id: 1,
|
|
12012
|
+
name: "auth",
|
|
12013
|
+
x: 25,
|
|
12014
|
+
y: 22
|
|
12015
|
+
},
|
|
12016
|
+
{
|
|
12017
|
+
id: 2,
|
|
12018
|
+
name: "users",
|
|
12019
|
+
x: 75,
|
|
12020
|
+
y: 22
|
|
12021
|
+
},
|
|
12022
|
+
{
|
|
12023
|
+
id: 3,
|
|
12024
|
+
name: "billing",
|
|
12025
|
+
x: 12,
|
|
12026
|
+
y: 46
|
|
12027
|
+
},
|
|
12028
|
+
{
|
|
12029
|
+
id: 4,
|
|
12030
|
+
name: "catalog",
|
|
12031
|
+
x: 40,
|
|
12032
|
+
y: 40
|
|
12033
|
+
},
|
|
12034
|
+
{
|
|
12035
|
+
id: 5,
|
|
12036
|
+
name: "orders",
|
|
12037
|
+
x: 64,
|
|
12038
|
+
y: 42
|
|
12039
|
+
},
|
|
12040
|
+
{
|
|
12041
|
+
id: 6,
|
|
12042
|
+
name: "search",
|
|
12043
|
+
x: 90,
|
|
12044
|
+
y: 44
|
|
12045
|
+
},
|
|
12046
|
+
{
|
|
12047
|
+
id: 7,
|
|
12048
|
+
name: "ledger",
|
|
12049
|
+
x: 20,
|
|
12050
|
+
y: 70
|
|
12051
|
+
},
|
|
12052
|
+
{
|
|
12053
|
+
id: 8,
|
|
12054
|
+
name: "shipping",
|
|
12055
|
+
x: 48,
|
|
12056
|
+
y: 68
|
|
12057
|
+
},
|
|
12058
|
+
{
|
|
12059
|
+
id: 9,
|
|
12060
|
+
name: "notify",
|
|
12061
|
+
x: 74,
|
|
12062
|
+
y: 70
|
|
12063
|
+
},
|
|
12064
|
+
{
|
|
12065
|
+
id: 10,
|
|
12066
|
+
name: "analytics",
|
|
12067
|
+
x: 34,
|
|
12068
|
+
y: 90
|
|
12069
|
+
},
|
|
12070
|
+
{
|
|
12071
|
+
id: 11,
|
|
12072
|
+
name: "ml-recs",
|
|
12073
|
+
x: 66,
|
|
12074
|
+
y: 90
|
|
12075
|
+
}
|
|
12076
|
+
],
|
|
12077
|
+
edges: [
|
|
12078
|
+
{
|
|
12079
|
+
a: 0,
|
|
12080
|
+
b: 1,
|
|
12081
|
+
w: 5
|
|
12082
|
+
},
|
|
12083
|
+
{
|
|
12084
|
+
a: 0,
|
|
12085
|
+
b: 2,
|
|
12086
|
+
w: 4
|
|
12087
|
+
},
|
|
12088
|
+
{
|
|
12089
|
+
a: 0,
|
|
12090
|
+
b: 4,
|
|
12091
|
+
w: 3
|
|
12092
|
+
},
|
|
12093
|
+
{
|
|
12094
|
+
a: 1,
|
|
12095
|
+
b: 2,
|
|
12096
|
+
w: 2
|
|
12097
|
+
},
|
|
12098
|
+
{
|
|
12099
|
+
a: 1,
|
|
12100
|
+
b: 3,
|
|
12101
|
+
w: 3
|
|
12102
|
+
},
|
|
12103
|
+
{
|
|
12104
|
+
a: 2,
|
|
12105
|
+
b: 5,
|
|
12106
|
+
w: 4
|
|
12107
|
+
},
|
|
12108
|
+
{
|
|
12109
|
+
a: 2,
|
|
12110
|
+
b: 6,
|
|
12111
|
+
w: 2
|
|
12112
|
+
},
|
|
12113
|
+
{
|
|
12114
|
+
a: 3,
|
|
12115
|
+
b: 7,
|
|
12116
|
+
w: 5
|
|
12117
|
+
},
|
|
12118
|
+
{
|
|
12119
|
+
a: 4,
|
|
12120
|
+
b: 5,
|
|
12121
|
+
w: 3
|
|
12122
|
+
},
|
|
12123
|
+
{
|
|
12124
|
+
a: 4,
|
|
12125
|
+
b: 6,
|
|
12126
|
+
w: 2
|
|
12127
|
+
},
|
|
12128
|
+
{
|
|
12129
|
+
a: 4,
|
|
12130
|
+
b: 11,
|
|
12131
|
+
w: 2
|
|
12132
|
+
},
|
|
12133
|
+
{
|
|
12134
|
+
a: 5,
|
|
12135
|
+
b: 8,
|
|
12136
|
+
w: 4
|
|
12137
|
+
},
|
|
12138
|
+
{
|
|
12139
|
+
a: 5,
|
|
12140
|
+
b: 9,
|
|
12141
|
+
w: 2
|
|
12142
|
+
},
|
|
12143
|
+
{
|
|
12144
|
+
a: 7,
|
|
12145
|
+
b: 10,
|
|
12146
|
+
w: 2
|
|
12147
|
+
},
|
|
12148
|
+
{
|
|
12149
|
+
a: 8,
|
|
12150
|
+
b: 9,
|
|
12151
|
+
w: 3
|
|
12152
|
+
},
|
|
12153
|
+
{
|
|
12154
|
+
a: 8,
|
|
12155
|
+
b: 10,
|
|
12156
|
+
w: 1
|
|
12157
|
+
},
|
|
12158
|
+
{
|
|
12159
|
+
a: 9,
|
|
12160
|
+
b: 11,
|
|
12161
|
+
w: 2
|
|
12162
|
+
},
|
|
12163
|
+
{
|
|
12164
|
+
a: 10,
|
|
12165
|
+
b: 11,
|
|
12166
|
+
w: 3
|
|
12167
|
+
}
|
|
12168
|
+
]
|
|
12169
|
+
},
|
|
12170
|
+
{
|
|
12171
|
+
family: "network",
|
|
12172
|
+
name: "Power Grid Islanding",
|
|
12173
|
+
description: "During a storm event, the grid must split into two self-sufficient islands. Maximize the inter-island line capacity you can afford to sever cleanly.",
|
|
12174
|
+
nodes: [
|
|
12175
|
+
{
|
|
12176
|
+
id: 0,
|
|
12177
|
+
name: "Plant North",
|
|
12178
|
+
x: 30,
|
|
12179
|
+
y: 10
|
|
12180
|
+
},
|
|
12181
|
+
{
|
|
12182
|
+
id: 1,
|
|
12183
|
+
name: "Plant South",
|
|
12184
|
+
x: 65,
|
|
12185
|
+
y: 90
|
|
12186
|
+
},
|
|
12187
|
+
{
|
|
12188
|
+
id: 2,
|
|
12189
|
+
name: "Sub Alpha",
|
|
12190
|
+
x: 15,
|
|
12191
|
+
y: 35
|
|
12192
|
+
},
|
|
12193
|
+
{
|
|
12194
|
+
id: 3,
|
|
12195
|
+
name: "Sub Bravo",
|
|
12196
|
+
x: 50,
|
|
12197
|
+
y: 28
|
|
12198
|
+
},
|
|
12199
|
+
{
|
|
12200
|
+
id: 4,
|
|
12201
|
+
name: "Sub Charlie",
|
|
12202
|
+
x: 85,
|
|
12203
|
+
y: 32
|
|
12204
|
+
},
|
|
12205
|
+
{
|
|
12206
|
+
id: 5,
|
|
12207
|
+
name: "Sub Delta",
|
|
12208
|
+
x: 25,
|
|
12209
|
+
y: 62
|
|
12210
|
+
},
|
|
12211
|
+
{
|
|
12212
|
+
id: 6,
|
|
12213
|
+
name: "Sub Echo",
|
|
12214
|
+
x: 58,
|
|
12215
|
+
y: 58
|
|
12216
|
+
},
|
|
12217
|
+
{
|
|
12218
|
+
id: 7,
|
|
12219
|
+
name: "Sub Foxtrot",
|
|
12220
|
+
x: 88,
|
|
12221
|
+
y: 66
|
|
12222
|
+
},
|
|
12223
|
+
{
|
|
12224
|
+
id: 8,
|
|
12225
|
+
name: "City West",
|
|
12226
|
+
x: 12,
|
|
12227
|
+
y: 88
|
|
12228
|
+
}
|
|
12229
|
+
],
|
|
12230
|
+
edges: [
|
|
12231
|
+
{
|
|
12232
|
+
a: 0,
|
|
12233
|
+
b: 2,
|
|
12234
|
+
w: 4
|
|
12235
|
+
},
|
|
12236
|
+
{
|
|
12237
|
+
a: 0,
|
|
12238
|
+
b: 3,
|
|
12239
|
+
w: 5
|
|
12240
|
+
},
|
|
12241
|
+
{
|
|
12242
|
+
a: 0,
|
|
12243
|
+
b: 4,
|
|
12244
|
+
w: 3
|
|
12245
|
+
},
|
|
12246
|
+
{
|
|
12247
|
+
a: 2,
|
|
12248
|
+
b: 3,
|
|
12249
|
+
w: 2
|
|
12250
|
+
},
|
|
12251
|
+
{
|
|
12252
|
+
a: 2,
|
|
12253
|
+
b: 5,
|
|
12254
|
+
w: 4
|
|
12255
|
+
},
|
|
12256
|
+
{
|
|
12257
|
+
a: 3,
|
|
12258
|
+
b: 4,
|
|
12259
|
+
w: 2
|
|
12260
|
+
},
|
|
12261
|
+
{
|
|
12262
|
+
a: 3,
|
|
12263
|
+
b: 6,
|
|
12264
|
+
w: 4
|
|
12265
|
+
},
|
|
12266
|
+
{
|
|
12267
|
+
a: 4,
|
|
12268
|
+
b: 7,
|
|
12269
|
+
w: 4
|
|
12270
|
+
},
|
|
12271
|
+
{
|
|
12272
|
+
a: 5,
|
|
12273
|
+
b: 6,
|
|
12274
|
+
w: 3
|
|
12275
|
+
},
|
|
12276
|
+
{
|
|
12277
|
+
a: 5,
|
|
12278
|
+
b: 8,
|
|
12279
|
+
w: 5
|
|
12280
|
+
},
|
|
12281
|
+
{
|
|
12282
|
+
a: 6,
|
|
12283
|
+
b: 7,
|
|
12284
|
+
w: 2
|
|
12285
|
+
},
|
|
12286
|
+
{
|
|
12287
|
+
a: 6,
|
|
12288
|
+
b: 1,
|
|
12289
|
+
w: 5
|
|
12290
|
+
},
|
|
12291
|
+
{
|
|
12292
|
+
a: 7,
|
|
12293
|
+
b: 1,
|
|
12294
|
+
w: 3
|
|
12295
|
+
},
|
|
12296
|
+
{
|
|
12297
|
+
a: 8,
|
|
12298
|
+
b: 1,
|
|
12299
|
+
w: 2
|
|
12300
|
+
}
|
|
12301
|
+
]
|
|
12302
|
+
}
|
|
12303
|
+
];
|
|
12304
|
+
/** Build a jittered grid mesh: cells at (col,row), edges between face-sharing neighbors. */
|
|
12305
|
+
function gridMesh(cols, rows, cellName, weightAt, jitter) {
|
|
12306
|
+
const nodes = [];
|
|
12307
|
+
const padX = 100 / (cols + 1);
|
|
12308
|
+
const padY = 100 / (rows + 1);
|
|
12309
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
12310
|
+
const i = r * cols + c;
|
|
12311
|
+
const { dx, dy } = jitter(i);
|
|
12312
|
+
nodes.push({
|
|
12313
|
+
id: i,
|
|
12314
|
+
name: cellName(i),
|
|
12315
|
+
x: Math.round(padX * (c + 1) + dx),
|
|
12316
|
+
y: Math.round(padY * (r + 1) + dy)
|
|
12317
|
+
});
|
|
12318
|
+
}
|
|
12319
|
+
const edges = [];
|
|
12320
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
12321
|
+
const i = r * cols + c;
|
|
12322
|
+
if (c + 1 < cols) edges.push({
|
|
12323
|
+
a: i,
|
|
12324
|
+
b: i + 1,
|
|
12325
|
+
w: weightAt(i, i + 1)
|
|
12326
|
+
});
|
|
12327
|
+
if (r + 1 < rows) edges.push({
|
|
12328
|
+
a: i,
|
|
12329
|
+
b: i + cols,
|
|
12330
|
+
w: weightAt(i, i + cols)
|
|
12331
|
+
});
|
|
12332
|
+
}
|
|
12333
|
+
return {
|
|
12334
|
+
nodes,
|
|
12335
|
+
edges
|
|
12336
|
+
};
|
|
12337
|
+
}
|
|
12338
|
+
const wobble = (i) => i * 7919 % 11 / 10 - .5;
|
|
12339
|
+
const plate = gridMesh(4, 3, (i) => `cell ${i}`, (a, b) => 1 + (a * 31 + b * 17) % 4, (i) => ({
|
|
12340
|
+
dx: wobble(i) * 6,
|
|
12341
|
+
dy: wobble(i + 3) * 6
|
|
12342
|
+
}));
|
|
12343
|
+
const reservoir = gridMesh(6, 3, (i) => `block ${i}`, (a, b) => 1 + (a * 13 + b * 29) % 5, (i) => ({
|
|
12344
|
+
dx: wobble(i + 1) * 8,
|
|
12345
|
+
dy: wobble(i + 5) * 8
|
|
12346
|
+
}));
|
|
12347
|
+
const blade = gridMesh(6, 4, (i) => `elem ${i}`, (a, b) => 1 + (a * 23 + b * 19) % 4, (i) => ({
|
|
12348
|
+
dx: wobble(i + 2) * 7,
|
|
12349
|
+
dy: wobble(i + 7) * 7
|
|
12350
|
+
}));
|
|
12351
|
+
const partitioningSampleProblems = [
|
|
12352
|
+
{
|
|
12353
|
+
family: "partitioning",
|
|
12354
|
+
name: "Cantilever Plate Mesh",
|
|
12355
|
+
description: "A 4×3 finite-element plate mesh split across two solver ranks. Edge weights are the face data exchanged every timestep — each cut edge is halo traffic both ranks pay forever. Classic balanced bisection, and small enough to race on the QAOA simulator in seconds.",
|
|
12356
|
+
nodes: plate.nodes,
|
|
12357
|
+
edges: plate.edges,
|
|
12358
|
+
k: 2,
|
|
12359
|
+
balanceTolerance: 1
|
|
12360
|
+
},
|
|
12361
|
+
{
|
|
12362
|
+
family: "partitioning",
|
|
12363
|
+
name: "Reservoir Grid Sectors",
|
|
12364
|
+
description: "An 18-block reservoir simulation grid decomposed across three compute nodes. The big version of this problem has billions of cells; the math of where to draw the seams is identical at every scale.",
|
|
12365
|
+
nodes: reservoir.nodes,
|
|
12366
|
+
edges: reservoir.edges,
|
|
12367
|
+
k: 3,
|
|
12368
|
+
balanceTolerance: 1
|
|
12369
|
+
},
|
|
12370
|
+
{
|
|
12371
|
+
family: "partitioning",
|
|
12372
|
+
name: "Turbine Blade Mesh",
|
|
12373
|
+
description: "A 24-element blade section spread over four solver ranks for a transient thermal run. Four-way splits punish lazy seams — every extra cut edge multiplies across thousands of timesteps.",
|
|
12374
|
+
nodes: blade.nodes,
|
|
12375
|
+
edges: blade.edges,
|
|
12376
|
+
k: 4,
|
|
12377
|
+
balanceTolerance: 1
|
|
12378
|
+
}
|
|
12379
|
+
];
|
|
12380
|
+
const selectionSampleProblems = [
|
|
12381
|
+
{
|
|
12382
|
+
family: "selection",
|
|
12383
|
+
name: "Indie Game Fund",
|
|
12384
|
+
description: "Twelve pitches, a $2M fund, and every project carries risk. Maximize expected portfolio value without betting the firm on moonshots.",
|
|
12385
|
+
budget: 200,
|
|
12386
|
+
riskWeight: 4,
|
|
12387
|
+
items: [
|
|
12388
|
+
{
|
|
12389
|
+
id: 0,
|
|
12390
|
+
name: "Cozy Farm Sim",
|
|
12391
|
+
value: 60,
|
|
12392
|
+
cost: 40,
|
|
12393
|
+
risk: 2
|
|
12394
|
+
},
|
|
12395
|
+
{
|
|
12396
|
+
id: 1,
|
|
12397
|
+
name: "Roguelike Deckbuilder",
|
|
12398
|
+
value: 85,
|
|
12399
|
+
cost: 55,
|
|
12400
|
+
risk: 4
|
|
12401
|
+
},
|
|
12402
|
+
{
|
|
12403
|
+
id: 2,
|
|
12404
|
+
name: "VR Escape Room",
|
|
12405
|
+
value: 95,
|
|
12406
|
+
cost: 70,
|
|
12407
|
+
risk: 8
|
|
12408
|
+
},
|
|
12409
|
+
{
|
|
12410
|
+
id: 3,
|
|
12411
|
+
name: "Pixel Metroidvania",
|
|
12412
|
+
value: 55,
|
|
12413
|
+
cost: 35,
|
|
12414
|
+
risk: 3
|
|
12415
|
+
},
|
|
12416
|
+
{
|
|
12417
|
+
id: 4,
|
|
12418
|
+
name: "MMO Sandbox",
|
|
12419
|
+
value: 160,
|
|
12420
|
+
cost: 120,
|
|
12421
|
+
risk: 10
|
|
12422
|
+
},
|
|
12423
|
+
{
|
|
12424
|
+
id: 5,
|
|
12425
|
+
name: "Mobile Puzzler",
|
|
12426
|
+
value: 35,
|
|
12427
|
+
cost: 18,
|
|
12428
|
+
risk: 1
|
|
12429
|
+
},
|
|
12430
|
+
{
|
|
12431
|
+
id: 6,
|
|
12432
|
+
name: "Co-op Heist Game",
|
|
12433
|
+
value: 75,
|
|
12434
|
+
cost: 50,
|
|
12435
|
+
risk: 5
|
|
12436
|
+
},
|
|
12437
|
+
{
|
|
12438
|
+
id: 7,
|
|
12439
|
+
name: "Narrative Adventure",
|
|
12440
|
+
value: 45,
|
|
12441
|
+
cost: 30,
|
|
12442
|
+
risk: 2
|
|
12443
|
+
},
|
|
12444
|
+
{
|
|
12445
|
+
id: 8,
|
|
12446
|
+
name: "Auto-Battler",
|
|
12447
|
+
value: 50,
|
|
12448
|
+
cost: 28,
|
|
12449
|
+
risk: 4
|
|
12450
|
+
},
|
|
12451
|
+
{
|
|
12452
|
+
id: 9,
|
|
12453
|
+
name: "Speedrun Platformer",
|
|
12454
|
+
value: 30,
|
|
12455
|
+
cost: 15,
|
|
12456
|
+
risk: 2
|
|
12457
|
+
},
|
|
12458
|
+
{
|
|
12459
|
+
id: 10,
|
|
12460
|
+
name: "City Builder",
|
|
12461
|
+
value: 90,
|
|
12462
|
+
cost: 65,
|
|
12463
|
+
risk: 5
|
|
12464
|
+
},
|
|
12465
|
+
{
|
|
12466
|
+
id: 11,
|
|
12467
|
+
name: "Horror Anthology",
|
|
12468
|
+
value: 40,
|
|
12469
|
+
cost: 25,
|
|
12470
|
+
risk: 6
|
|
12471
|
+
}
|
|
12472
|
+
]
|
|
12473
|
+
},
|
|
12474
|
+
{
|
|
12475
|
+
family: "selection",
|
|
12476
|
+
name: "Drone Sensor Loadout",
|
|
12477
|
+
description: "A recon drone has 48 units of payload mass. Pick the sensor suite that maximizes mission value — leave the gold-plated gear on the bench.",
|
|
12478
|
+
budget: 48,
|
|
12479
|
+
riskWeight: 0,
|
|
12480
|
+
items: [
|
|
12481
|
+
{
|
|
12482
|
+
id: 0,
|
|
12483
|
+
name: "EO Camera",
|
|
12484
|
+
value: 30,
|
|
12485
|
+
cost: 12
|
|
12486
|
+
},
|
|
12487
|
+
{
|
|
12488
|
+
id: 1,
|
|
12489
|
+
name: "IR Thermal",
|
|
12490
|
+
value: 28,
|
|
12491
|
+
cost: 10
|
|
12492
|
+
},
|
|
12493
|
+
{
|
|
12494
|
+
id: 2,
|
|
12495
|
+
name: "LIDAR",
|
|
12496
|
+
value: 35,
|
|
12497
|
+
cost: 18
|
|
12498
|
+
},
|
|
12499
|
+
{
|
|
12500
|
+
id: 3,
|
|
12501
|
+
name: "SIGINT Pod",
|
|
12502
|
+
value: 25,
|
|
12503
|
+
cost: 14
|
|
12504
|
+
},
|
|
12505
|
+
{
|
|
12506
|
+
id: 4,
|
|
12507
|
+
name: "Synthetic Aperture Radar",
|
|
12508
|
+
value: 40,
|
|
12509
|
+
cost: 22
|
|
12510
|
+
},
|
|
12511
|
+
{
|
|
12512
|
+
id: 5,
|
|
12513
|
+
name: "Laser Designator",
|
|
12514
|
+
value: 18,
|
|
12515
|
+
cost: 8
|
|
12516
|
+
},
|
|
12517
|
+
{
|
|
12518
|
+
id: 6,
|
|
12519
|
+
name: "Comms Relay",
|
|
12520
|
+
value: 15,
|
|
12521
|
+
cost: 6
|
|
12522
|
+
},
|
|
12523
|
+
{
|
|
12524
|
+
id: 7,
|
|
12525
|
+
name: "Magnetometer",
|
|
12526
|
+
value: 10,
|
|
12527
|
+
cost: 4
|
|
12528
|
+
},
|
|
12529
|
+
{
|
|
12530
|
+
id: 8,
|
|
12531
|
+
name: "Air Sampler",
|
|
12532
|
+
value: 8,
|
|
12533
|
+
cost: 5
|
|
12534
|
+
},
|
|
12535
|
+
{
|
|
12536
|
+
id: 9,
|
|
12537
|
+
name: "Spare Battery",
|
|
12538
|
+
value: 12,
|
|
12539
|
+
cost: 9
|
|
12540
|
+
}
|
|
12541
|
+
]
|
|
12542
|
+
},
|
|
12543
|
+
{
|
|
12544
|
+
family: "selection",
|
|
12545
|
+
name: "Feature Flag Quarter",
|
|
12546
|
+
description: "Fourteen engineering initiatives, 90 days of team capacity. Each carries delivery risk. Choose the roadmap that maximizes shipped value.",
|
|
12547
|
+
budget: 90,
|
|
12548
|
+
riskWeight: 3,
|
|
12549
|
+
items: [
|
|
12550
|
+
{
|
|
12551
|
+
id: 0,
|
|
12552
|
+
name: "Realtime Collab",
|
|
12553
|
+
value: 55,
|
|
12554
|
+
cost: 30,
|
|
12555
|
+
risk: 6
|
|
12556
|
+
},
|
|
12557
|
+
{
|
|
12558
|
+
id: 1,
|
|
12559
|
+
name: "Mobile Offline Mode",
|
|
12560
|
+
value: 40,
|
|
12561
|
+
cost: 25,
|
|
12562
|
+
risk: 4
|
|
12563
|
+
},
|
|
12564
|
+
{
|
|
12565
|
+
id: 2,
|
|
12566
|
+
name: "SSO Everywhere",
|
|
12567
|
+
value: 35,
|
|
12568
|
+
cost: 15,
|
|
12569
|
+
risk: 2
|
|
12570
|
+
},
|
|
12571
|
+
{
|
|
12572
|
+
id: 3,
|
|
12573
|
+
name: "Billing v2",
|
|
12574
|
+
value: 50,
|
|
12575
|
+
cost: 35,
|
|
12576
|
+
risk: 7
|
|
12577
|
+
},
|
|
12578
|
+
{
|
|
12579
|
+
id: 4,
|
|
12580
|
+
name: "AI Summaries",
|
|
12581
|
+
value: 45,
|
|
12582
|
+
cost: 20,
|
|
12583
|
+
risk: 3
|
|
12584
|
+
},
|
|
12585
|
+
{
|
|
12586
|
+
id: 5,
|
|
12587
|
+
name: "Audit Logs",
|
|
12588
|
+
value: 25,
|
|
12589
|
+
cost: 10,
|
|
12590
|
+
risk: 1
|
|
12591
|
+
},
|
|
12592
|
+
{
|
|
12593
|
+
id: 6,
|
|
12594
|
+
name: "Perf: Cold Start",
|
|
12595
|
+
value: 30,
|
|
12596
|
+
cost: 12,
|
|
12597
|
+
risk: 2
|
|
12598
|
+
},
|
|
12599
|
+
{
|
|
12600
|
+
id: 7,
|
|
12601
|
+
name: "Theme System",
|
|
12602
|
+
value: 15,
|
|
12603
|
+
cost: 8,
|
|
12604
|
+
risk: 1
|
|
12605
|
+
},
|
|
12606
|
+
{
|
|
12607
|
+
id: 8,
|
|
12608
|
+
name: "Webhooks v2",
|
|
12609
|
+
value: 28,
|
|
12610
|
+
cost: 14,
|
|
12611
|
+
risk: 3
|
|
12612
|
+
},
|
|
12613
|
+
{
|
|
12614
|
+
id: 9,
|
|
12615
|
+
name: "Data Residency",
|
|
12616
|
+
value: 38,
|
|
12617
|
+
cost: 28,
|
|
12618
|
+
risk: 5
|
|
12619
|
+
},
|
|
12620
|
+
{
|
|
12621
|
+
id: 10,
|
|
12622
|
+
name: "Search Rewrite",
|
|
12623
|
+
value: 42,
|
|
12624
|
+
cost: 26,
|
|
12625
|
+
risk: 5
|
|
12626
|
+
},
|
|
12627
|
+
{
|
|
12628
|
+
id: 11,
|
|
12629
|
+
name: "Onboarding Flow",
|
|
12630
|
+
value: 22,
|
|
12631
|
+
cost: 9,
|
|
12632
|
+
risk: 1
|
|
12633
|
+
},
|
|
12634
|
+
{
|
|
12635
|
+
id: 12,
|
|
12636
|
+
name: "Plugin SDK",
|
|
12637
|
+
value: 48,
|
|
12638
|
+
cost: 32,
|
|
12639
|
+
risk: 6
|
|
12640
|
+
},
|
|
12641
|
+
{
|
|
12642
|
+
id: 13,
|
|
12643
|
+
name: "A11y Sweep",
|
|
12644
|
+
value: 20,
|
|
12645
|
+
cost: 11,
|
|
12646
|
+
risk: 1
|
|
12647
|
+
}
|
|
12648
|
+
]
|
|
12649
|
+
}
|
|
12650
|
+
];
|
|
12651
|
+
const economicSampleProblems = [
|
|
12652
|
+
{
|
|
12653
|
+
family: "economic",
|
|
12654
|
+
name: "Spectrum Auction",
|
|
12655
|
+
description: "Five regional spectrum licenses, nine carriers bidding on bundles. Sell each license once, maximize treasury revenue — the classic FCC winner-determination problem.",
|
|
12656
|
+
goods: [
|
|
12657
|
+
{
|
|
12658
|
+
id: 0,
|
|
12659
|
+
name: "North Band"
|
|
12660
|
+
},
|
|
12661
|
+
{
|
|
12662
|
+
id: 1,
|
|
12663
|
+
name: "South Band"
|
|
12664
|
+
},
|
|
12665
|
+
{
|
|
12666
|
+
id: 2,
|
|
12667
|
+
name: "East Band"
|
|
12668
|
+
},
|
|
12669
|
+
{
|
|
12670
|
+
id: 3,
|
|
12671
|
+
name: "West Band"
|
|
12672
|
+
},
|
|
12673
|
+
{
|
|
12674
|
+
id: 4,
|
|
12675
|
+
name: "Metro Core"
|
|
12676
|
+
}
|
|
12677
|
+
],
|
|
12678
|
+
bids: [
|
|
12679
|
+
{
|
|
12680
|
+
id: 0,
|
|
12681
|
+
bidder: "AstraTel",
|
|
12682
|
+
price: 120,
|
|
12683
|
+
goodIds: [0, 4]
|
|
12684
|
+
},
|
|
12685
|
+
{
|
|
12686
|
+
id: 1,
|
|
12687
|
+
bidder: "AstraTel",
|
|
12688
|
+
price: 60,
|
|
12689
|
+
goodIds: [0]
|
|
12690
|
+
},
|
|
12691
|
+
{
|
|
12692
|
+
id: 2,
|
|
12693
|
+
bidder: "Borealis",
|
|
12694
|
+
price: 140,
|
|
12695
|
+
goodIds: [1, 2]
|
|
12696
|
+
},
|
|
12697
|
+
{
|
|
12698
|
+
id: 3,
|
|
12699
|
+
bidder: "Borealis",
|
|
12700
|
+
price: 65,
|
|
12701
|
+
goodIds: [1]
|
|
12702
|
+
},
|
|
12703
|
+
{
|
|
12704
|
+
id: 4,
|
|
12705
|
+
bidder: "CometNet",
|
|
12706
|
+
price: 95,
|
|
12707
|
+
goodIds: [2, 3]
|
|
12708
|
+
},
|
|
12709
|
+
{
|
|
12710
|
+
id: 5,
|
|
12711
|
+
bidder: "CometNet",
|
|
12712
|
+
price: 50,
|
|
12713
|
+
goodIds: [3]
|
|
12714
|
+
},
|
|
12715
|
+
{
|
|
12716
|
+
id: 6,
|
|
12717
|
+
bidder: "DyneMobile",
|
|
12718
|
+
price: 180,
|
|
12719
|
+
goodIds: [
|
|
12720
|
+
0,
|
|
12721
|
+
1,
|
|
12722
|
+
4
|
|
12723
|
+
]
|
|
12724
|
+
},
|
|
12725
|
+
{
|
|
12726
|
+
id: 7,
|
|
12727
|
+
bidder: "Equinox",
|
|
12728
|
+
price: 75,
|
|
12729
|
+
goodIds: [4]
|
|
12730
|
+
},
|
|
12731
|
+
{
|
|
12732
|
+
id: 8,
|
|
12733
|
+
bidder: "Equinox",
|
|
12734
|
+
price: 110,
|
|
12735
|
+
goodIds: [2, 4]
|
|
12736
|
+
}
|
|
12737
|
+
]
|
|
12738
|
+
},
|
|
12739
|
+
{
|
|
12740
|
+
family: "economic",
|
|
12741
|
+
name: "Cloud Spot Market",
|
|
12742
|
+
description: "Six GPU node pools, ten batch workloads bidding for exclusive overnight windows. Maximize the operator's take across all-or-nothing reservations.",
|
|
12743
|
+
goods: [
|
|
12744
|
+
{
|
|
12745
|
+
id: 0,
|
|
12746
|
+
name: "A100 Pool 1"
|
|
12747
|
+
},
|
|
12748
|
+
{
|
|
12749
|
+
id: 1,
|
|
12750
|
+
name: "A100 Pool 2"
|
|
12751
|
+
},
|
|
12752
|
+
{
|
|
12753
|
+
id: 2,
|
|
12754
|
+
name: "H100 Pool 1"
|
|
12755
|
+
},
|
|
12756
|
+
{
|
|
12757
|
+
id: 3,
|
|
12758
|
+
name: "H100 Pool 2"
|
|
12759
|
+
},
|
|
12760
|
+
{
|
|
12761
|
+
id: 4,
|
|
12762
|
+
name: "TPU Pod"
|
|
12763
|
+
},
|
|
12764
|
+
{
|
|
12765
|
+
id: 5,
|
|
12766
|
+
name: "CPU Farm"
|
|
12767
|
+
}
|
|
12768
|
+
],
|
|
12769
|
+
bids: [
|
|
12770
|
+
{
|
|
12771
|
+
id: 0,
|
|
12772
|
+
bidder: "BioFold Labs",
|
|
12773
|
+
price: 90,
|
|
12774
|
+
goodIds: [2, 3]
|
|
12775
|
+
},
|
|
12776
|
+
{
|
|
12777
|
+
id: 1,
|
|
12778
|
+
bidder: "BioFold Labs",
|
|
12779
|
+
price: 48,
|
|
12780
|
+
goodIds: [2]
|
|
12781
|
+
},
|
|
12782
|
+
{
|
|
12783
|
+
id: 2,
|
|
12784
|
+
bidder: "RenderWorks",
|
|
12785
|
+
price: 55,
|
|
12786
|
+
goodIds: [0, 1]
|
|
12787
|
+
},
|
|
12788
|
+
{
|
|
12789
|
+
id: 3,
|
|
12790
|
+
bidder: "RenderWorks",
|
|
12791
|
+
price: 30,
|
|
12792
|
+
goodIds: [0]
|
|
12793
|
+
},
|
|
12794
|
+
{
|
|
12795
|
+
id: 4,
|
|
12796
|
+
bidder: "LLM Foundry",
|
|
12797
|
+
price: 130,
|
|
12798
|
+
goodIds: [
|
|
12799
|
+
2,
|
|
12800
|
+
3,
|
|
12801
|
+
4
|
|
12802
|
+
]
|
|
12803
|
+
},
|
|
12804
|
+
{
|
|
12805
|
+
id: 5,
|
|
12806
|
+
bidder: "LLM Foundry",
|
|
12807
|
+
price: 70,
|
|
12808
|
+
goodIds: [4]
|
|
12809
|
+
},
|
|
12810
|
+
{
|
|
12811
|
+
id: 6,
|
|
12812
|
+
bidder: "QuantSim",
|
|
12813
|
+
price: 42,
|
|
12814
|
+
goodIds: [1, 5]
|
|
12815
|
+
},
|
|
12816
|
+
{
|
|
12817
|
+
id: 7,
|
|
12818
|
+
bidder: "QuantSim",
|
|
12819
|
+
price: 22,
|
|
12820
|
+
goodIds: [5]
|
|
12821
|
+
},
|
|
12822
|
+
{
|
|
12823
|
+
id: 8,
|
|
12824
|
+
bidder: "WeatherNet",
|
|
12825
|
+
price: 65,
|
|
12826
|
+
goodIds: [0, 5]
|
|
12827
|
+
},
|
|
12828
|
+
{
|
|
12829
|
+
id: 9,
|
|
12830
|
+
bidder: "GenomeScan",
|
|
12831
|
+
price: 38,
|
|
12832
|
+
goodIds: [1]
|
|
12833
|
+
}
|
|
12834
|
+
]
|
|
12835
|
+
},
|
|
12836
|
+
{
|
|
12837
|
+
family: "economic",
|
|
12838
|
+
name: "Stadium Sponsorship Bundle",
|
|
12839
|
+
description: "Seven sponsorship assets — naming rights, jersey patch, tunnel club — and eight brands bidding on combinations. One sale per asset; maximize the franchise's deal sheet.",
|
|
12840
|
+
goods: [
|
|
12841
|
+
{
|
|
12842
|
+
id: 0,
|
|
12843
|
+
name: "Naming Rights"
|
|
12844
|
+
},
|
|
12845
|
+
{
|
|
12846
|
+
id: 1,
|
|
12847
|
+
name: "Jersey Patch"
|
|
12848
|
+
},
|
|
12849
|
+
{
|
|
12850
|
+
id: 2,
|
|
12851
|
+
name: "Tunnel Club"
|
|
12852
|
+
},
|
|
12853
|
+
{
|
|
12854
|
+
id: 3,
|
|
12855
|
+
name: "Scoreboard"
|
|
12856
|
+
},
|
|
12857
|
+
{
|
|
12858
|
+
id: 4,
|
|
12859
|
+
name: "Practice Facility"
|
|
12860
|
+
},
|
|
12861
|
+
{
|
|
12862
|
+
id: 5,
|
|
12863
|
+
name: "Beer Pouring Rights"
|
|
12864
|
+
},
|
|
12865
|
+
{
|
|
12866
|
+
id: 6,
|
|
12867
|
+
name: "Halftime Show"
|
|
12868
|
+
}
|
|
12869
|
+
],
|
|
12870
|
+
bids: [
|
|
12871
|
+
{
|
|
12872
|
+
id: 0,
|
|
12873
|
+
bidder: "Vertex Air",
|
|
12874
|
+
price: 200,
|
|
12875
|
+
goodIds: [0, 3]
|
|
12876
|
+
},
|
|
12877
|
+
{
|
|
12878
|
+
id: 1,
|
|
12879
|
+
bidder: "Vertex Air",
|
|
12880
|
+
price: 130,
|
|
12881
|
+
goodIds: [0]
|
|
12882
|
+
},
|
|
12883
|
+
{
|
|
12884
|
+
id: 2,
|
|
12885
|
+
bidder: "Cascade Beer",
|
|
12886
|
+
price: 85,
|
|
12887
|
+
goodIds: [5, 6]
|
|
12888
|
+
},
|
|
12889
|
+
{
|
|
12890
|
+
id: 3,
|
|
12891
|
+
bidder: "Cascade Beer",
|
|
12892
|
+
price: 55,
|
|
12893
|
+
goodIds: [5]
|
|
12894
|
+
},
|
|
12895
|
+
{
|
|
12896
|
+
id: 4,
|
|
12897
|
+
bidder: "NovaBank",
|
|
12898
|
+
price: 150,
|
|
12899
|
+
goodIds: [1, 2]
|
|
12900
|
+
},
|
|
12901
|
+
{
|
|
12902
|
+
id: 5,
|
|
12903
|
+
bidder: "NovaBank",
|
|
12904
|
+
price: 80,
|
|
12905
|
+
goodIds: [1]
|
|
12906
|
+
},
|
|
12907
|
+
{
|
|
12908
|
+
id: 6,
|
|
12909
|
+
bidder: "GrindHouse Coffee",
|
|
12910
|
+
price: 45,
|
|
12911
|
+
goodIds: [2]
|
|
12912
|
+
},
|
|
12913
|
+
{
|
|
12914
|
+
id: 7,
|
|
12915
|
+
bidder: "Pixel Motors",
|
|
12916
|
+
price: 110,
|
|
12917
|
+
goodIds: [3, 4]
|
|
12918
|
+
},
|
|
12919
|
+
{
|
|
12920
|
+
id: 8,
|
|
12921
|
+
bidder: "Pixel Motors",
|
|
12922
|
+
price: 60,
|
|
12923
|
+
goodIds: [4]
|
|
12924
|
+
},
|
|
12925
|
+
{
|
|
12926
|
+
id: 9,
|
|
12927
|
+
bidder: "StreamCo",
|
|
12928
|
+
price: 70,
|
|
12929
|
+
goodIds: [6]
|
|
12930
|
+
}
|
|
12931
|
+
]
|
|
10886
12932
|
}
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
12933
|
+
];
|
|
12934
|
+
const continuousSampleProblems = [
|
|
12935
|
+
{
|
|
12936
|
+
family: "continuous",
|
|
12937
|
+
name: "Reactor Temperature Tuning",
|
|
12938
|
+
description: "One control dial, a yield curve full of local sweet spots, and exactly one true optimum. The wavy bowl eats naive hill climbers for breakfast.",
|
|
12939
|
+
functionId: "wavy-bowl",
|
|
12940
|
+
dims: 1,
|
|
12941
|
+
lo: -10,
|
|
12942
|
+
hi: 10,
|
|
12943
|
+
paramNames: ["temperature offset"]
|
|
12944
|
+
},
|
|
12945
|
+
{
|
|
12946
|
+
family: "continuous",
|
|
12947
|
+
name: "Antenna Sweet Spot",
|
|
12948
|
+
description: "Two placement coordinates on the roof; signal interference makes four equally good mounting points. Himmelblau's function — which optimum will your solver find?",
|
|
12949
|
+
functionId: "himmelblau",
|
|
12950
|
+
dims: 2,
|
|
12951
|
+
lo: -6,
|
|
12952
|
+
hi: 6,
|
|
12953
|
+
paramNames: ["east-west", "north-south"]
|
|
12954
|
+
},
|
|
12955
|
+
{
|
|
12956
|
+
family: "continuous",
|
|
12957
|
+
name: "Hyperparameter Canyon",
|
|
12958
|
+
description: "Two training knobs over a Rastrigin egg-carton — dozens of local minima arranged in a lattice, one global floor at the origin. Pure trap density.",
|
|
12959
|
+
functionId: "rastrigin",
|
|
12960
|
+
dims: 2,
|
|
12961
|
+
lo: -5.12,
|
|
12962
|
+
hi: 5.12,
|
|
12963
|
+
paramNames: ["learning rate (scaled)", "regularization (scaled)"]
|
|
10900
12964
|
}
|
|
10901
|
-
|
|
10902
|
-
nodes,
|
|
10903
|
-
edges
|
|
10904
|
-
};
|
|
10905
|
-
}
|
|
10906
|
-
const wobble = (i) => i * 7919 % 11 / 10 - .5;
|
|
10907
|
-
const plate = gridMesh(4, 3, (i) => `cell ${i}`, (a, b) => 1 + (a * 31 + b * 17) % 4, (i) => ({
|
|
10908
|
-
dx: wobble(i) * 6,
|
|
10909
|
-
dy: wobble(i + 3) * 6
|
|
10910
|
-
}));
|
|
10911
|
-
const reservoir = gridMesh(6, 3, (i) => `block ${i}`, (a, b) => 1 + (a * 13 + b * 29) % 5, (i) => ({
|
|
10912
|
-
dx: wobble(i + 1) * 8,
|
|
10913
|
-
dy: wobble(i + 5) * 8
|
|
10914
|
-
}));
|
|
10915
|
-
const blade = gridMesh(6, 4, (i) => `elem ${i}`, (a, b) => 1 + (a * 23 + b * 19) % 4, (i) => ({
|
|
10916
|
-
dx: wobble(i + 2) * 7,
|
|
10917
|
-
dy: wobble(i + 7) * 7
|
|
10918
|
-
}));
|
|
10919
|
-
plate.nodes, plate.edges, reservoir.nodes, reservoir.edges, blade.nodes, blade.edges;
|
|
12965
|
+
];
|
|
10920
12966
|
var QuboBuilder = class {
|
|
10921
12967
|
size;
|
|
10922
12968
|
q = /* @__PURE__ */ new Map();
|
|
@@ -11248,8 +13294,270 @@ function continuousToy() {
|
|
|
11248
13294
|
};
|
|
11249
13295
|
}
|
|
11250
13296
|
schedulingToy(), routingToy(), packingToy(), assignmentToy(), networkToy(), partitioningToy(), selectionToy(), economicToy(), continuousToy();
|
|
13297
|
+
/**
|
|
13298
|
+
* Per-family problem Zod schemas — the validation foundation for custom problem
|
|
13299
|
+
* EDITING (FamilyProblemEditor validates JSON against these) and LLM FORMULATION
|
|
13300
|
+
* (quantum_formulate validates the model's output before surfacing it).
|
|
13301
|
+
*
|
|
13302
|
+
* Authored to match the hand-written interfaces in `./types`; a type-level check
|
|
13303
|
+
* at the bottom keeps the two in sync. The family discriminant lets a single
|
|
13304
|
+
* editor/tool dispatch across all eight shapes.
|
|
13305
|
+
*/
|
|
13306
|
+
const named = {
|
|
13307
|
+
id: z.number().int(),
|
|
13308
|
+
name: z.string().min(1)
|
|
13309
|
+
};
|
|
13310
|
+
const xy = {
|
|
13311
|
+
x: z.number(),
|
|
13312
|
+
y: z.number()
|
|
13313
|
+
};
|
|
13314
|
+
const edge = z.object({
|
|
13315
|
+
a: z.number().int().nonnegative(),
|
|
13316
|
+
b: z.number().int().nonnegative(),
|
|
13317
|
+
w: z.number().optional()
|
|
13318
|
+
});
|
|
13319
|
+
const RoutingProblemSchema = z.object({
|
|
13320
|
+
family: z.literal("routing"),
|
|
13321
|
+
name: z.string().min(1),
|
|
13322
|
+
description: z.string().optional(),
|
|
13323
|
+
nodes: z.array(z.object({
|
|
13324
|
+
...named,
|
|
13325
|
+
...xy
|
|
13326
|
+
})).min(2)
|
|
13327
|
+
});
|
|
13328
|
+
const PackingProblemSchema = z.object({
|
|
13329
|
+
family: z.literal("packing"),
|
|
13330
|
+
name: z.string().min(1),
|
|
13331
|
+
description: z.string().optional(),
|
|
13332
|
+
items: z.array(z.object({
|
|
13333
|
+
...named,
|
|
13334
|
+
size: z.number().positive()
|
|
13335
|
+
})).min(1),
|
|
13336
|
+
binCapacity: z.number().positive(),
|
|
13337
|
+
binLabel: z.string().min(1)
|
|
13338
|
+
});
|
|
13339
|
+
const AssignmentProblemSchema = z.object({
|
|
13340
|
+
family: z.literal("assignment"),
|
|
13341
|
+
name: z.string().min(1),
|
|
13342
|
+
description: z.string().optional(),
|
|
13343
|
+
agents: z.array(z.object(named)).min(1),
|
|
13344
|
+
tasks: z.array(z.object(named)).min(1),
|
|
13345
|
+
cost: z.array(z.array(z.number())).min(1)
|
|
13346
|
+
});
|
|
13347
|
+
const NetworkProblemSchema = z.object({
|
|
13348
|
+
family: z.literal("network"),
|
|
13349
|
+
name: z.string().min(1),
|
|
13350
|
+
description: z.string().optional(),
|
|
13351
|
+
nodes: z.array(z.object({
|
|
13352
|
+
...named,
|
|
13353
|
+
...xy
|
|
13354
|
+
})).min(1),
|
|
13355
|
+
edges: z.array(edge)
|
|
13356
|
+
});
|
|
13357
|
+
const PartitionProblemSchema = z.object({
|
|
13358
|
+
family: z.literal("partitioning"),
|
|
13359
|
+
name: z.string().min(1),
|
|
13360
|
+
description: z.string().optional(),
|
|
13361
|
+
nodes: z.array(z.object({
|
|
13362
|
+
...named,
|
|
13363
|
+
...xy
|
|
13364
|
+
})).min(1),
|
|
13365
|
+
edges: z.array(edge),
|
|
13366
|
+
k: z.number().int().min(2),
|
|
13367
|
+
balanceTolerance: z.number().int().nonnegative().optional()
|
|
13368
|
+
});
|
|
13369
|
+
const SelectionProblemSchema = z.object({
|
|
13370
|
+
family: z.literal("selection"),
|
|
13371
|
+
name: z.string().min(1),
|
|
13372
|
+
description: z.string().optional(),
|
|
13373
|
+
items: z.array(z.object({
|
|
13374
|
+
...named,
|
|
13375
|
+
value: z.number(),
|
|
13376
|
+
cost: z.number().positive(),
|
|
13377
|
+
risk: z.number().optional()
|
|
13378
|
+
})).min(1),
|
|
13379
|
+
budget: z.number().positive(),
|
|
13380
|
+
riskWeight: z.number().optional()
|
|
13381
|
+
});
|
|
13382
|
+
const EconomicProblemSchema = z.object({
|
|
13383
|
+
family: z.literal("economic"),
|
|
13384
|
+
name: z.string().min(1),
|
|
13385
|
+
description: z.string().optional(),
|
|
13386
|
+
goods: z.array(z.object(named)).min(1),
|
|
13387
|
+
bids: z.array(z.object({
|
|
13388
|
+
id: z.number().int(),
|
|
13389
|
+
bidder: z.string().min(1),
|
|
13390
|
+
price: z.number(),
|
|
13391
|
+
goodIds: z.array(z.number().int().nonnegative())
|
|
13392
|
+
})).min(1)
|
|
13393
|
+
});
|
|
13394
|
+
const ContinuousProblemSchema = z.object({
|
|
13395
|
+
family: z.literal("continuous"),
|
|
13396
|
+
name: z.string().min(1),
|
|
13397
|
+
description: z.string().optional(),
|
|
13398
|
+
functionId: z.enum([
|
|
13399
|
+
"rastrigin",
|
|
13400
|
+
"ackley",
|
|
13401
|
+
"himmelblau",
|
|
13402
|
+
"wavy-bowl"
|
|
13403
|
+
]),
|
|
13404
|
+
dims: z.union([z.literal(1), z.literal(2)]),
|
|
13405
|
+
lo: z.number(),
|
|
13406
|
+
hi: z.number(),
|
|
13407
|
+
paramNames: z.array(z.string())
|
|
13408
|
+
});
|
|
13409
|
+
z.discriminatedUnion("family", [
|
|
13410
|
+
RoutingProblemSchema,
|
|
13411
|
+
PackingProblemSchema,
|
|
13412
|
+
AssignmentProblemSchema,
|
|
13413
|
+
NetworkProblemSchema,
|
|
13414
|
+
PartitionProblemSchema,
|
|
13415
|
+
SelectionProblemSchema,
|
|
13416
|
+
EconomicProblemSchema,
|
|
13417
|
+
ContinuousProblemSchema
|
|
13418
|
+
]);
|
|
13419
|
+
const refineAssignment = (p, ctx) => {
|
|
13420
|
+
if (p.cost.length !== p.agents.length) ctx.addIssue({
|
|
13421
|
+
code: z.ZodIssueCode.custom,
|
|
13422
|
+
path: ["cost"],
|
|
13423
|
+
message: `cost must have one row per agent (${p.agents.length}); got ${p.cost.length}`
|
|
13424
|
+
});
|
|
13425
|
+
p.cost.forEach((row, i) => {
|
|
13426
|
+
if (row.length !== p.tasks.length) ctx.addIssue({
|
|
13427
|
+
code: z.ZodIssueCode.custom,
|
|
13428
|
+
path: ["cost", i],
|
|
13429
|
+
message: `cost row ${i} must have one column per task (${p.tasks.length}); got ${row.length}`
|
|
13430
|
+
});
|
|
13431
|
+
});
|
|
13432
|
+
};
|
|
13433
|
+
const refineEdgeBounds = (p, ctx) => {
|
|
13434
|
+
const n = p.nodes.length;
|
|
13435
|
+
p.edges.forEach((e, i) => {
|
|
13436
|
+
if (e.a >= n || e.b >= n) ctx.addIssue({
|
|
13437
|
+
code: z.ZodIssueCode.custom,
|
|
13438
|
+
path: ["edges", i],
|
|
13439
|
+
message: `edge endpoints must reference nodes 0..${n - 1}; got a=${e.a}, b=${e.b}`
|
|
13440
|
+
});
|
|
13441
|
+
});
|
|
13442
|
+
};
|
|
13443
|
+
const refineEconomic = (p, ctx) => {
|
|
13444
|
+
const n = p.goods.length;
|
|
13445
|
+
p.bids.forEach((bid, i) => {
|
|
13446
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13447
|
+
bid.goodIds.forEach((g, j) => {
|
|
13448
|
+
if (g >= n) ctx.addIssue({
|
|
13449
|
+
code: z.ZodIssueCode.custom,
|
|
13450
|
+
path: [
|
|
13451
|
+
"bids",
|
|
13452
|
+
i,
|
|
13453
|
+
"goodIds",
|
|
13454
|
+
j
|
|
13455
|
+
],
|
|
13456
|
+
message: `goodId must reference goods 0..${n - 1}; got ${g}`
|
|
13457
|
+
});
|
|
13458
|
+
if (seen.has(g)) ctx.addIssue({
|
|
13459
|
+
code: z.ZodIssueCode.custom,
|
|
13460
|
+
path: [
|
|
13461
|
+
"bids",
|
|
13462
|
+
i,
|
|
13463
|
+
"goodIds",
|
|
13464
|
+
j
|
|
13465
|
+
],
|
|
13466
|
+
message: `duplicate goodId ${g} in bid ${i}`
|
|
13467
|
+
});
|
|
13468
|
+
seen.add(g);
|
|
13469
|
+
});
|
|
13470
|
+
});
|
|
13471
|
+
};
|
|
13472
|
+
/** Per-family schema lookup — the editor/tool pick the right one by familyId. */
|
|
13473
|
+
const FAMILY_PROBLEM_SCHEMAS = {
|
|
13474
|
+
routing: RoutingProblemSchema,
|
|
13475
|
+
packing: PackingProblemSchema,
|
|
13476
|
+
assignment: AssignmentProblemSchema.superRefine(refineAssignment),
|
|
13477
|
+
network: NetworkProblemSchema.superRefine(refineEdgeBounds),
|
|
13478
|
+
partitioning: PartitionProblemSchema.superRefine(refineEdgeBounds),
|
|
13479
|
+
selection: SelectionProblemSchema,
|
|
13480
|
+
economic: EconomicProblemSchema.superRefine(refineEconomic),
|
|
13481
|
+
continuous: ContinuousProblemSchema
|
|
13482
|
+
};
|
|
13483
|
+
const FAMILY_SAMPLE_PROBLEMS = {
|
|
13484
|
+
routing: routingSampleProblems,
|
|
13485
|
+
packing: packingSampleProblems,
|
|
13486
|
+
assignment: assignmentSampleProblems,
|
|
13487
|
+
network: networkSampleProblems,
|
|
13488
|
+
partitioning: partitioningSampleProblems,
|
|
13489
|
+
selection: selectionSampleProblems,
|
|
13490
|
+
economic: economicSampleProblems,
|
|
13491
|
+
continuous: continuousSampleProblems
|
|
13492
|
+
};
|
|
11251
13493
|
//#endregion
|
|
11252
|
-
//#region ../../b4m-core/services/dist/tools-
|
|
13494
|
+
//#region ../../b4m-core/services/dist/tools-BhiSgg5-.mjs
|
|
13495
|
+
const createFabFileSchema = z.object({
|
|
13496
|
+
fileName: z.string(),
|
|
13497
|
+
mimeType: z.string(),
|
|
13498
|
+
fileSize: z.number(),
|
|
13499
|
+
type: z.enum(KnowledgeType),
|
|
13500
|
+
content: z.union([z.string(), z.instanceof(Buffer)]).optional(),
|
|
13501
|
+
organizationId: z.string().optional(),
|
|
13502
|
+
/**
|
|
13503
|
+
* Content type of the file
|
|
13504
|
+
* @example 'text/markdown'
|
|
13505
|
+
* @example 'application/pdf'
|
|
13506
|
+
* @example 'application/octet-stream' for binary files
|
|
13507
|
+
*/
|
|
13508
|
+
contentType: z.string().optional(),
|
|
13509
|
+
public: z.boolean().optional(),
|
|
13510
|
+
prefix: z.string().optional(),
|
|
13511
|
+
system: z.boolean().optional(),
|
|
13512
|
+
tags: z.array(z.object({
|
|
13513
|
+
name: z.string(),
|
|
13514
|
+
strength: z.number()
|
|
13515
|
+
})).optional(),
|
|
13516
|
+
systemPriority: z.number().optional(),
|
|
13517
|
+
sessionId: z.string().optional(),
|
|
13518
|
+
contentHash: z.string().optional(),
|
|
13519
|
+
batchId: z.string().optional(),
|
|
13520
|
+
relativePath: z.string().optional()
|
|
13521
|
+
});
|
|
13522
|
+
const DEFAULT_MAX_FILE_SIZE = 20;
|
|
13523
|
+
const DEFAULT_EXPIRE_IN_SECONDS = 3600 * 24 * 5;
|
|
13524
|
+
const createFabFile = async (userId, parameters, { db, storage }) => {
|
|
13525
|
+
const params = secureParameters(parameters, createFabFileSchema);
|
|
13526
|
+
const user = await db.users.findById(userId);
|
|
13527
|
+
if (!user) throw new BadRequestError("User not found");
|
|
13528
|
+
let ext = "";
|
|
13529
|
+
let mimeType = parameters.mimeType;
|
|
13530
|
+
ext = getFileExtension(params.fileName);
|
|
13531
|
+
mimeType = params.mimeType || getMimeTypeByExtension(ext);
|
|
13532
|
+
if (!mimeType) mimeType = SupportedFabFileMimeTypes.TXT_PLAIN;
|
|
13533
|
+
if (!Object.values(SupportedFabFileMimeTypes).some((type) => type === mimeType)) throw new BadRequestError(`File type ${mimeType} is not supported`);
|
|
13534
|
+
let filePath = params.prefix ? `${params.prefix}/` : "";
|
|
13535
|
+
filePath += `${v4()}${ext ? `.${ext}` : ".txt"}`;
|
|
13536
|
+
const maxFileSize = getSettingsValue("MaxFileSize", await getSettingsMap(db), DEFAULT_MAX_FILE_SIZE) * 1024 * 1024;
|
|
13537
|
+
if (params.fileSize >= maxFileSize) throw new BadRequestError("File size exceeds maximum file size");
|
|
13538
|
+
await checkStorageLimitForFile(user, params.fileSize, params.organizationId, db.organizations?.findById);
|
|
13539
|
+
const buildData = {
|
|
13540
|
+
userId,
|
|
13541
|
+
...params,
|
|
13542
|
+
mimeType,
|
|
13543
|
+
filePath,
|
|
13544
|
+
users: [],
|
|
13545
|
+
groups: [],
|
|
13546
|
+
isGlobalRead: false,
|
|
13547
|
+
isGlobalWrite: false,
|
|
13548
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
13549
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
13550
|
+
};
|
|
13551
|
+
if (params.content) {
|
|
13552
|
+
await storage.upload(filePath, params.content, {
|
|
13553
|
+
ContentType: params.contentType,
|
|
13554
|
+
ContentLength: params.fileSize
|
|
13555
|
+
});
|
|
13556
|
+
buildData.fileUrl = await storage.generateSignedUrl(filePath, DEFAULT_EXPIRE_IN_SECONDS, "get");
|
|
13557
|
+
buildData.fileUrlExpireAt = new Date(Date.now() + DEFAULT_EXPIRE_IN_SECONDS * 1e3);
|
|
13558
|
+
} else buildData.presignedUrl = await storage.generateSignedUrl(filePath, 600, "put");
|
|
13559
|
+
return await db.fabFiles.create(buildData);
|
|
13560
|
+
};
|
|
11253
13561
|
async function performDeepResearch(context, params, config = {}) {
|
|
11254
13562
|
const maxDepth = config.maxDepth || 7;
|
|
11255
13563
|
const duration = config.duration || 4.5;
|
|
@@ -11610,9 +13918,10 @@ const deepResearchTool = {
|
|
|
11610
13918
|
async function getDynamicDataLakeAccess(context) {
|
|
11611
13919
|
const userTags = context.user.tags || [];
|
|
11612
13920
|
const entitlementKeys = context.entitlementKeys ?? [];
|
|
13921
|
+
const organizationId = context.user.organizationId ? String(context.user.organizationId) : void 0;
|
|
11613
13922
|
let dynamicDataLakes;
|
|
11614
13923
|
if (context.db.dataLakes) try {
|
|
11615
|
-
dynamicDataLakes = (await context.db.dataLakes.findActiveByUserTagsAndEntitlements(userTags, entitlementKeys)).map(toDataLakeConfig);
|
|
13924
|
+
dynamicDataLakes = (await context.db.dataLakes.findActiveByUserTagsAndEntitlements(userTags, entitlementKeys, organizationId)).map(toDataLakeConfig);
|
|
11616
13925
|
} catch {}
|
|
11617
13926
|
const accessibleLakes = getAccessibleDataLakes(userTags, dynamicDataLakes, entitlementKeys);
|
|
11618
13927
|
return {
|
|
@@ -11760,6 +14069,60 @@ const weatherTool = {
|
|
|
11760
14069
|
}
|
|
11761
14070
|
})
|
|
11762
14071
|
};
|
|
14072
|
+
/**
|
|
14073
|
+
* Persist a tool-generated file (image, Excel, etc.) as a session-scoped FabFile so it
|
|
14074
|
+
* shows up in the Knowledge Base / WorkBench and is downloadable after the run.
|
|
14075
|
+
*
|
|
14076
|
+
* Why this exists: file-generating tools historically only pushed the generated filename
|
|
14077
|
+
* into `quest.images` via `statusUpdate`, which (a) renders fine inline for images but is
|
|
14078
|
+
* a broken `<img>` for non-image files like .xlsx, and (b) was never recorded as a FabFile,
|
|
14079
|
+
* so nothing the user can browse referenced it — the file was effectively orphaned in the
|
|
14080
|
+
* generated-content bucket (see prod session 6a41abae…, where 4 agent-generated images were
|
|
14081
|
+
* lost entirely). Creating a FabFile with `sessionId` set makes the file appear in the
|
|
14082
|
+
* Knowledge Viewer via `useGetFabFilesBySessionId` → `useMessageFiles`.
|
|
14083
|
+
*
|
|
14084
|
+
* Best-effort: a failure here (missing adapters, storage quota, unsupported mime) must never
|
|
14085
|
+
* break the tool itself — the inline `quest.images` render still works. We log and swallow.
|
|
14086
|
+
*
|
|
14087
|
+
* The file is re-uploaded into the FabFile bucket (`context.storage`) because the Knowledge
|
|
14088
|
+
* Viewer reads FabFiles through their signed `fileUrl`, which is issued against that bucket.
|
|
14089
|
+
*/
|
|
14090
|
+
async function persistGeneratedFileAsFabFile(context, file) {
|
|
14091
|
+
const { sessionId, userId, db, storage, logger } = context;
|
|
14092
|
+
if (!sessionId) return;
|
|
14093
|
+
if (!db.fabfiles || !db.users || !db.adminSettings) {
|
|
14094
|
+
logger.warn("[persistGeneratedFileAsFabFile] missing db adapters — skipping FabFile persist");
|
|
14095
|
+
return;
|
|
14096
|
+
}
|
|
14097
|
+
try {
|
|
14098
|
+
await createFabFile(userId, {
|
|
14099
|
+
fileName: file.fileName,
|
|
14100
|
+
mimeType: file.mimeType,
|
|
14101
|
+
fileSize: file.content.length,
|
|
14102
|
+
type: KnowledgeType.FILE,
|
|
14103
|
+
content: file.content,
|
|
14104
|
+
contentType: file.mimeType,
|
|
14105
|
+
sessionId,
|
|
14106
|
+
prefix: "generated",
|
|
14107
|
+
tags: [{
|
|
14108
|
+
name: "generated",
|
|
14109
|
+
strength: 1
|
|
14110
|
+
}]
|
|
14111
|
+
}, {
|
|
14112
|
+
db: {
|
|
14113
|
+
fabFiles: db.fabfiles,
|
|
14114
|
+
adminSettings: db.adminSettings,
|
|
14115
|
+
users: db.users
|
|
14116
|
+
},
|
|
14117
|
+
storage: {
|
|
14118
|
+
upload: (path, content, options) => storage.upload(content, path, options),
|
|
14119
|
+
generateSignedUrl: (path, expireInSeconds, type) => storage.getSignedUrl(path, type ?? "get", { expiresIn: expireInSeconds })
|
|
14120
|
+
}
|
|
14121
|
+
});
|
|
14122
|
+
} catch (err) {
|
|
14123
|
+
logger.error("[persistGeneratedFileAsFabFile] failed to persist generated file (non-fatal)", err);
|
|
14124
|
+
}
|
|
14125
|
+
}
|
|
11763
14126
|
async function downloadImage$1(url) {
|
|
11764
14127
|
if (url.startsWith("data:image/")) {
|
|
11765
14128
|
const base64Data = url.split(",")[1];
|
|
@@ -11793,8 +14156,15 @@ async function processAndStoreImages(images, context) {
|
|
|
11793
14156
|
return Promise.all(images.map(async (image) => {
|
|
11794
14157
|
const buffer = await downloadImage$1(image);
|
|
11795
14158
|
const fileType = await fileTypeFromBuffer(buffer);
|
|
11796
|
-
const
|
|
11797
|
-
|
|
14159
|
+
const ext = fileType?.ext ?? "png";
|
|
14160
|
+
const filename = `${v4()}.${ext}`;
|
|
14161
|
+
const path = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
14162
|
+
await persistGeneratedFileAsFabFile(context, {
|
|
14163
|
+
fileName: `generated-image-${filename.slice(0, 8)}.${ext}`,
|
|
14164
|
+
mimeType: fileType?.mime ?? "image/png",
|
|
14165
|
+
content: buffer
|
|
14166
|
+
});
|
|
14167
|
+
return path;
|
|
11798
14168
|
}));
|
|
11799
14169
|
}
|
|
11800
14170
|
async function updateQuestAndReturnMarkdown$1(storedImageUrls, context) {
|
|
@@ -15278,13 +17648,13 @@ const knowledgeBaseRetrieveTool = {
|
|
|
15278
17648
|
function formatResult$1(result) {
|
|
15279
17649
|
const lines = [
|
|
15280
17650
|
`Solver: ${result.solverName} (${result.solverId})`,
|
|
15281
|
-
`Makespan: ${result.
|
|
17651
|
+
`Makespan: ${result.objective}`,
|
|
15282
17652
|
`Elapsed: ${result.elapsedMs.toFixed(1)}ms`
|
|
15283
17653
|
];
|
|
15284
17654
|
if (result.iterations !== void 0) lines.push(`Iterations: ${result.iterations}`);
|
|
15285
17655
|
lines.push("Schedule:");
|
|
15286
17656
|
const byMachine = /* @__PURE__ */ new Map();
|
|
15287
|
-
for (const op of result.
|
|
17657
|
+
for (const op of result.solution) {
|
|
15288
17658
|
if (!byMachine.has(op.machineId)) byMachine.set(op.machineId, []);
|
|
15289
17659
|
byMachine.get(op.machineId).push(op);
|
|
15290
17660
|
}
|
|
@@ -15321,13 +17691,13 @@ async function runQuantumSchedule(params) {
|
|
|
15321
17691
|
}
|
|
15322
17692
|
}
|
|
15323
17693
|
if (results.length === 0) return `Error: No solvers completed successfully.\n${errors.join("\n")}`;
|
|
15324
|
-
results.sort((a, b) => a.
|
|
17694
|
+
results.sort((a, b) => a.objective - b.objective);
|
|
15325
17695
|
const lines = [];
|
|
15326
17696
|
lines.push(`## Scheduling Results for "${problem.name}"`);
|
|
15327
17697
|
lines.push(`Problem: ${problem.jobs.length} jobs, ${problem.machines.length} machines, ${problem.jobs.reduce((s, j) => s + j.operations.length, 0)} operations`);
|
|
15328
17698
|
lines.push("");
|
|
15329
17699
|
if (results.length > 1) {
|
|
15330
|
-
lines.push(`### Winner: ${results[0].solverName} (makespan: ${results[0].
|
|
17700
|
+
lines.push(`### Winner: ${results[0].solverName} (makespan: ${results[0].objective})`);
|
|
15331
17701
|
lines.push("");
|
|
15332
17702
|
}
|
|
15333
17703
|
for (const result of results) {
|
|
@@ -15444,37 +17814,92 @@ The problem must define jobs (each with ordered operations) and machines. Each o
|
|
|
15444
17814
|
}
|
|
15445
17815
|
})
|
|
15446
17816
|
};
|
|
17817
|
+
const FAMILY_IDS = [
|
|
17818
|
+
"routing",
|
|
17819
|
+
"packing",
|
|
17820
|
+
"assignment",
|
|
17821
|
+
"network",
|
|
17822
|
+
"partitioning",
|
|
17823
|
+
"selection",
|
|
17824
|
+
"economic",
|
|
17825
|
+
"continuous"
|
|
17826
|
+
];
|
|
17827
|
+
/** Run the model and pull a JSON object out of the response (handles code fences). */
|
|
17828
|
+
async function completeToJson(context, systemPrompt, userDescription) {
|
|
17829
|
+
let rawContent = "";
|
|
17830
|
+
await context.llm.complete(context.model ?? "gpt-4", [{
|
|
17831
|
+
role: "system",
|
|
17832
|
+
content: systemPrompt
|
|
17833
|
+
}, {
|
|
17834
|
+
role: "user",
|
|
17835
|
+
content: userDescription
|
|
17836
|
+
}], {
|
|
17837
|
+
temperature: .2,
|
|
17838
|
+
stream: false
|
|
17839
|
+
}, async (texts) => {
|
|
17840
|
+
rawContent = texts.filter((t) => t !== null && t !== void 0).join("");
|
|
17841
|
+
});
|
|
17842
|
+
let jsonStr = rawContent.trim();
|
|
17843
|
+
const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
17844
|
+
if (codeBlockMatch) jsonStr = codeBlockMatch[1].trim();
|
|
17845
|
+
try {
|
|
17846
|
+
return { json: JSON.parse(jsonStr) };
|
|
17847
|
+
} catch {
|
|
17848
|
+
return { error: `Could not parse the model response as JSON. Raw response:\n${rawContent}` };
|
|
17849
|
+
}
|
|
17850
|
+
}
|
|
17851
|
+
/** Build the per-family system prompt from a real sample as the shape template. */
|
|
17852
|
+
function familyFormulationPrompt(familyId) {
|
|
17853
|
+
return `You convert a natural-language description into a "${familyId}" optimization problem as JSON.
|
|
17854
|
+
|
|
17855
|
+
Output ONLY a single JSON object matching this exact shape (a real ${familyId} example):
|
|
17856
|
+
|
|
17857
|
+
${JSON.stringify(FAMILY_SAMPLE_PROBLEMS[familyId][0], null, 2)}
|
|
17858
|
+
|
|
17859
|
+
Rules:
|
|
17860
|
+
- "family" MUST be exactly "${familyId}".
|
|
17861
|
+
- Keep it small and browser-solvable, at a scale similar to the example.
|
|
17862
|
+
- ids are integers starting at 0; names are short human-readable strings.
|
|
17863
|
+
- Output ONLY the JSON object — no prose, no markdown fences.`;
|
|
17864
|
+
}
|
|
15447
17865
|
const quantumFormulateTool = {
|
|
15448
17866
|
name: "quantum_formulate",
|
|
15449
17867
|
implementation: (context) => ({
|
|
15450
17868
|
toolFn: async (value) => {
|
|
15451
|
-
const
|
|
15452
|
-
|
|
17869
|
+
const params = value;
|
|
17870
|
+
const userDescription = params.description?.trim();
|
|
17871
|
+
if (!userDescription) return "Error: Please provide a description of the optimization problem to formulate.";
|
|
17872
|
+
if (params.familyId && !FAMILY_IDS.includes(params.familyId)) return `Error: unknown familyId "${String(params.familyId)}". Valid families: ${FAMILY_IDS.join(", ")}. Omit familyId to formulate a job-shop scheduling problem.`;
|
|
17873
|
+
const familyId = params.familyId || void 0;
|
|
15453
17874
|
try {
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15473
|
-
|
|
15474
|
-
|
|
17875
|
+
if (familyId) {
|
|
17876
|
+
const result = await completeToJson(context, familyFormulationPrompt(familyId), userDescription);
|
|
17877
|
+
if ("error" in result) return `Error: ${result.error}\n\nPlease rephrase with more specifics for a ${familyId} problem.`;
|
|
17878
|
+
const validated = FAMILY_PROBLEM_SCHEMAS[familyId].safeParse(result.json);
|
|
17879
|
+
if (!validated.success) return `Error: the model produced an invalid ${familyId} problem.\n${validated.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}\n\nPlease rephrase your description.`;
|
|
17880
|
+
const problem = validated.data;
|
|
17881
|
+
const summary = [
|
|
17882
|
+
`## Formulated: "${problem.name}"`,
|
|
17883
|
+
problem.description ? `\n${problem.description}` : "",
|
|
17884
|
+
"",
|
|
17885
|
+
`**${familyId} problem** — ready to load.`,
|
|
17886
|
+
"",
|
|
17887
|
+
`Open the ${familyId} console's Problem tab and click "Load problem" on the pending banner to review, tweak, and race solvers.`
|
|
17888
|
+
].filter((l) => l !== void 0).join("\n");
|
|
17889
|
+
return JSON.stringify({
|
|
17890
|
+
__uiSideEffect: true,
|
|
17891
|
+
type: "populateFamilyProblem",
|
|
17892
|
+
payload: {
|
|
17893
|
+
familyId,
|
|
17894
|
+
problem
|
|
17895
|
+
},
|
|
17896
|
+
displayMessage: summary
|
|
17897
|
+
});
|
|
15475
17898
|
}
|
|
15476
|
-
const
|
|
15477
|
-
if (
|
|
17899
|
+
const result = await completeToJson(context, PROBLEM_FORMULATION_PROMPT, userDescription);
|
|
17900
|
+
if ("error" in result) return `Error: ${result.error}\n\nPlease try rephrasing with specific jobs, machines, and processing times.`;
|
|
17901
|
+
const validated = SchedulingProblemSchema.safeParse(result.json);
|
|
17902
|
+
if (!validated.success) return `Error: LLM generated an invalid problem structure.\n${validated.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}\n\nPlease try rephrasing your description.`;
|
|
15478
17903
|
const problem = validated.data;
|
|
15479
17904
|
const totalOps = problem.jobs.reduce((s, j) => s + j.operations.length, 0);
|
|
15480
17905
|
const humanReadableSummary = [
|
|
@@ -15509,21 +17934,28 @@ const quantumFormulateTool = {
|
|
|
15509
17934
|
},
|
|
15510
17935
|
toolSchema: {
|
|
15511
17936
|
name: "quantum_formulate",
|
|
15512
|
-
description: `Convert a natural
|
|
17937
|
+
description: `Convert a natural-language description of an optimization problem into a structured problem that the /opti solvers can run.
|
|
15513
17938
|
|
|
15514
|
-
|
|
17939
|
+
Pass \`familyId\` to target one of the eight pattern families; omit it for job-shop scheduling:
|
|
17940
|
+
- routing (TSP / vehicle routing), packing (bin packing), assignment (who does what),
|
|
17941
|
+
network (max-cut), partitioning (balanced k-way), selection (knapsack / portfolio),
|
|
17942
|
+
economic (combinatorial auction), continuous (function minimization).
|
|
15515
17943
|
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
- "Schedule 4 software builds across 2 CI runners. Build A needs compile (5min) then test (3min)..."
|
|
15519
|
-
- "A bakery needs to make 5 cakes. Each cake goes through mixing, baking, and decorating on separate stations."`,
|
|
15520
|
-
strict: true,
|
|
17944
|
+
Describe the scenario in plain English — the entities, resources, costs/values, and constraints — and the tool produces a structured problem definition for that family.`,
|
|
17945
|
+
strict: false,
|
|
15521
17946
|
parameters: {
|
|
15522
17947
|
type: "object",
|
|
15523
|
-
properties: {
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
17948
|
+
properties: {
|
|
17949
|
+
description: {
|
|
17950
|
+
type: "string",
|
|
17951
|
+
description: "Natural-language description of the optimization problem to formulate"
|
|
17952
|
+
},
|
|
17953
|
+
familyId: {
|
|
17954
|
+
type: "string",
|
|
17955
|
+
enum: FAMILY_IDS,
|
|
17956
|
+
description: "Optional optimization family. Omit for job-shop scheduling; otherwise one of the eight families."
|
|
17957
|
+
}
|
|
17958
|
+
},
|
|
15527
17959
|
required: ["description"],
|
|
15528
17960
|
additionalProperties: false
|
|
15529
17961
|
}
|
|
@@ -15837,6 +18269,7 @@ Please generate a complete, well-structured notebook that performs this analysis
|
|
|
15837
18269
|
}
|
|
15838
18270
|
})
|
|
15839
18271
|
};
|
|
18272
|
+
const XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
15840
18273
|
const LIMITS = {
|
|
15841
18274
|
MAX_SHEETS: 10,
|
|
15842
18275
|
MAX_CELLS_PER_SHEET: 1e4,
|
|
@@ -16155,9 +18588,14 @@ const excelGenerationTool = {
|
|
|
16155
18588
|
const sanitizedName = sanitizeFilename(params.filename);
|
|
16156
18589
|
const filename = `${sanitizedName}-${v4().slice(0, 8)}.xlsx`;
|
|
16157
18590
|
await context.imageGenerateStorage.upload(buffer, filename, {
|
|
16158
|
-
ContentType:
|
|
18591
|
+
ContentType: XLSX_MIME,
|
|
16159
18592
|
ContentDisposition: `attachment; filename="${sanitizedName}.xlsx"`
|
|
16160
18593
|
});
|
|
18594
|
+
await persistGeneratedFileAsFabFile(context, {
|
|
18595
|
+
fileName: `${sanitizedName}.xlsx`,
|
|
18596
|
+
mimeType: XLSX_MIME,
|
|
18597
|
+
content: buffer
|
|
18598
|
+
});
|
|
16161
18599
|
await context.onFinish?.("excel_generation", [filename]);
|
|
16162
18600
|
await context.statusUpdate({ images: [filename] });
|
|
16163
18601
|
return `Successfully generated Excel file: ${sanitizedName}.xlsx`;
|
|
@@ -17443,10 +19881,11 @@ const b4mTools = {
|
|
|
17443
19881
|
fmp_financial_data: fmpTool,
|
|
17444
19882
|
skill: skillTool
|
|
17445
19883
|
};
|
|
17446
|
-
const generateTools = (userId, user, logger, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model, imageProcessorLambdaName, tools = b4mTools, allowedDirectories, entitlementKeys = []) => {
|
|
19884
|
+
const generateTools = (userId, user, logger, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model, imageProcessorLambdaName, tools = b4mTools, allowedDirectories, entitlementKeys = [], sessionId) => {
|
|
17447
19885
|
const context = {
|
|
17448
19886
|
userId,
|
|
17449
19887
|
user,
|
|
19888
|
+
sessionId,
|
|
17450
19889
|
logger,
|
|
17451
19890
|
db,
|
|
17452
19891
|
storage,
|
|
@@ -18467,7 +20906,11 @@ var ReActAgent = class extends EventEmitter {
|
|
|
18467
20906
|
* This can be overridden in the context or customized here
|
|
18468
20907
|
*/
|
|
18469
20908
|
getSystemPrompt() {
|
|
18470
|
-
|
|
20909
|
+
const base = this.context.systemPrompt ? this.context.systemPrompt : this.buildDefaultSystemPrompt();
|
|
20910
|
+
const persona = this.context.personaPrompt?.trim();
|
|
20911
|
+
return persona ? `${persona}\n\n${base}` : base;
|
|
20912
|
+
}
|
|
20913
|
+
buildDefaultSystemPrompt() {
|
|
18471
20914
|
return `You are an autonomous AI agent with access to tools. Your job is to solve problems by taking action, not by asking for clarification.
|
|
18472
20915
|
|
|
18473
20916
|
CORE PRINCIPLES:
|
|
@@ -19090,7 +21533,7 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
19090
21533
|
})}</function>`;
|
|
19091
21534
|
}
|
|
19092
21535
|
}
|
|
19093
|
-
return `Error: Tool ${toolUse.name} not
|
|
21536
|
+
return `Error: Tool "${toolUse.name}" is not available in this context and cannot be called. Do NOT attempt to call it again. Proceed without it — call other available tools if your plan still needs them, or compose your final answer from the information already gathered if no more tools are needed.`;
|
|
19094
21537
|
}
|
|
19095
21538
|
try {
|
|
19096
21539
|
const params = this.parseToolArguments(toolUse.arguments);
|
|
@@ -20458,33 +22901,6 @@ z.object({
|
|
|
20458
22901
|
fabFileId: z.string(),
|
|
20459
22902
|
chunkId: z.string()
|
|
20460
22903
|
});
|
|
20461
|
-
z.object({
|
|
20462
|
-
fileName: z.string(),
|
|
20463
|
-
mimeType: z.string(),
|
|
20464
|
-
fileSize: z.number(),
|
|
20465
|
-
type: z.enum(KnowledgeType),
|
|
20466
|
-
content: z.union([z.string(), z.instanceof(Buffer)]).optional(),
|
|
20467
|
-
organizationId: z.string().optional(),
|
|
20468
|
-
/**
|
|
20469
|
-
* Content type of the file
|
|
20470
|
-
* @example 'text/markdown'
|
|
20471
|
-
* @example 'application/pdf'
|
|
20472
|
-
* @example 'application/octet-stream' for binary files
|
|
20473
|
-
*/
|
|
20474
|
-
contentType: z.string().optional(),
|
|
20475
|
-
public: z.boolean().optional(),
|
|
20476
|
-
prefix: z.string().optional(),
|
|
20477
|
-
system: z.boolean().optional(),
|
|
20478
|
-
tags: z.array(z.object({
|
|
20479
|
-
name: z.string(),
|
|
20480
|
-
strength: z.number()
|
|
20481
|
-
})).optional(),
|
|
20482
|
-
systemPriority: z.number().optional(),
|
|
20483
|
-
sessionId: z.string().optional(),
|
|
20484
|
-
contentHash: z.string().optional(),
|
|
20485
|
-
batchId: z.string().optional(),
|
|
20486
|
-
relativePath: z.string().optional()
|
|
20487
|
-
});
|
|
20488
22904
|
z.object({ sessionId: z.string() });
|
|
20489
22905
|
z.object({ questId: z.string() });
|
|
20490
22906
|
z.object({ url: z.string().regex(/^(?!https?:\/\/(drive|docs)\.google\.com\/(?:file\/d\/|open\?id=|uc\?id=|document\/d\/|spreadsheets\/d\/|presentation\/d\/|forms\/d\/|drive\/folders\/)([a-zA-Z0-9_-]{10,})).+/) });
|