@mcmcjs/julia 0.11.3 → 0.12.0
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/dist/fitlib.jl +127 -10
- package/dist/index.cjs +140 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +129 -39
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -233,7 +233,7 @@ async function runFit(spec, resolved, io) {
|
|
|
233
233
|
return finalizeOkFit(spec, resolved, io, lastJsonLine(stdout), startedAt, elapsedMs);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
// src/
|
|
236
|
+
// src/loglik.ts
|
|
237
237
|
import { existsSync as existsSync3, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
238
238
|
import { join as join4 } from "path";
|
|
239
239
|
import {
|
|
@@ -241,6 +241,95 @@ import {
|
|
|
241
241
|
parseSamples as parseSamples2,
|
|
242
242
|
RUN_RECORD_SCHEMA_VERSION as RUN_RECORD_SCHEMA_VERSION2
|
|
243
243
|
} from "@mcmcjs/core";
|
|
244
|
+
async function runLogLik(spec, resolved, io) {
|
|
245
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
246
|
+
const start = performance.now();
|
|
247
|
+
const runtimeRequested = spec.backend.version;
|
|
248
|
+
const ownTmp = io.tmpDir === void 0;
|
|
249
|
+
const tmp = io.tmpDir ?? makeRequestDir("loglik");
|
|
250
|
+
const requestPath = join4(tmp, "request.json");
|
|
251
|
+
writeFileSync2(
|
|
252
|
+
requestPath,
|
|
253
|
+
JSON.stringify({
|
|
254
|
+
mode: "loglik",
|
|
255
|
+
schema_version: spec.schema_version,
|
|
256
|
+
backend: { id: spec.backend.id },
|
|
257
|
+
model: { file: spec.modelPath, entry: spec.model.entry },
|
|
258
|
+
data: spec.data,
|
|
259
|
+
samples: io.samplesPath,
|
|
260
|
+
seed: spec.seed,
|
|
261
|
+
out: io.outPath
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
const args = [
|
|
265
|
+
...resolved.args,
|
|
266
|
+
"--startup-file=no",
|
|
267
|
+
`--project=${io.projectDir}`,
|
|
268
|
+
driverPath(),
|
|
269
|
+
requestPath
|
|
270
|
+
];
|
|
271
|
+
let stdout;
|
|
272
|
+
let stderr;
|
|
273
|
+
let code;
|
|
274
|
+
try {
|
|
275
|
+
({ stdout, stderr, code } = await io.spawn(resolved.command, args));
|
|
276
|
+
} finally {
|
|
277
|
+
if (ownTmp) rmSync2(tmp, { recursive: true, force: true });
|
|
278
|
+
}
|
|
279
|
+
const elapsedMs = Math.round(performance.now() - start);
|
|
280
|
+
if (code !== 0 || !existsSync3(io.outPath)) {
|
|
281
|
+
const failure = lastJsonLine(stderr);
|
|
282
|
+
const error = failure?.error ?? stderr.trim().split("\n").pop() ?? `julia exited with code ${code}`;
|
|
283
|
+
return { status: "error", runtimeRequested, elapsedMs, stage: toStage(failure?.stage), error };
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
parseSamples2(readFileSync2(io.outPath, "utf8"));
|
|
287
|
+
} catch (error) {
|
|
288
|
+
return {
|
|
289
|
+
status: "error",
|
|
290
|
+
runtimeRequested,
|
|
291
|
+
elapsedMs,
|
|
292
|
+
stage: "write",
|
|
293
|
+
error: `log-likelihood file did not parse: ${error.message}`
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const provenance = lastJsonLine(stdout);
|
|
297
|
+
const julia = provenance?.julia_version;
|
|
298
|
+
const record = {
|
|
299
|
+
schema_version: RUN_RECORD_SCHEMA_VERSION2,
|
|
300
|
+
spec_hash: spec.specHash,
|
|
301
|
+
seed: spec.seed,
|
|
302
|
+
backend: { id: spec.backend.id, runtime: spec.backend.runtime },
|
|
303
|
+
runtime: { requested: runtimeRequested, actual: julia, path: resolved.command },
|
|
304
|
+
manifest_sha256: provenance?.manifest_sha256,
|
|
305
|
+
packages: provenance?.packages,
|
|
306
|
+
model_sha256: existsSync3(spec.modelPath) ? sha256(readFileSync2(spec.modelPath, "utf8")) : void 0,
|
|
307
|
+
data_sha256: sha256(canonicalJson2(spec.data)),
|
|
308
|
+
posterior_samples: io.samplesPath,
|
|
309
|
+
posterior_samples_sha256: existsSync3(io.samplesPath) ? sha256(readFileSync2(io.samplesPath, "utf8")) : void 0,
|
|
310
|
+
samples_file: io.outPath,
|
|
311
|
+
started_at: startedAt,
|
|
312
|
+
elapsed_ms: elapsedMs
|
|
313
|
+
};
|
|
314
|
+
writeFileSync2(`${io.outPath}.run.json`, `${JSON.stringify(record, null, 2)}
|
|
315
|
+
`);
|
|
316
|
+
return {
|
|
317
|
+
status: "ok",
|
|
318
|
+
samplesFile: io.outPath,
|
|
319
|
+
runtimeRequested,
|
|
320
|
+
runtimeActual: julia,
|
|
321
|
+
elapsedMs
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/predict.ts
|
|
326
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
327
|
+
import { join as join5 } from "path";
|
|
328
|
+
import {
|
|
329
|
+
canonicalJson as canonicalJson3,
|
|
330
|
+
parseSamples as parseSamples3,
|
|
331
|
+
RUN_RECORD_SCHEMA_VERSION as RUN_RECORD_SCHEMA_VERSION3
|
|
332
|
+
} from "@mcmcjs/core";
|
|
244
333
|
function predictData(spec) {
|
|
245
334
|
const predict = spec.predict;
|
|
246
335
|
if (!predict) throw new Error("spec has no [predict] block");
|
|
@@ -258,8 +347,8 @@ async function runPredict(spec, resolved, io) {
|
|
|
258
347
|
const data = predictData(spec);
|
|
259
348
|
const ownTmp = io.tmpDir === void 0;
|
|
260
349
|
const tmp = io.tmpDir ?? makeRequestDir("predict");
|
|
261
|
-
const requestPath =
|
|
262
|
-
|
|
350
|
+
const requestPath = join5(tmp, "request.json");
|
|
351
|
+
writeFileSync3(
|
|
263
352
|
requestPath,
|
|
264
353
|
JSON.stringify({
|
|
265
354
|
mode: "predict",
|
|
@@ -286,16 +375,16 @@ async function runPredict(spec, resolved, io) {
|
|
|
286
375
|
try {
|
|
287
376
|
({ stdout, stderr, code } = await io.spawn(resolved.command, args));
|
|
288
377
|
} finally {
|
|
289
|
-
if (ownTmp)
|
|
378
|
+
if (ownTmp) rmSync3(tmp, { recursive: true, force: true });
|
|
290
379
|
}
|
|
291
380
|
const elapsedMs = Math.round(performance.now() - start);
|
|
292
|
-
if (code !== 0 || !
|
|
381
|
+
if (code !== 0 || !existsSync4(io.outPath)) {
|
|
293
382
|
const failure = lastJsonLine(stderr);
|
|
294
383
|
const error = failure?.error ?? stderr.trim().split("\n").pop() ?? `julia exited with code ${code}`;
|
|
295
384
|
return { status: "error", runtimeRequested, elapsedMs, stage: toStage(failure?.stage), error };
|
|
296
385
|
}
|
|
297
386
|
try {
|
|
298
|
-
|
|
387
|
+
parseSamples3(readFileSync3(io.outPath, "utf8"));
|
|
299
388
|
} catch (error) {
|
|
300
389
|
return {
|
|
301
390
|
status: "error",
|
|
@@ -308,22 +397,22 @@ async function runPredict(spec, resolved, io) {
|
|
|
308
397
|
const provenance = lastJsonLine(stdout);
|
|
309
398
|
const julia = provenance?.julia_version;
|
|
310
399
|
const record = {
|
|
311
|
-
schema_version:
|
|
400
|
+
schema_version: RUN_RECORD_SCHEMA_VERSION3,
|
|
312
401
|
spec_hash: spec.specHash,
|
|
313
402
|
seed: spec.seed,
|
|
314
403
|
backend: { id: spec.backend.id, runtime: spec.backend.runtime },
|
|
315
404
|
runtime: { requested: runtimeRequested, actual: julia, path: resolved.command },
|
|
316
405
|
manifest_sha256: provenance?.manifest_sha256,
|
|
317
406
|
packages: provenance?.packages,
|
|
318
|
-
model_sha256:
|
|
319
|
-
data_sha256: sha256(
|
|
407
|
+
model_sha256: existsSync4(spec.modelPath) ? sha256(readFileSync3(spec.modelPath, "utf8")) : void 0,
|
|
408
|
+
data_sha256: sha256(canonicalJson3(data)),
|
|
320
409
|
posterior_samples: io.samplesPath,
|
|
321
|
-
posterior_samples_sha256:
|
|
410
|
+
posterior_samples_sha256: existsSync4(io.samplesPath) ? sha256(readFileSync3(io.samplesPath, "utf8")) : void 0,
|
|
322
411
|
samples_file: io.outPath,
|
|
323
412
|
started_at: startedAt,
|
|
324
413
|
elapsed_ms: elapsedMs
|
|
325
414
|
};
|
|
326
|
-
|
|
415
|
+
writeFileSync3(`${io.outPath}.run.json`, `${JSON.stringify(record, null, 2)}
|
|
327
416
|
`);
|
|
328
417
|
return {
|
|
329
418
|
status: "ok",
|
|
@@ -335,10 +424,10 @@ async function runPredict(spec, resolved, io) {
|
|
|
335
424
|
}
|
|
336
425
|
|
|
337
426
|
// src/project.ts
|
|
338
|
-
import { copyFileSync, existsSync as
|
|
427
|
+
import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
339
428
|
import { homedir as homedir2 } from "os";
|
|
340
|
-
import { join as
|
|
341
|
-
import { canonicalJson as
|
|
429
|
+
import { join as join6 } from "path";
|
|
430
|
+
import { canonicalJson as canonicalJson4, DEFAULT_JULIA_CHANNEL } from "@mcmcjs/core";
|
|
342
431
|
import { createRunner as createRunner3 } from "@mcmcjs/engine";
|
|
343
432
|
var PACKAGES = [
|
|
344
433
|
"Turing",
|
|
@@ -375,19 +464,19 @@ function hasPins(pins) {
|
|
|
375
464
|
return pins !== void 0 && Object.keys(pins).length > 0;
|
|
376
465
|
}
|
|
377
466
|
function managedProjectDir(version, pins) {
|
|
378
|
-
const base = process.env.XDG_DATA_HOME ||
|
|
379
|
-
const root =
|
|
467
|
+
const base = process.env.XDG_DATA_HOME || join6(homedir2(), ".local", "share");
|
|
468
|
+
const root = join6(base, "mcmcjs", "julia", "env");
|
|
380
469
|
if (!version && !hasPins(pins)) return root;
|
|
381
470
|
let leaf = (version ?? "default").replace(/[^A-Za-z0-9._-]/g, "_");
|
|
382
|
-
if (hasPins(pins)) leaf += `-${sha256(
|
|
383
|
-
return
|
|
471
|
+
if (hasPins(pins)) leaf += `-${sha256(canonicalJson4(pins)).slice(0, 8)}`;
|
|
472
|
+
return join6(root, leaf);
|
|
384
473
|
}
|
|
385
474
|
function sentinelPath(dir) {
|
|
386
|
-
return
|
|
475
|
+
return join6(dir, ".mcmcjs-packages.json");
|
|
387
476
|
}
|
|
388
477
|
var PROVISION_GENERATION = 1;
|
|
389
478
|
function expectedSentinel(pins) {
|
|
390
|
-
return
|
|
479
|
+
return canonicalJson4({
|
|
391
480
|
gen: PROVISION_GENERATION,
|
|
392
481
|
packages: [...PACKAGES].sort(),
|
|
393
482
|
pins: pins ?? {}
|
|
@@ -395,13 +484,13 @@ function expectedSentinel(pins) {
|
|
|
395
484
|
}
|
|
396
485
|
function provisioned(dir, pins) {
|
|
397
486
|
try {
|
|
398
|
-
return
|
|
487
|
+
return readFileSync4(sentinelPath(dir), "utf8").trim() === expectedSentinel(pins);
|
|
399
488
|
} catch {
|
|
400
489
|
return false;
|
|
401
490
|
}
|
|
402
491
|
}
|
|
403
492
|
function managedProjectReady(dir = managedProjectDir(), pins) {
|
|
404
|
-
return
|
|
493
|
+
return existsSync5(join6(dir, "Project.toml")) && provisioned(dir, pins);
|
|
405
494
|
}
|
|
406
495
|
function packageSpecsCode(pins) {
|
|
407
496
|
const specs = PACKAGES.map((name) => {
|
|
@@ -411,15 +500,15 @@ function packageSpecsCode(pins) {
|
|
|
411
500
|
return `[${specs.join(", ")}]`;
|
|
412
501
|
}
|
|
413
502
|
function usesPinnedEnv(version, pins) {
|
|
414
|
-
return !hasPins(pins) && version === DEFAULT_JULIA_CHANNEL &&
|
|
503
|
+
return !hasPins(pins) && version === DEFAULT_JULIA_CHANNEL && existsSync5(pinnedEnvDir());
|
|
415
504
|
}
|
|
416
505
|
async function ensureProject(juliaBin, run = createRunner3(30 * 6e4), dir = managedProjectDir(), pins, opts) {
|
|
417
506
|
validatePins(pins);
|
|
418
507
|
if (managedProjectReady(dir, pins)) return dir;
|
|
419
508
|
mkdirSync2(dir, { recursive: true });
|
|
420
509
|
if (usesPinnedEnv(opts?.version, pins)) {
|
|
421
|
-
copyFileSync(
|
|
422
|
-
copyFileSync(
|
|
510
|
+
copyFileSync(join6(pinnedEnvDir(), "Project.toml"), join6(dir, "Project.toml"));
|
|
511
|
+
copyFileSync(join6(pinnedEnvDir(), "Manifest.toml"), join6(dir, "Manifest.toml"));
|
|
423
512
|
await run(juliaBin, [
|
|
424
513
|
"--startup-file=no",
|
|
425
514
|
`--project=${dir}`,
|
|
@@ -430,12 +519,12 @@ async function ensureProject(juliaBin, run = createRunner3(30 * 6e4), dir = mana
|
|
|
430
519
|
const code = `using Pkg; Pkg.add(${packageSpecsCode(pins)}); Pkg.precompile()`;
|
|
431
520
|
await run(juliaBin, ["--startup-file=no", `--project=${dir}`, "-e", code]);
|
|
432
521
|
}
|
|
433
|
-
|
|
522
|
+
writeFileSync4(sentinelPath(dir), expectedSentinel(pins));
|
|
434
523
|
return dir;
|
|
435
524
|
}
|
|
436
525
|
|
|
437
526
|
// src/run-matrix.ts
|
|
438
|
-
import { join as
|
|
527
|
+
import { join as join7 } from "path";
|
|
439
528
|
async function runMatrix(spec, versions, io) {
|
|
440
529
|
const entries = [];
|
|
441
530
|
for (const version of versions) {
|
|
@@ -447,7 +536,7 @@ async function runMatrix(spec, versions, io) {
|
|
|
447
536
|
const result = await runFit(versioned, resolved, {
|
|
448
537
|
spawn: io.spawn,
|
|
449
538
|
projectDir,
|
|
450
|
-
outPath:
|
|
539
|
+
outPath: join7(io.outDir, `${version}.samples.json`),
|
|
451
540
|
dataFile: io.dataFile,
|
|
452
541
|
dataSha256: io.dataSha256
|
|
453
542
|
});
|
|
@@ -624,9 +713,9 @@ function assertVersionsInstalled(channels, installed) {
|
|
|
624
713
|
|
|
625
714
|
// src/worker.ts
|
|
626
715
|
import { spawn } from "child_process";
|
|
627
|
-
import { mkdirSync as mkdirSync3, readdirSync, readFileSync as
|
|
716
|
+
import { mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync5, rmdirSync, rmSync as rmSync4, statSync } from "fs";
|
|
628
717
|
import { createConnection } from "net";
|
|
629
|
-
import { join as
|
|
718
|
+
import { join as join8 } from "path";
|
|
630
719
|
import { parseDrawBatchLine, parseProgressLine } from "@mcmcjs/engine";
|
|
631
720
|
var START_WAIT_MS = 18e4;
|
|
632
721
|
var CONNECT_TIMEOUT_MS = 1e3;
|
|
@@ -645,7 +734,7 @@ function workerPidPath(socket) {
|
|
|
645
734
|
function killWorker(socket) {
|
|
646
735
|
const pidPath = workerPidPath(socket);
|
|
647
736
|
try {
|
|
648
|
-
const pid = Number(
|
|
737
|
+
const pid = Number(readFileSync5(pidPath, "utf8").trim());
|
|
649
738
|
if (Number.isInteger(pid) && pid > 0) {
|
|
650
739
|
try {
|
|
651
740
|
process.kill(-pid, "SIGKILL");
|
|
@@ -655,17 +744,17 @@ function killWorker(socket) {
|
|
|
655
744
|
}
|
|
656
745
|
} catch {
|
|
657
746
|
}
|
|
658
|
-
|
|
659
|
-
|
|
747
|
+
rmSync4(socket, { force: true });
|
|
748
|
+
rmSync4(pidPath, { force: true });
|
|
660
749
|
}
|
|
661
750
|
function workersDir() {
|
|
662
751
|
const runtime = process.env.XDG_RUNTIME_DIR;
|
|
663
|
-
const dir = runtime ?
|
|
752
|
+
const dir = runtime ? join8(runtime, "mcmcjs") : join8(sharedTmpParent(), "workers");
|
|
664
753
|
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
665
754
|
return dir;
|
|
666
755
|
}
|
|
667
756
|
function workerSocketPath(command, projectDir) {
|
|
668
|
-
return
|
|
757
|
+
return join8(workersDir(), `worker-${sha256(`${command}
|
|
669
758
|
${projectDir}`).slice(0, 12)}.sock`);
|
|
670
759
|
}
|
|
671
760
|
function connectOnce(path) {
|
|
@@ -720,7 +809,7 @@ async function ensureWorker(resolved, projectDir, notify, signal) {
|
|
|
720
809
|
const startedHere = acquireStartLock(path);
|
|
721
810
|
if (startedHere) {
|
|
722
811
|
try {
|
|
723
|
-
|
|
812
|
+
rmSync4(path, { force: true });
|
|
724
813
|
notify?.("starting the Julia worker (first use loads Turing, can take a minute)...");
|
|
725
814
|
const child = spawn(
|
|
726
815
|
resolved.command,
|
|
@@ -915,7 +1004,7 @@ async function listWorkers() {
|
|
|
915
1004
|
const sockets = readdirSync(dir).filter((f) => f.startsWith("worker-") && f.endsWith(".sock"));
|
|
916
1005
|
const statuses = [];
|
|
917
1006
|
for (const name of sockets) {
|
|
918
|
-
const socket =
|
|
1007
|
+
const socket = join8(dir, name);
|
|
919
1008
|
let alive = false;
|
|
920
1009
|
try {
|
|
921
1010
|
const sock = await connectOnce(socket);
|
|
@@ -932,7 +1021,7 @@ async function stopWorker(socket) {
|
|
|
932
1021
|
try {
|
|
933
1022
|
sock = await connectOnce(socket);
|
|
934
1023
|
} catch {
|
|
935
|
-
|
|
1024
|
+
rmSync4(socket, { force: true });
|
|
936
1025
|
return "stale";
|
|
937
1026
|
}
|
|
938
1027
|
const acked = await new Promise((resolve) => {
|
|
@@ -948,7 +1037,7 @@ async function stopWorker(socket) {
|
|
|
948
1037
|
});
|
|
949
1038
|
sock.destroy();
|
|
950
1039
|
if (!acked) return "pending";
|
|
951
|
-
|
|
1040
|
+
rmSync4(socket, { force: true });
|
|
952
1041
|
return "stopped";
|
|
953
1042
|
}
|
|
954
1043
|
export {
|
|
@@ -972,6 +1061,7 @@ export {
|
|
|
972
1061
|
runDoctor,
|
|
973
1062
|
runFit,
|
|
974
1063
|
runFitAuto,
|
|
1064
|
+
runLogLik,
|
|
975
1065
|
runMatrix,
|
|
976
1066
|
runPredict,
|
|
977
1067
|
runSetup,
|