eyelang 1.1.14 → 1.1.16

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/docs/guide.md CHANGED
@@ -302,10 +302,10 @@ Use `holds/2` when you want to match the member term directly, for example `name
302
302
 
303
303
  ## Example catalog
304
304
 
305
- The repository includes examples for recursion, graph reachability, finite search, arithmetic, list processing, optimization, policies, puzzles, and applied scientific calculations. Bundled examples use relation-style output.
305
+ Each example has a checked golden output in `examples/output`.
306
306
 
307
- | Input | Short description | Output |
308
- | --- | --- | --- |
307
+ | Example | What it demonstrates | Golden output |
308
+ |---|---|---|
309
309
  | [`access-control-policy.pl`](../examples/access-control-policy.pl) | Evaluates role and condition based access decisions. | [`output/access-control-policy.pl`](../examples/output/access-control-policy.pl) |
310
310
  | [`ackermann.pl`](../examples/ackermann.pl) | Computes Ackermann-style hyperoperation values. | [`output/ackermann.pl`](../examples/output/ackermann.pl) |
311
311
  | [`age.pl`](../examples/age.pl) | Checks whether people meet age thresholds. | [`output/age.pl`](../examples/output/age.pl) |
@@ -328,6 +328,7 @@ The repository includes examples for recursion, graph reachability, finite searc
328
328
  | [`cache-performance.pl`](../examples/cache-performance.pl) | Summarizes cache latency performance. | [`output/cache-performance.pl`](../examples/output/cache-performance.pl) |
329
329
  | [`canary-release.pl`](../examples/canary-release.pl) | Decides canary rollout or rollback. | [`output/canary-release.pl`](../examples/output/canary-release.pl) |
330
330
  | [`cat-koko.pl`](../examples/cat-koko.pl) | Demonstrates named existential witnesses from a Cat Koko rule pattern. | [`output/cat-koko.pl`](../examples/output/cat-koko.pl) |
331
+ | [`chart-parser.pl`](../examples/chart-parser.pl) | Parses small sentences with a memoized chart parser. | [`output/chart-parser.pl`](../examples/output/chart-parser.pl) |
331
332
  | [`clinical-trial-screening.pl`](../examples/clinical-trial-screening.pl) | Screens candidates for a trial. | [`output/clinical-trial-screening.pl`](../examples/output/clinical-trial-screening.pl) |
332
333
  | [`collatz-1000.pl`](../examples/collatz-1000.pl) | Materializes Collatz trajectories for starts 1000 down to 1. | [`output/collatz-1000.pl`](../examples/output/collatz-1000.pl) |
333
334
  | [`combinatorics-findall-sort.pl`](../examples/combinatorics-findall-sort.pl) | Collects and sorts finite combinations. | [`output/combinatorics-findall-sort.pl`](../examples/output/combinatorics-findall-sort.pl) |
@@ -337,6 +338,7 @@ The repository includes examples for recursion, graph reachability, finite searc
337
338
  | [`context-association.pl`](../examples/context-association.pl) | Associates named contexts with their contents. | [`output/context-association.pl`](../examples/output/context-association.pl) |
338
339
  | [`context-schema-audit.pl`](../examples/context-schema-audit.pl) | Audits mixed-arity context members with `holds/3`. | [`output/context-schema-audit.pl`](../examples/output/context-schema-audit.pl) |
339
340
  | [`control-system.pl`](../examples/control-system.pl) | Evaluates control-system measurements and targets. | [`output/control-system.pl`](../examples/output/control-system.pl) |
341
+ | [`critical-path-schedule.pl`](../examples/critical-path-schedule.pl) | Computes earliest starts and the critical path for a project network. | [`output/critical-path-schedule.pl`](../examples/output/critical-path-schedule.pl) |
340
342
  | [`cyclic-path.pl`](../examples/cyclic-path.pl) | Computes paths in a cyclic graph. | [`output/cyclic-path.pl`](../examples/output/cyclic-path.pl) |
341
343
  | [`d3-group.pl`](../examples/d3-group.pl) | Enumerates subgroups of the D3 group. | [`output/d3-group.pl`](../examples/output/d3-group.pl) |
342
344
  | [`dairy-energy-balance.pl`](../examples/dairy-energy-balance.pl) | Classifies dairy cow energy balance. | [`output/dairy-energy-balance.pl`](../examples/output/dairy-energy-balance.pl) |
@@ -391,6 +393,8 @@ The repository includes examples for recursion, graph reachability, finite searc
391
393
  | [`heron-theorem.pl`](../examples/heron-theorem.pl) | Computes triangle area by Heron's theorem. | [`output/heron-theorem.pl`](../examples/output/heron-theorem.pl) |
392
394
  | [`ideal-gas-law.pl`](../examples/ideal-gas-law.pl) | Applies the ideal gas law. | [`output/ideal-gas-law.pl`](../examples/output/ideal-gas-law.pl) |
393
395
  | [`illegitimate-reasoning.pl`](../examples/illegitimate-reasoning.pl) | Detects suspect reasoning patterns. | [`output/illegitimate-reasoning.pl`](../examples/output/illegitimate-reasoning.pl) |
396
+ | [`job-shop-scheduling.pl`](../examples/job-shop-scheduling.pl) | Searches a small job-shop schedule and minimizes makespan. | [`output/job-shop-scheduling.pl`](../examples/output/job-shop-scheduling.pl) |
397
+ | [`knapsack-optimization.pl`](../examples/knapsack-optimization.pl) | Optimizes a finite 0/1 knapsack pack with aggregation. | [`output/knapsack-optimization.pl`](../examples/output/knapsack-optimization.pl) |
394
398
  | [`knowledge-engineering-alignment-flow.pl`](../examples/knowledge-engineering-alignment-flow.pl) | Specializes reusable alignment rules into a target-shaped flow view. | [`output/knowledge-engineering-alignment-flow.pl`](../examples/output/knowledge-engineering-alignment-flow.pl) |
395
399
  | [`law-of-cosines.pl`](../examples/law-of-cosines.pl) | Computes a triangle side by cosine law. | [`output/law-of-cosines.pl`](../examples/output/law-of-cosines.pl) |
396
400
  | [`least-squares-regression.pl`](../examples/least-squares-regression.pl) | Fits a least-squares regression line. | [`output/least-squares-regression.pl`](../examples/output/least-squares-regression.pl) |
@@ -398,7 +402,9 @@ The repository includes examples for recursion, graph reachability, finite searc
398
402
  | [`lldm.pl`](../examples/lldm.pl) | Calculates leg-length discrepancy measurements. | [`output/lldm.pl`](../examples/output/lldm.pl) |
399
403
  | [`manufacturing-quality-control.pl`](../examples/manufacturing-quality-control.pl) | Evaluates process capability and quality. | [`output/manufacturing-quality-control.pl`](../examples/output/manufacturing-quality-control.pl) |
400
404
  | [`microgrid-dispatch.pl`](../examples/microgrid-dispatch.pl) | Plans microgrid dispatch and reserve. | [`output/microgrid-dispatch.pl`](../examples/output/microgrid-dispatch.pl) |
405
+ | [`missionaries-cannibals.pl`](../examples/missionaries-cannibals.pl) | Solves the missionaries-and-cannibals river crossing puzzle. | [`output/missionaries-cannibals.pl`](../examples/output/missionaries-cannibals.pl) |
401
406
  | [`monkey-bananas.pl`](../examples/monkey-bananas.pl) | Solves the monkey-and-bananas puzzle. | [`output/monkey-bananas.pl`](../examples/output/monkey-bananas.pl) |
407
+ | [`n-queens-8.pl`](../examples/n-queens-8.pl) | Solves the 8-queens search problem with diagonal constraints. | [`output/n-queens-8.pl`](../examples/output/n-queens-8.pl) |
402
408
  | [`network-sla.pl`](../examples/network-sla.pl) | Checks network path SLA compliance. | [`output/network-sla.pl`](../examples/output/network-sla.pl) |
403
409
  | [`newton-raphson.pl`](../examples/newton-raphson.pl) | Finds roots by Newton-Raphson iteration. | [`output/newton-raphson.pl`](../examples/output/newton-raphson.pl) |
404
410
  | [`nixon-diamond.pl`](../examples/nixon-diamond.pl) | Reports the classic Nixon-diamond conflict. | [`output/nixon-diamond.pl`](../examples/output/nixon-diamond.pl) |
@@ -418,24 +424,29 @@ The repository includes examples for recursion, graph reachability, finite searc
418
424
  | [`reusable-builtins.pl`](../examples/reusable-builtins.pl) | Tours reusable numeric, list, and string builtins. | [`output/reusable-builtins.pl`](../examples/output/reusable-builtins.pl) |
419
425
  | [`riemann-hypothesis.pl`](../examples/riemann-hypothesis.pl) | Checks a finite catalogue of non-trivial zeta zeros against the Riemann-hypothesis condition. | [`output/riemann-hypothesis.pl`](../examples/output/riemann-hypothesis.pl) |
420
426
  | [`security-incident-correlation.pl`](../examples/security-incident-correlation.pl) | Correlates security incidents across signals. | [`output/security-incident-correlation.pl`](../examples/output/security-incident-correlation.pl) |
427
+ | [`send-more-money.pl`](../examples/send-more-money.pl) | Solves the SEND + MORE = MONEY cryptarithm. | [`output/send-more-money.pl`](../examples/output/send-more-money.pl) |
421
428
  | [`service-impact.pl`](../examples/service-impact.pl) | Analyzes service impact over cyclic dependencies. | [`output/service-impact.pl`](../examples/output/service-impact.pl) |
422
429
  | [`sieve.pl`](../examples/sieve.pl) | Enumerates primes with a sieve-style program. | [`output/sieve.pl`](../examples/output/sieve.pl) |
423
430
  | [`skolem-functions.pl`](../examples/skolem-functions.pl) | Generates deterministic functional terms. | [`output/skolem-functions.pl`](../examples/output/skolem-functions.pl) |
424
431
  | [`socket-age.pl`](../examples/socket-age.pl) | Shows socket-declared age reasoning inputs and plugs. | [`output/socket-age.pl`](../examples/output/socket-age.pl) |
425
432
  | [`socket-family.pl`](../examples/socket-family.pl) | Shows socket-declared family-source inputs and ancestry rules. | [`output/socket-family.pl`](../examples/output/socket-family.pl) |
426
433
  | [`socrates.pl`](../examples/socrates.pl) | Derives that Socrates is mortal. | [`output/socrates.pl`](../examples/output/socrates.pl) |
434
+ | [`stable-marriage.pl`](../examples/stable-marriage.pl) | Finds stable matchings by excluding blocking pairs. | [`output/stable-marriage.pl`](../examples/output/stable-marriage.pl) |
427
435
  | [`statistics-summary.pl`](../examples/statistics-summary.pl) | Computes population statistics for a sample. | [`output/statistics-summary.pl`](../examples/output/statistics-summary.pl) |
436
+ | [`sudoku-4x4.pl`](../examples/sudoku-4x4.pl) | Solves a compact 4x4 Sudoku by finite constraint search. | [`output/sudoku-4x4.pl`](../examples/output/sudoku-4x4.pl) |
428
437
  | [`superdense-coding.pl`](../examples/superdense-coding.pl) | Models superdense-coding bit transmission. | [`output/superdense-coding.pl`](../examples/output/superdense-coding.pl) |
429
438
  | [`term-tools.pl`](../examples/term-tools.pl) | Inspects, builds, renders, and validates terms with reusable term/control builtins. | [`output/term-tools.pl`](../examples/output/term-tools.pl) |
430
439
  | [`trust-flow-provenance-threshold.pl`](../examples/trust-flow-provenance-threshold.pl) | Classifies message trust from provenance confidence scores. | [`output/trust-flow-provenance-threshold.pl`](../examples/output/trust-flow-provenance-threshold.pl) |
431
440
  | [`turing.pl`](../examples/turing.pl) | Simulates a binary-increment Turing machine. | [`output/turing.pl`](../examples/output/turing.pl) |
432
441
  | [`vector-similarity.pl`](../examples/vector-similarity.pl) | Computes dot product, norm, and cosine similarity. | [`output/vector-similarity.pl`](../examples/output/vector-similarity.pl) |
433
442
  | [`vulnerability-impact.pl`](../examples/vulnerability-impact.pl) | Analyzes vulnerable transitive dependencies and urgent patch impact. | [`output/vulnerability-impact.pl`](../examples/output/vulnerability-impact.pl) |
443
+ | [`weighted-interval-scheduling.pl`](../examples/weighted-interval-scheduling.pl) | Selects the best non-overlapping weighted intervals with memoized dynamic programming. | [`output/weighted-interval-scheduling.pl`](../examples/output/weighted-interval-scheduling.pl) |
434
444
  | [`witch.pl`](../examples/witch.pl) | Derives the classic “burn the witch” rule chain. | [`output/witch.pl`](../examples/output/witch.pl) |
435
445
  | [`wolf-goat-cabbage.pl`](../examples/wolf-goat-cabbage.pl) | Solves the wolf-goat-cabbage river crossing. | [`output/wolf-goat-cabbage.pl`](../examples/output/wolf-goat-cabbage.pl) |
436
446
  | [`zebra.pl`](../examples/zebra.pl) | Solves the zebra logic puzzle. | [`output/zebra.pl`](../examples/output/zebra.pl) |
437
447
 
438
448
 
449
+
439
450
  ## Golden outputs, tests, and conformance
440
451
 
441
452
  Golden answer outputs live in [`examples/output`](../examples/output). `npm run test:eyelang` covers the eyelang integration check, conformance cases, regression checks, runnable examples, and proof-output examples. A curated proof-output suite for `.pl` examples lives in [`examples/proof`](../examples/proof). Example tests pin `local_time/1` to `2026-05-30` so date-dependent examples stay deterministic. Regenerate them after an intentional output or explanation change:
@@ -0,0 +1,59 @@
1
+ % A tiny memoized chart parser for a context-free grammar.
2
+ % span/4 is the dynamic-programming chart relation: sentence, category,
3
+ % start index, and end index.
4
+ materialize(chart_parser_answer, 2).
5
+
6
+ memoize(span, 4).
7
+
8
+ sentence(command, 5).
9
+ sentence(ambiguous_pp, 8).
10
+
11
+ word(command, 0, the).
12
+ word(command, 1, robot).
13
+ word(command, 2, moves).
14
+ word(command, 3, the).
15
+ word(command, 4, box).
16
+
17
+ word(ambiguous_pp, 0, the).
18
+ word(ambiguous_pp, 1, robot).
19
+ word(ambiguous_pp, 2, sees).
20
+ word(ambiguous_pp, 3, the).
21
+ word(ambiguous_pp, 4, box).
22
+ word(ambiguous_pp, 5, with).
23
+ word(ambiguous_pp, 6, the).
24
+ word(ambiguous_pp, 7, telescope).
25
+
26
+ terminal(det, the).
27
+ terminal(noun, robot).
28
+ terminal(noun, box).
29
+ terminal(noun, telescope).
30
+ terminal(verb, moves).
31
+ terminal(verb, sees).
32
+ terminal(prep, with).
33
+
34
+ rule(s, np, vp).
35
+ rule(np, det, noun).
36
+ rule(np, np, pp).
37
+ rule(vp, verb, np).
38
+ rule(vp, vp, pp).
39
+ rule(pp, prep, np).
40
+
41
+ span(Sentence, Category, Start, End) :-
42
+ word(Sentence, Start, Token),
43
+ terminal(Category, Token),
44
+ add(Start, 1, End).
45
+ span(Sentence, Category, Start, End) :-
46
+ rule(Category, Left, Right),
47
+ span(Sentence, Left, Start, Middle),
48
+ span(Sentence, Right, Middle, End).
49
+
50
+ chart_parser_answer(parsed, Sentence) :-
51
+ sentence(Sentence, Length),
52
+ span(Sentence, s, 0, Length).
53
+ chart_parser_answer(parse_count, count(Sentence, Count)) :-
54
+ sentence(Sentence, Length),
55
+ countall(span(Sentence, s, 0, Length), Count).
56
+ chart_parser_answer(noun_phrase_count, count(Sentence, Count)) :-
57
+ sentence(Sentence, Length),
58
+ countall(span(Sentence, np, _Start, _End), Count),
59
+ gt(Length, 0).
@@ -0,0 +1,77 @@
1
+ % Critical-path scheduling for a small project network.
2
+ % earliest_start/2 and finish_time/2 are memoized because many schedule and
3
+ % critical-path queries reuse the same predecessor subproblems.
4
+ materialize(critical_path_answer, 2).
5
+
6
+ memoize(earliest_start, 2).
7
+ memoize(finish_time, 2).
8
+
9
+ task(requirements, 2).
10
+ task(architecture, 3).
11
+ task(api_design, 2).
12
+ task(database, 4).
13
+ task(backend, 6).
14
+ task(frontend, 5).
15
+ task(auth, 3).
16
+ task(integration, 4).
17
+ task(security_review, 3).
18
+ task(load_test, 2).
19
+ task(launch, 1).
20
+
21
+ depends(architecture, requirements).
22
+ depends(api_design, requirements).
23
+ depends(database, architecture).
24
+ depends(backend, api_design).
25
+ depends(backend, database).
26
+ depends(frontend, api_design).
27
+ depends(auth, architecture).
28
+ depends(integration, backend).
29
+ depends(integration, frontend).
30
+ depends(integration, auth).
31
+ depends(security_review, integration).
32
+ depends(load_test, integration).
33
+ depends(launch, security_review).
34
+ depends(launch, load_test).
35
+
36
+ earliest_start(Task, 0) :-
37
+ task(Task, _Duration),
38
+ not(depends(Task, _Pred)).
39
+ earliest_start(Task, Start) :-
40
+ depends(Task, _Pred),
41
+ aggregate_max(Finish, Pred,
42
+ (depends(Task, Pred), finish_time(Pred, Finish)),
43
+ Start, _CriticalPred).
44
+
45
+ finish_time(Task, Finish) :-
46
+ task(Task, Duration),
47
+ earliest_start(Task, Start),
48
+ add(Start, Duration, Finish).
49
+
50
+ critical_predecessor(Task, Pred) :-
51
+ depends(Task, _AnyPred),
52
+ aggregate_max(Finish, P,
53
+ (depends(Task, P), finish_time(P, Finish)),
54
+ _BestFinish, Pred).
55
+
56
+ project_finish(Finish) :-
57
+ aggregate_max(FinishTime, Task, finish_time(Task, FinishTime), Finish, _LastTask).
58
+
59
+ final_task(Task) :-
60
+ project_finish(Finish),
61
+ finish_time(Task, Finish).
62
+
63
+ critical_chain(Task, Task).
64
+ critical_chain(Task, Pred) :-
65
+ critical_predecessor(Task, Parent),
66
+ critical_chain(Parent, Pred).
67
+
68
+ critical_task(Task) :-
69
+ final_task(Final),
70
+ critical_chain(Final, Task).
71
+
72
+ critical_path_answer(project_finish, Finish) :- project_finish(Finish).
73
+ critical_path_answer(critical_task, Task) :- critical_task(Task).
74
+ critical_path_answer(schedule, task(Task, Start, Finish)) :-
75
+ task(Task, _Duration),
76
+ earliest_start(Task, Start),
77
+ finish_time(Task, Finish).
@@ -0,0 +1,44 @@
1
+ % Tiny job-shop scheduling benchmark.
2
+ % Three jobs each need one mill operation and one lathe operation; the solver
3
+ % searches start times and minimizes the makespan.
4
+ materialize(job_shop_answer, 2).
5
+
6
+ nonoverlap(_StartA, EndA, StartB, _EndB) :- le(EndA, StartB).
7
+ nonoverlap(StartA, _EndA, _StartB, EndB) :- le(EndB, StartA).
8
+
9
+ feasible_schedule(Makespan, [
10
+ op(j1_mill, J1MillStart, J1MillEnd),
11
+ op(j1_lathe, J1LatheStart, J1LatheEnd),
12
+ op(j2_lathe, J2LatheStart, J2LatheEnd),
13
+ op(j2_mill, J2MillStart, J2MillEnd),
14
+ op(j3_mill, J3MillStart, J3MillEnd),
15
+ op(j3_lathe, J3LatheStart, J3LatheEnd)
16
+ ]) :-
17
+ between(0, 6, J1MillStart), add(J1MillStart, 3, J1MillEnd),
18
+ between(0, 6, J1LatheStart), add(J1LatheStart, 2, J1LatheEnd),
19
+ le(J1MillEnd, J1LatheStart),
20
+
21
+ between(0, 6, J2LatheStart), add(J2LatheStart, 2, J2LatheEnd),
22
+ between(0, 6, J2MillStart), add(J2MillStart, 4, J2MillEnd),
23
+ le(J2LatheEnd, J2MillStart),
24
+
25
+ between(0, 6, J3MillStart), add(J3MillStart, 2, J3MillEnd),
26
+ between(0, 6, J3LatheStart), add(J3LatheStart, 3, J3LatheEnd),
27
+ le(J3MillEnd, J3LatheStart),
28
+
29
+ nonoverlap(J1MillStart, J1MillEnd, J2MillStart, J2MillEnd),
30
+ nonoverlap(J1MillStart, J1MillEnd, J3MillStart, J3MillEnd),
31
+ nonoverlap(J2MillStart, J2MillEnd, J3MillStart, J3MillEnd),
32
+ nonoverlap(J1LatheStart, J1LatheEnd, J2LatheStart, J2LatheEnd),
33
+ nonoverlap(J1LatheStart, J1LatheEnd, J3LatheStart, J3LatheEnd),
34
+ nonoverlap(J2LatheStart, J2LatheEnd, J3LatheStart, J3LatheEnd),
35
+
36
+ max(J1LatheEnd, J2MillEnd, PartialMakespan),
37
+ max(PartialMakespan, J3LatheEnd, Makespan).
38
+
39
+ best_schedule(Makespan, Schedule) :-
40
+ aggregate_min(Makespan, Schedule, feasible_schedule(Makespan, Schedule), Makespan, Schedule).
41
+
42
+ job_shop_answer(best_makespan, Makespan) :- best_schedule(Makespan, _Schedule).
43
+ job_shop_answer(best_schedule, Schedule) :- best_schedule(_Makespan, Schedule).
44
+ job_shop_answer(feasible_schedule_count, Count) :- countall(feasible_schedule(_Makespan, _Schedule), Count).
@@ -0,0 +1,40 @@
1
+ % 0/1 knapsack search with an aggregate maximum over all feasible packs.
2
+ materialize(knapsack_answer, 2).
3
+
4
+ capacity(15).
5
+ items([atlas, battery, camera, drone, emergency_radio, field_laptop, medkit, sensor]).
6
+
7
+ item(atlas, 2, 6).
8
+ item(battery, 4, 10).
9
+ item(camera, 3, 8).
10
+ item(drone, 6, 13).
11
+ item(emergency_radio, 5, 11).
12
+ item(field_laptop, 7, 16).
13
+ item(medkit, 4, 9).
14
+ item(sensor, 2, 7).
15
+
16
+ subset([], []).
17
+ subset([Item|Rest], [Item|Chosen]) :- subset(Rest, Chosen).
18
+ subset([_Item|Rest], Chosen) :- subset(Rest, Chosen).
19
+
20
+ item_weight(Item, Weight) :- item(Item, Weight, _Value).
21
+ item_value(Item, Value) :- item(Item, _Weight, Value).
22
+
23
+ total_weight(Items, Weight) :- findall(W, (member(Item, Items), item_weight(Item, W)), Weights), sum_list(Weights, Weight).
24
+ total_value(Items, Value) :- findall(V, (member(Item, Items), item_value(Item, V)), Values), sum_list(Values, Value).
25
+
26
+ feasible_pack(Pack, Weight, Value) :-
27
+ items(All),
28
+ subset(All, Pack),
29
+ total_weight(Pack, Weight),
30
+ capacity(Capacity),
31
+ le(Weight, Capacity),
32
+ total_value(Pack, Value).
33
+
34
+ best_pack(Pack, Weight, Value) :-
35
+ aggregate_max(Value, pack(Pack, Weight), feasible_pack(Pack, Weight, Value), Value, pack(Pack, Weight)).
36
+
37
+ knapsack_answer(best_pack, Pack) :- best_pack(Pack, _Weight, _Value).
38
+ knapsack_answer(total_weight, Weight) :- best_pack(_Pack, Weight, _Value).
39
+ knapsack_answer(total_value, Value) :- best_pack(_Pack, _Weight, Value).
40
+ knapsack_answer(feasible_pack_count, Count) :- countall(feasible_pack(_Pack, _Weight, _Value), Count).
@@ -0,0 +1,47 @@
1
+ % Missionaries-and-cannibals river crossing as a guarded state-space search.
2
+ materialize(missionaries_cannibals_answer, 2).
3
+
4
+ move(1, 0).
5
+ move(0, 1).
6
+ move(2, 0).
7
+ move(0, 2).
8
+ move(1, 1).
9
+
10
+ bank_safe(0, _C).
11
+ bank_safe(M, C) :- gt(M, 0), ge(M, C).
12
+
13
+ state_safe(state(MLeft, CLeft, _Boat)) :-
14
+ between(0, 3, MLeft),
15
+ between(0, 3, CLeft),
16
+ sub(3, MLeft, MRight),
17
+ sub(3, CLeft, CRight),
18
+ bank_safe(MLeft, CLeft),
19
+ bank_safe(MRight, CRight).
20
+
21
+ crossing(state(MLeft, CLeft, left), state(NextM, NextC, right), carry(MoveM, MoveC)) :-
22
+ move(MoveM, MoveC),
23
+ sub(MLeft, MoveM, NextM),
24
+ sub(CLeft, MoveC, NextC),
25
+ state_safe(state(NextM, NextC, right)).
26
+ crossing(state(MLeft, CLeft, right), state(NextM, NextC, left), carry(MoveM, MoveC)) :-
27
+ move(MoveM, MoveC),
28
+ add(MLeft, MoveM, NextM),
29
+ add(CLeft, MoveC, NextC),
30
+ state_safe(state(NextM, NextC, left)).
31
+
32
+ journey(Goal, Goal, Visited, Visited).
33
+ journey(State, Goal, Visited, Path) :-
34
+ crossing(State, Next, _Carry),
35
+ not_member(Next, Visited),
36
+ journey(Next, Goal, [Next|Visited], Path).
37
+
38
+ solution(Path) :-
39
+ journey(state(3, 3, left), state(0, 0, right), [state(3, 3, left)], ReversePath),
40
+ reverse(ReversePath, Path).
41
+
42
+ missionaries_cannibals_answer(first_solution, Path) :- once(solution(Path)).
43
+ missionaries_cannibals_answer(state_count, Count) :- countall(state_safe(state(_M, _C, _Boat)), Count).
44
+ missionaries_cannibals_answer(step_count, Steps) :-
45
+ once(solution(Path)),
46
+ length(Path, States),
47
+ sub(States, 1, Steps).
@@ -0,0 +1,31 @@
1
+ % N-queens search for the 8x8 board.
2
+ % This example enumerates all row permutations and filters diagonal attacks.
3
+ materialize(n_queens_answer, 2).
4
+
5
+ % Cache diagonal checks; the same row/distance/suffix states recur across
6
+ % many candidate permutations during the 8-queens search.
7
+ memoize(no_diagonal_attack, 3).
8
+
9
+ perm([], []).
10
+ perm(Items, [X|Rest]) :-
11
+ select(X, Items, Remaining),
12
+ perm(Remaining, Rest).
13
+
14
+ safe_rows([]).
15
+ safe_rows([Row|Rest]) :-
16
+ no_diagonal_attack(Row, 1, Rest),
17
+ safe_rows(Rest).
18
+
19
+ no_diagonal_attack(_Row, _Distance, []).
20
+ no_diagonal_attack(Row, Distance, [Other|Rest]) :-
21
+ sub(Row, Other, Delta),
22
+ abs(Delta, AbsDelta),
23
+ neq(AbsDelta, Distance),
24
+ add(Distance, 1, NextDistance),
25
+ no_diagonal_attack(Row, NextDistance, Rest).
26
+
27
+ queen_solution(Rows) :-
28
+ perm([1, 2, 3, 4, 5, 6, 7, 8], Rows),
29
+ safe_rows(Rows).
30
+
31
+ n_queens_answer(first_solution, Rows) :- once(queen_solution(Rows)).
@@ -0,0 +1,6 @@
1
+ chart_parser_answer(parsed, command).
2
+ chart_parser_answer(parsed, ambiguous_pp).
3
+ chart_parser_answer(parse_count, count(command, 1)).
4
+ chart_parser_answer(parse_count, count(ambiguous_pp, 1)).
5
+ chart_parser_answer(noun_phrase_count, count(command, 2)).
6
+ chart_parser_answer(noun_phrase_count, count(ambiguous_pp, 3)).
@@ -0,0 +1,19 @@
1
+ critical_path_answer(project_finish, 23).
2
+ critical_path_answer(critical_task, launch).
3
+ critical_path_answer(critical_task, security_review).
4
+ critical_path_answer(critical_task, integration).
5
+ critical_path_answer(critical_task, backend).
6
+ critical_path_answer(critical_task, database).
7
+ critical_path_answer(critical_task, architecture).
8
+ critical_path_answer(critical_task, requirements).
9
+ critical_path_answer(schedule, task(requirements, 0, 2)).
10
+ critical_path_answer(schedule, task(architecture, 2, 5)).
11
+ critical_path_answer(schedule, task(api_design, 2, 4)).
12
+ critical_path_answer(schedule, task(database, 5, 9)).
13
+ critical_path_answer(schedule, task(backend, 9, 15)).
14
+ critical_path_answer(schedule, task(frontend, 4, 9)).
15
+ critical_path_answer(schedule, task(auth, 5, 8)).
16
+ critical_path_answer(schedule, task(integration, 15, 19)).
17
+ critical_path_answer(schedule, task(security_review, 19, 22)).
18
+ critical_path_answer(schedule, task(load_test, 19, 21)).
19
+ critical_path_answer(schedule, task(launch, 22, 23)).
@@ -0,0 +1,3 @@
1
+ job_shop_answer(best_makespan, 9).
2
+ job_shop_answer(best_schedule, [op(j1_mill, 0, 3), op(j1_lathe, 3, 5), op(j2_lathe, 0, 2), op(j2_mill, 5, 9), op(j3_mill, 3, 5), op(j3_lathe, 5, 8)]).
3
+ job_shop_answer(feasible_schedule_count, 35).
@@ -0,0 +1,4 @@
1
+ knapsack_answer(best_pack, [atlas, battery, camera, medkit, sensor]).
2
+ knapsack_answer(total_weight, 15).
3
+ knapsack_answer(total_value, 40).
4
+ knapsack_answer(feasible_pack_count, 113).
@@ -0,0 +1,3 @@
1
+ missionaries_cannibals_answer(first_solution, [state(3, 3, left), state(3, 1, right), state(3, 2, left), state(3, 0, right), state(3, 1, left), state(1, 1, right), state(2, 2, left), state(0, 2, right), state(0, 3, left), state(0, 1, right), state(1, 1, left), state(0, 0, right)]).
2
+ missionaries_cannibals_answer(state_count, 10).
3
+ missionaries_cannibals_answer(step_count, 11).
@@ -0,0 +1 @@
1
+ n_queens_answer(first_solution, [1, 5, 8, 6, 3, 7, 2, 4]).
@@ -0,0 +1,3 @@
1
+ cryptarithm_answer(assignments, solution(9, 5, 6, 7, 1, 0, 8, 2)).
2
+ cryptarithm_answer(equation, equation(9567, 1085, 10652)).
3
+ cryptarithm_answer(solution_count, 1).
@@ -0,0 +1,2 @@
1
+ stable_marriage_answer(first_stable_matching, [pair(adam, bea), pair(brian, dana), pair(cole, amy), pair(drew, cora)]).
2
+ stable_marriage_answer(stable_matching_count, 1).
@@ -0,0 +1,2 @@
1
+ sudoku_answer(solution, [[1, 2, 3, 4], [3, 4, 1, 2], [2, 1, 4, 3], [4, 3, 2, 1]]).
2
+ sudoku_answer(solution_count, 2).
@@ -0,0 +1,5 @@
1
+ weighted_interval_answer(best_value, 13).
2
+ weighted_interval_answer(chosen_interval, interval(1, 1, 4, 5)).
3
+ weighted_interval_answer(chosen_interval, interval(4, 4, 7, 4)).
4
+ weighted_interval_answer(chosen_interval, interval(8, 8, 11, 4)).
5
+ weighted_interval_answer(candidate_count, 8).
@@ -0,0 +1,66 @@
1
+ % Cryptarithm search for SEND + MORE = MONEY.
2
+ % Column constraints prune the digit assignment search.
3
+ materialize(cryptarithm_answer, 2).
4
+
5
+ all_digits([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).
6
+
7
+ send_more_money(solution(S, E, N, D, M, O, R, Y)) :-
8
+ all_digits(Digits),
9
+ eq(M, 1),
10
+ eq(O, 0),
11
+ select(M, Digits, D0),
12
+ select(O, D0, D1),
13
+
14
+ select(D, D1, D2),
15
+ select(E, D2, D3),
16
+ add(D, E, OnesSum),
17
+ mod(OnesSum, 10, Y),
18
+ div(OnesSum, 10, Carry1),
19
+ select(Y, D3, D4),
20
+
21
+ select(N, D4, D5),
22
+ select(R, D5, D6),
23
+ add(N, R, TensPartial),
24
+ add(TensPartial, Carry1, TensSum),
25
+ mod(TensSum, 10, E),
26
+ div(TensSum, 10, Carry2),
27
+
28
+ add(E, O, HundredsPartial),
29
+ add(HundredsPartial, Carry2, HundredsSum),
30
+ mod(HundredsSum, 10, N),
31
+ div(HundredsSum, 10, Carry3),
32
+
33
+ select(S, D6, _D7),
34
+ neq(S, 0),
35
+ add(S, M, ThousandsPartial),
36
+ add(ThousandsPartial, Carry3, ThousandsSum),
37
+ mod(ThousandsSum, 10, O),
38
+ div(ThousandsSum, 10, M).
39
+
40
+ number4(A, B, C, D, Value) :-
41
+ mul(A, 1000, APart),
42
+ mul(B, 100, BPart),
43
+ mul(C, 10, CPart),
44
+ add(APart, BPart, AB),
45
+ add(AB, CPart, ABC),
46
+ add(ABC, D, Value).
47
+
48
+ number5(A, B, C, D, E, Value) :-
49
+ mul(A, 10000, APart),
50
+ mul(B, 1000, BPart),
51
+ mul(C, 100, CPart),
52
+ mul(D, 10, DPart),
53
+ add(APart, BPart, AB),
54
+ add(AB, CPart, ABC),
55
+ add(ABC, DPart, ABCD),
56
+ add(ABCD, E, Value).
57
+
58
+ cryptarithm_answer(assignments, solution(S, E, N, D, M, O, R, Y)) :-
59
+ send_more_money(solution(S, E, N, D, M, O, R, Y)).
60
+ cryptarithm_answer(equation, equation(Send, More, Money)) :-
61
+ send_more_money(solution(S, E, N, D, M, O, R, Y)),
62
+ number4(S, E, N, D, Send),
63
+ number4(M, O, R, E, More),
64
+ number5(M, O, N, E, Y, Money).
65
+ cryptarithm_answer(solution_count, Count) :-
66
+ countall(send_more_money(_Solution), Count).
@@ -0,0 +1,86 @@
1
+ % Stable-marriage search with blocking-pair detection.
2
+ materialize(stable_marriage_answer, 2).
3
+
4
+ man(adam).
5
+ man(brian).
6
+ man(cole).
7
+ man(drew).
8
+
9
+ woman(amy).
10
+ woman(bea).
11
+ woman(cora).
12
+ woman(dana).
13
+
14
+ rank_man(adam, bea, 1).
15
+ rank_man(adam, amy, 2).
16
+ rank_man(adam, dana, 3).
17
+ rank_man(adam, cora, 4).
18
+ rank_man(brian, amy, 1).
19
+ rank_man(brian, cora, 2).
20
+ rank_man(brian, bea, 3).
21
+ rank_man(brian, dana, 4).
22
+ rank_man(cole, amy, 1).
23
+ rank_man(cole, bea, 2).
24
+ rank_man(cole, dana, 3).
25
+ rank_man(cole, cora, 4).
26
+ rank_man(drew, cora, 1).
27
+ rank_man(drew, dana, 2).
28
+ rank_man(drew, bea, 3).
29
+ rank_man(drew, amy, 4).
30
+
31
+ rank_woman(amy, cole, 1).
32
+ rank_woman(amy, adam, 2).
33
+ rank_woman(amy, brian, 3).
34
+ rank_woman(amy, drew, 4).
35
+ rank_woman(bea, adam, 1).
36
+ rank_woman(bea, cole, 2).
37
+ rank_woman(bea, drew, 3).
38
+ rank_woman(bea, brian, 4).
39
+ rank_woman(cora, drew, 1).
40
+ rank_woman(cora, brian, 2).
41
+ rank_woman(cora, adam, 3).
42
+ rank_woman(cora, cole, 4).
43
+ rank_woman(dana, brian, 1).
44
+ rank_woman(dana, drew, 2).
45
+ rank_woman(dana, cole, 3).
46
+ rank_woman(dana, adam, 4).
47
+
48
+ perm([], []).
49
+ perm(Items, [X|Rest]) :-
50
+ select(X, Items, Remaining),
51
+ perm(Remaining, Rest).
52
+
53
+ matching([
54
+ pair(adam, W1),
55
+ pair(brian, W2),
56
+ pair(cole, W3),
57
+ pair(drew, W4)
58
+ ]) :-
59
+ perm([amy, bea, cora, dana], [W1, W2, W3, W4]).
60
+
61
+ assigned(Matching, Man, Woman) :- member(pair(Man, Woman), Matching).
62
+
63
+ prefers_man(Man, Candidate, Current) :-
64
+ rank_man(Man, Candidate, CandidateRank),
65
+ rank_man(Man, Current, CurrentRank),
66
+ lt(CandidateRank, CurrentRank).
67
+
68
+ prefers_woman(Woman, Candidate, Current) :-
69
+ rank_woman(Woman, Candidate, CandidateRank),
70
+ rank_woman(Woman, Current, CurrentRank),
71
+ lt(CandidateRank, CurrentRank).
72
+
73
+ blocking_pair(Matching, Man, Woman) :-
74
+ assigned(Matching, Man, CurrentWoman),
75
+ woman(Woman),
76
+ neq(Woman, CurrentWoman),
77
+ prefers_man(Man, Woman, CurrentWoman),
78
+ assigned(Matching, CurrentMan, Woman),
79
+ prefers_woman(Woman, Man, CurrentMan).
80
+
81
+ stable_matching(Matching) :-
82
+ matching(Matching),
83
+ not(blocking_pair(Matching, _Man, _Woman)).
84
+
85
+ stable_marriage_answer(first_stable_matching, Matching) :- once(stable_matching(Matching)).
86
+ stable_marriage_answer(stable_matching_count, Count) :- countall(stable_matching(_Matching), Count).
@@ -0,0 +1,48 @@
1
+ % A compact 4x4 Sudoku search with row permutations and column/box constraints.
2
+ materialize(sudoku_answer, 2).
3
+
4
+ perm([], []).
5
+ perm(Items, [X|Rest]) :-
6
+ select(X, Items, Remaining),
7
+ perm(Remaining, Rest).
8
+
9
+ distinct([]).
10
+ distinct([X|Xs]) :-
11
+ not_member(X, Xs),
12
+ distinct(Xs).
13
+
14
+ row1([1, B, C, 4]) :- perm([1, 2, 3, 4], [1, B, C, 4]).
15
+ row2([A, 4, 1, D]) :- perm([1, 2, 3, 4], [A, 4, 1, D]).
16
+ row3([B, 1, 4, C]) :- perm([1, 2, 3, 4], [B, 1, 4, C]).
17
+ row4([4, C, B, 1]) :- perm([1, 2, 3, 4], [4, C, B, 1]).
18
+
19
+ column([R1, R2, R3, R4], Index, [A, B, C, D]) :-
20
+ nth0(Index, R1, A),
21
+ nth0(Index, R2, B),
22
+ nth0(Index, R3, C),
23
+ nth0(Index, R4, D).
24
+
25
+ boxes([R1, R2, R3, R4], [Box1, Box2, Box3, Box4]) :-
26
+ nth0(0, R1, A), nth0(1, R1, B), nth0(0, R2, C), nth0(1, R2, D),
27
+ eq(Box1, [A, B, C, D]),
28
+ nth0(2, R1, E), nth0(3, R1, F), nth0(2, R2, G), nth0(3, R2, H),
29
+ eq(Box2, [E, F, G, H]),
30
+ nth0(0, R3, I), nth0(1, R3, J), nth0(0, R4, K), nth0(1, R4, L),
31
+ eq(Box3, [I, J, K, L]),
32
+ nth0(2, R3, M), nth0(3, R3, N), nth0(2, R4, O), nth0(3, R4, P),
33
+ eq(Box4, [M, N, O, P]).
34
+
35
+ sudoku_solution([R1, R2, R3, R4]) :-
36
+ row1(R1),
37
+ row2(R2),
38
+ row3(R3),
39
+ row4(R4),
40
+ column([R1, R2, R3, R4], 0, C0), distinct(C0),
41
+ column([R1, R2, R3, R4], 1, C1), distinct(C1),
42
+ column([R1, R2, R3, R4], 2, C2), distinct(C2),
43
+ column([R1, R2, R3, R4], 3, C3), distinct(C3),
44
+ boxes([R1, R2, R3, R4], [B1, B2, B3, B4]),
45
+ distinct(B1), distinct(B2), distinct(B3), distinct(B4).
46
+
47
+ sudoku_answer(solution, Grid) :- once(sudoku_solution(Grid)).
48
+ sudoku_answer(solution_count, Count) :- countall(sudoku_solution(_Grid), Count).
@@ -0,0 +1,76 @@
1
+ % Weighted interval scheduling via memoized dynamic programming.
2
+ % Intervals are already ordered by finish time; best_from/2 chooses take/skip.
3
+ materialize(weighted_interval_answer, 2).
4
+
5
+ memoize(best_from, 2).
6
+
7
+ last_interval(8).
8
+ sentinel(9).
9
+
10
+ interval(1, 1, 4, 5).
11
+ interval(2, 3, 5, 1).
12
+ interval(3, 0, 6, 8).
13
+ interval(4, 4, 7, 4).
14
+ interval(5, 3, 9, 6).
15
+ interval(6, 5, 9, 3).
16
+ interval(7, 6, 10, 2).
17
+ interval(8, 8, 11, 4).
18
+
19
+ next_compatible(I, J) :-
20
+ interval(I, _Start, Finish, _Value),
21
+ aggregate_min(K, K,
22
+ (interval(K, StartK, _FinishK, _ValueK), gt(K, I), ge(StartK, Finish)),
23
+ J, J).
24
+ next_compatible(I, 9) :-
25
+ interval(I, _Start, Finish, _Value),
26
+ not((interval(K, StartK, _FinishK, _ValueK), gt(K, I), ge(StartK, Finish))).
27
+
28
+ best_from(9, 0).
29
+ best_from(I, Best) :-
30
+ last_interval(Last),
31
+ le(I, Last),
32
+ add(I, 1, Next),
33
+ best_from(Next, Skip),
34
+ next_compatible(I, Compatible),
35
+ best_from(Compatible, Tail),
36
+ interval(I, _Start, _Finish, Value),
37
+ add(Value, Tail, Take),
38
+ max(Take, Skip, Best).
39
+
40
+ chosen_from(I, I) :-
41
+ best_from(I, Best),
42
+ add(I, 1, Next),
43
+ best_from(Next, Skip),
44
+ next_compatible(I, Compatible),
45
+ best_from(Compatible, Tail),
46
+ interval(I, _Start, _Finish, Value),
47
+ add(Value, Tail, Take),
48
+ eq(Best, Take),
49
+ ge(Take, Skip).
50
+ chosen_from(I, Chosen) :-
51
+ best_from(I, Best),
52
+ add(I, 1, Next),
53
+ best_from(Next, Skip),
54
+ next_compatible(I, Compatible),
55
+ best_from(Compatible, Tail),
56
+ interval(I, _Start, _Finish, Value),
57
+ add(Value, Tail, Take),
58
+ eq(Best, Take),
59
+ ge(Take, Skip),
60
+ chosen_from(Compatible, Chosen).
61
+ chosen_from(I, Chosen) :-
62
+ best_from(I, Best),
63
+ add(I, 1, Next),
64
+ best_from(Next, Skip),
65
+ next_compatible(I, Compatible),
66
+ best_from(Compatible, Tail),
67
+ interval(I, _Start, _Finish, Value),
68
+ add(Value, Tail, Take),
69
+ gt(Skip, Take),
70
+ chosen_from(Next, Chosen).
71
+
72
+ weighted_interval_answer(best_value, Best) :- best_from(1, Best).
73
+ weighted_interval_answer(chosen_interval, interval(I, Start, Finish, Value)) :-
74
+ chosen_from(1, I),
75
+ interval(I, Start, Finish, Value).
76
+ weighted_interval_answer(candidate_count, Count) :- countall(interval(_I, _Start, _Finish, _Value), Count).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyelang",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "description": "A small Prolog-syntax-subset logic programming language for rules, goals, answers, and proofs.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/playground.html CHANGED
@@ -434,135 +434,145 @@
434
434
 
435
435
  <script type="module">
436
436
  const EXAMPLES = [
437
- "access-control-policy",
438
- "ackermann",
439
- "age",
440
- "aliases-and-namespaces",
441
- "alignment-demo",
442
- "allen-interval-calculus",
443
- "ancestor",
444
- "animal",
445
- "annotation",
446
- "auroracare",
447
- "backward",
448
- "basic-monadic",
449
- "bayes-diagnosis",
450
- "bayes-therapy",
451
- "beam-deflection",
452
- "blocks-world-planning",
453
- "bmi",
454
- "braking-safety-worlds",
455
- "buck-converter-design",
456
- "cache-performance",
457
- "canary-release",
458
- "cat-koko",
459
- "clinical-trial-screening",
460
- "collatz-1000",
461
- "combinatorics-findall-sort",
462
- "competitive-enzyme-kinetics",
463
- "complex",
464
- "composition-of-injective-functions-is-injective",
465
- "context-association",
466
- "context-schema-audit",
467
- "control-system",
468
- "cyclic-path",
469
- "d3-group",
470
- "dairy-energy-balance",
471
- "data-negotiation",
472
- "deep-taxonomy-10",
473
- "deep-taxonomy-100",
474
- "deep-taxonomy-1000",
475
- "deep-taxonomy-10000",
476
- "deep-taxonomy-100000",
477
- "delfour",
478
- "deontic-logic",
479
- "derived-backward-rule",
480
- "derived-rule",
481
- "diamond-property",
482
- "dijkstra-findall-sort",
483
- "dijkstra-risk-path",
484
- "dijkstra",
485
- "dining-philosophers",
486
- "dog",
487
- "dpv-odrl-purpose-mapping",
488
- "drone-corridor-planner",
489
- "easter-computus",
490
- "electrical-rc-filter",
491
- "epidemic-policy",
492
- "equivalence-classes-overlap-implies-same-class",
493
- "eulerian-path",
494
- "ev-range-worlds",
495
- "existential-rule",
496
- "exoplanet-validation-worlds",
497
- "expression-eval",
498
- "family-cousins",
499
- "fastpow",
500
- "fft8-numeric",
501
- "fibonacci",
502
- "field-nitrogen-balance",
503
- "flandor",
504
- "floating-point",
505
- "four-color-map",
506
- "fundamental-theorem-arithmetic",
507
- "gd-step-certified",
508
- "gdpr-compliance",
509
- "good-cobbler",
510
- "gps",
511
- "graph-reachability",
512
- "gray-code-counter",
513
- "greatest-lower-bound-uniqueness",
514
- "group-inverse-uniqueness",
515
- "hamiltonian-path",
516
- "hamming-code",
517
- "hanoi",
518
- "heat-loss",
519
- "heron-theorem",
520
- "ideal-gas-law",
521
- "illegitimate-reasoning",
522
- "knowledge-engineering-alignment-flow",
523
- "law-of-cosines",
524
- "least-squares-regression",
525
- "list-collection",
526
- "lldm",
527
- "manufacturing-quality-control",
528
- "microgrid-dispatch",
529
- "monkey-bananas",
530
- "network-sla",
531
- "newton-raphson",
532
- "nixon-diamond",
533
- "observability-log-correlation",
534
- "odrl-dpv-fpv-trust-flow",
535
- "odrl-dpv-healthcare-risk-ranked",
536
- "odrl-dpv-risk-ranked",
537
- "orbital-transfer-design",
538
- "path-discovery",
539
- "peano-arithmetic",
540
- "peasant",
541
- "pendulum-period",
542
- "polynomial",
543
- "proof-contrapositive",
544
- "quadratic-formula",
545
- "radioactive-decay",
546
- "reusable-builtins",
547
- "riemann-hypothesis",
548
- "security-incident-correlation",
549
- "service-impact",
550
- "sieve",
551
- "skolem-functions",
552
- "socket-age",
553
- "socket-family",
554
- "socrates",
555
- "statistics-summary",
556
- "superdense-coding",
557
- "term-tools",
558
- "trust-flow-provenance-threshold",
559
- "turing",
560
- "vector-similarity",
561
- "vulnerability-impact",
562
- "witch",
563
- "wolf-goat-cabbage",
564
- "zebra"
565
- ];
437
+ "access-control-policy",
438
+ "ackermann",
439
+ "age",
440
+ "aliases-and-namespaces",
441
+ "alignment-demo",
442
+ "allen-interval-calculus",
443
+ "ancestor",
444
+ "animal",
445
+ "annotation",
446
+ "auroracare",
447
+ "backward",
448
+ "basic-monadic",
449
+ "bayes-diagnosis",
450
+ "bayes-therapy",
451
+ "beam-deflection",
452
+ "blocks-world-planning",
453
+ "bmi",
454
+ "braking-safety-worlds",
455
+ "buck-converter-design",
456
+ "cache-performance",
457
+ "canary-release",
458
+ "cat-koko",
459
+ "chart-parser",
460
+ "clinical-trial-screening",
461
+ "collatz-1000",
462
+ "combinatorics-findall-sort",
463
+ "competitive-enzyme-kinetics",
464
+ "complex",
465
+ "composition-of-injective-functions-is-injective",
466
+ "context-association",
467
+ "context-schema-audit",
468
+ "control-system",
469
+ "critical-path-schedule",
470
+ "cyclic-path",
471
+ "d3-group",
472
+ "dairy-energy-balance",
473
+ "data-negotiation",
474
+ "deep-taxonomy-10",
475
+ "deep-taxonomy-100",
476
+ "deep-taxonomy-1000",
477
+ "deep-taxonomy-10000",
478
+ "deep-taxonomy-100000",
479
+ "delfour",
480
+ "deontic-logic",
481
+ "derived-backward-rule",
482
+ "derived-rule",
483
+ "diamond-property",
484
+ "dijkstra",
485
+ "dijkstra-findall-sort",
486
+ "dijkstra-risk-path",
487
+ "dining-philosophers",
488
+ "dog",
489
+ "dpv-odrl-purpose-mapping",
490
+ "drone-corridor-planner",
491
+ "easter-computus",
492
+ "electrical-rc-filter",
493
+ "epidemic-policy",
494
+ "equivalence-classes-overlap-implies-same-class",
495
+ "eulerian-path",
496
+ "ev-range-worlds",
497
+ "existential-rule",
498
+ "exoplanet-validation-worlds",
499
+ "expression-eval",
500
+ "family-cousins",
501
+ "fastpow",
502
+ "fft8-numeric",
503
+ "fibonacci",
504
+ "field-nitrogen-balance",
505
+ "flandor",
506
+ "floating-point",
507
+ "four-color-map",
508
+ "fundamental-theorem-arithmetic",
509
+ "gd-step-certified",
510
+ "gdpr-compliance",
511
+ "good-cobbler",
512
+ "gps",
513
+ "graph-reachability",
514
+ "gray-code-counter",
515
+ "greatest-lower-bound-uniqueness",
516
+ "group-inverse-uniqueness",
517
+ "hamiltonian-path",
518
+ "hamming-code",
519
+ "hanoi",
520
+ "heat-loss",
521
+ "heron-theorem",
522
+ "ideal-gas-law",
523
+ "illegitimate-reasoning",
524
+ "job-shop-scheduling",
525
+ "knapsack-optimization",
526
+ "knowledge-engineering-alignment-flow",
527
+ "law-of-cosines",
528
+ "least-squares-regression",
529
+ "list-collection",
530
+ "lldm",
531
+ "manufacturing-quality-control",
532
+ "microgrid-dispatch",
533
+ "missionaries-cannibals",
534
+ "monkey-bananas",
535
+ "n-queens-8",
536
+ "network-sla",
537
+ "newton-raphson",
538
+ "nixon-diamond",
539
+ "observability-log-correlation",
540
+ "odrl-dpv-fpv-trust-flow",
541
+ "odrl-dpv-healthcare-risk-ranked",
542
+ "odrl-dpv-risk-ranked",
543
+ "orbital-transfer-design",
544
+ "path-discovery",
545
+ "peano-arithmetic",
546
+ "peasant",
547
+ "pendulum-period",
548
+ "polynomial",
549
+ "proof-contrapositive",
550
+ "quadratic-formula",
551
+ "radioactive-decay",
552
+ "reusable-builtins",
553
+ "riemann-hypothesis",
554
+ "security-incident-correlation",
555
+ "send-more-money",
556
+ "service-impact",
557
+ "sieve",
558
+ "skolem-functions",
559
+ "socket-age",
560
+ "socket-family",
561
+ "socrates",
562
+ "stable-marriage",
563
+ "statistics-summary",
564
+ "sudoku-4x4",
565
+ "superdense-coding",
566
+ "term-tools",
567
+ "trust-flow-provenance-threshold",
568
+ "turing",
569
+ "vector-similarity",
570
+ "vulnerability-impact",
571
+ "weighted-interval-scheduling",
572
+ "witch",
573
+ "wolf-goat-cabbage",
574
+ "zebra"
575
+ ];
566
576
  const FALLBACK_SOURCE = `materialize(answer, 1).
567
577
  answer(ok) :- eq(ok, ok).
568
578
  `;
@@ -1015,11 +1025,13 @@ answer(ok) :- eq(ok, ok).
1015
1025
 
1016
1026
  async function copyShareLink() {
1017
1027
  const link = buildShareLink();
1018
- if (link == null) {
1019
- setStatus('This program is too large for a reliable URL. Use “Create Gist share” instead.', true);
1028
+ if (link != null) {
1029
+ await copyText(link, 'Share link copied.');
1020
1030
  return;
1021
1031
  }
1022
- await copyText(link, 'Share link copied.');
1032
+ await createGistShare({
1033
+ reason: 'This program is too large for an inline URL, so Copy share link will create a Gist share instead.',
1034
+ });
1023
1035
  }
1024
1036
 
1025
1037
  function buildShareLink() {
@@ -1043,12 +1055,16 @@ answer(ok) :- eq(ok, ok).
1043
1055
  return `${basePlaygroundUrl()}#${params.toString()}`;
1044
1056
  }
1045
1057
 
1046
- async function createGistShare() {
1058
+ async function createGistShare(options = {}) {
1047
1059
  const stateText = JSON.stringify(currentShareState(), null, 2);
1048
- const token = prompt('Optional GitHub token with gist scope. It is only sent to api.github.com and is not stored. Leave blank to copy Gist-ready state instead.');
1049
- if (token === null) return;
1060
+ if (options.reason) setStatus(options.reason);
1061
+ const token = prompt(`${options.reason ? `${options.reason}\n\n` : ''}Optional GitHub token with gist scope. It is only sent to api.github.com and is not stored. Leave blank to copy Gist-ready state and open gist.github.com.`);
1062
+ if (token === null) {
1063
+ setStatus('Gist share cancelled.');
1064
+ return;
1065
+ }
1050
1066
  if (!token.trim()) {
1051
- await copyText(stateText, `Gist-ready state copied. Create a Gist file named ${GIST_STATE_FILENAME}, paste it, then share its raw URL with #state-url=...`);
1067
+ await copyText(stateText, `Gist-ready state copied. Create a Gist file named ${GIST_STATE_FILENAME}, paste it, then copy its raw URL into a playground #state-url link.`);
1052
1068
  window.open('https://gist.github.com/', '_blank', 'noopener');
1053
1069
  return;
1054
1070
  }
@@ -524,6 +524,36 @@ function whiteBoxCases() {
524
524
  assertEqual(termToString(candidates.primary[0].head, new Env(), true), 'edge(a, b)', 'primary head');
525
525
  },
526
526
  },
527
+ {
528
+ name: 'challenging examples keep dynamic-programming predicates memoized',
529
+ run: () => {
530
+ const checks = [
531
+ ['chart-parser.pl', 'span', 4, true],
532
+ ['critical-path-schedule.pl', 'earliest_start', 2, false],
533
+ ['critical-path-schedule.pl', 'finish_time', 2, false],
534
+ ['weighted-interval-scheduling.pl', 'best_from', 2, true],
535
+ ];
536
+ for (const [filename, name, arity, recursive] of checks) {
537
+ const text = fs.readFileSync(path.join(packageRoot, 'examples', filename), 'utf8');
538
+ const program = Program.parseSources([{ text, filename }]);
539
+ const group = program.findGroup(name, arity);
540
+ assertEqual(Boolean(group), true, `${filename} ${name}/${arity} group exists`);
541
+ assertEqual(group.memoized, true, `${filename} ${name}/${arity} memoized`);
542
+ assertEqual(group.recursive, recursive, `${filename} ${name}/${arity} recursive`);
543
+ }
544
+ },
545
+ },
546
+ {
547
+ name: 'n-queens example keeps diagonal checks memoized',
548
+ run: () => {
549
+ const text = fs.readFileSync(path.join(packageRoot, 'examples', 'n-queens-8.pl'), 'utf8');
550
+ const program = Program.parseSources([{ text, filename: 'n-queens-8.pl' }]);
551
+ const group = program.findGroup('no_diagonal_attack', 3);
552
+ assertEqual(Boolean(group), true, 'no_diagonal_attack/3 group exists');
553
+ assertEqual(group.memoized, true, 'no_diagonal_attack/3 memoized');
554
+ assertEqual(group.recursive, true, 'no_diagonal_attack/3 recursive');
555
+ },
556
+ },
527
557
  {
528
558
  name: 'collatz example keeps recursive trajectory predicate memoized',
529
559
  run: () => {
@@ -684,6 +714,9 @@ function playgroundStaticIssues() {
684
714
  if (!html.includes('id="create-gist"') || !html.includes('createGistShare') || !html.includes('GIST_STATE_FILENAME') || !html.includes("fetch('https://api.github.com/gists'")) {
685
715
  issues.push('playground must support Gist-backed sharing for large programs');
686
716
  }
717
+ if (!html.includes('await createGistShare({') || html.includes('Use “Create Gist share” instead')) {
718
+ issues.push('playground Copy share link must automatically fall back to Gist sharing for large programs');
719
+ }
687
720
  if (!html.includes("params.has('state-url')") || !html.includes('#state-url=')) {
688
721
  issues.push('playground must restore state from raw Gist state URLs');
689
722
  }