eyelang 1.7.13 → 1.7.15
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 +10 -0
- package/examples/abstract-interpretation.eye +50 -0
- package/examples/cdcl-sat-solver.eye +65 -0
- package/examples/equality-saturation.eye +84 -0
- package/examples/knuth-bendix-completion.eye +55 -0
- package/examples/output/abstract-interpretation.eye +16 -0
- package/examples/output/cdcl-sat-solver.eye +7 -0
- package/examples/output/equality-saturation.eye +5 -0
- package/examples/output/knuth-bendix-completion.eye +7 -0
- package/examples/output/partial-evaluator.eye +4 -0
- package/examples/output/pointer-analysis.eye +8 -0
- package/examples/output/register-allocation.eye +8 -0
- package/examples/output/sat-solver-dpll.eye +11 -0
- package/examples/output/truth-maintenance-system.eye +25 -0
- package/examples/output/type-inference.eye +8 -0
- package/examples/partial-evaluator.eye +74 -0
- package/examples/pointer-analysis.eye +50 -0
- package/examples/register-allocation.eye +77 -0
- package/examples/sat-solver-dpll.eye +88 -0
- package/examples/truth-maintenance-system.eye +62 -0
- package/examples/type-inference.eye +58 -0
- package/package.json +1 -1
- package/playground.html +10 -0
package/docs/guide.md
CHANGED
|
@@ -310,6 +310,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
310
310
|
|
|
311
311
|
| Example | Description | Golden output |
|
|
312
312
|
| --- | --- | --- |
|
|
313
|
+
| [`abstract-interpretation.eye`](../examples/abstract-interpretation.eye) | Performs a sign-domain abstract interpretation and reports a possible divide-by-zero warning. | [`output/abstract-interpretation.eye`](../examples/output/abstract-interpretation.eye) |
|
|
313
314
|
| [`access-control-policy.eye`](../examples/access-control-policy.eye) | Evaluates role and condition based access decisions. | [`output/access-control-policy.eye`](../examples/output/access-control-policy.eye) |
|
|
314
315
|
| [`ackermann.eye`](../examples/ackermann.eye) | Computes Ackermann-style hyperoperation values. | [`output/ackermann.eye`](../examples/output/ackermann.eye) |
|
|
315
316
|
| [`age.eye`](../examples/age.eye) | Checks whether people meet age thresholds. | [`output/age.eye`](../examples/output/age.eye) |
|
|
@@ -334,6 +335,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
334
335
|
| [`canary-release.eye`](../examples/canary-release.eye) | Decides canary rollout or rollback. | [`output/canary-release.eye`](../examples/output/canary-release.eye) |
|
|
335
336
|
| [`cat-koko.eye`](../examples/cat-koko.eye) | Demonstrates named existential witnesses from a Cat Koko rule pattern. | [`output/cat-koko.eye`](../examples/output/cat-koko.eye) |
|
|
336
337
|
| [`catalan-convolution.eye`](../examples/catalan-convolution.eye) | Computes Catalan numbers by tabled convolution. | [`output/catalan-convolution.eye`](../examples/output/catalan-convolution.eye) |
|
|
338
|
+
| [`cdcl-sat-solver.eye`](../examples/cdcl-sat-solver.eye) | Simulates one CDCL conflict-analysis step with a learned clause and backjumped model. | [`output/cdcl-sat-solver.eye`](../examples/output/cdcl-sat-solver.eye) |
|
|
337
339
|
| [`chart-parser.eye`](../examples/chart-parser.eye) | Parses small sentences with a tabled chart parser. | [`output/chart-parser.eye`](../examples/output/chart-parser.eye) |
|
|
338
340
|
| [`clinical-trial-screening.eye`](../examples/clinical-trial-screening.eye) | Screens candidates for a trial. | [`output/clinical-trial-screening.eye`](../examples/output/clinical-trial-screening.eye) |
|
|
339
341
|
| [`collatz-1000.eye`](../examples/collatz-1000.eye) | Materializes Collatz trajectories for starts 1000 down to 1. | [`output/collatz-1000.eye`](../examples/output/collatz-1000.eye) |
|
|
@@ -369,6 +371,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
369
371
|
| [`drone-corridor-planner.eye`](../examples/drone-corridor-planner.eye) | Plans bounded drone corridor routes. | [`output/drone-corridor-planner.eye`](../examples/output/drone-corridor-planner.eye) |
|
|
370
372
|
| [`easter-computus.eye`](../examples/easter-computus.eye) | Computes Gregorian Easter dates. | [`output/easter-computus.eye`](../examples/output/easter-computus.eye) |
|
|
371
373
|
| [`electrical-rc-filter.eye`](../examples/electrical-rc-filter.eye) | Sizes an RC low-pass filter. | [`output/electrical-rc-filter.eye`](../examples/output/electrical-rc-filter.eye) |
|
|
374
|
+
| [`equality-saturation.eye`](../examples/equality-saturation.eye) | Performs bounded equality saturation and extracts the cheapest equivalent expression. | [`output/equality-saturation.eye`](../examples/output/equality-saturation.eye) |
|
|
372
375
|
| [`epidemic-policy.eye`](../examples/epidemic-policy.eye) | Chooses policies from risk and social cost. | [`output/epidemic-policy.eye`](../examples/output/epidemic-policy.eye) |
|
|
373
376
|
| [`equivalence-classes-overlap-implies-same-class.eye`](../examples/equivalence-classes-overlap-implies-same-class.eye) | Packages the shared-member proof pattern for equivalence classes. | [`output/equivalence-classes-overlap-implies-same-class.eye`](../examples/output/equivalence-classes-overlap-implies-same-class.eye) |
|
|
374
377
|
| [`eulerian-path.eye`](../examples/eulerian-path.eye) | Finds an Eulerian path using each edge once. | [`output/eulerian-path.eye`](../examples/output/eulerian-path.eye) |
|
|
@@ -406,6 +409,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
406
409
|
| [`intuitionistic-logic-kripke.eye`](../examples/intuitionistic-logic-kripke.eye) | Emulates intuitionistic Kripke forcing and constructive implication. | [`output/intuitionistic-logic-kripke.eye`](../examples/output/intuitionistic-logic-kripke.eye) |
|
|
407
410
|
| [`job-shop-scheduling.eye`](../examples/job-shop-scheduling.eye) | Searches a small job-shop schedule and minimizes makespan. | [`output/job-shop-scheduling.eye`](../examples/output/job-shop-scheduling.eye) |
|
|
408
411
|
| [`knapsack-optimization.eye`](../examples/knapsack-optimization.eye) | Optimizes a finite 0/1 knapsack pack with aggregation. | [`output/knapsack-optimization.eye`](../examples/output/knapsack-optimization.eye) |
|
|
412
|
+
| [`knuth-bendix-completion.eye`](../examples/knuth-bendix-completion.eye) | Checks bounded Knuth-Bendix-style critical pairs for joinability. | [`output/knuth-bendix-completion.eye`](../examples/output/knuth-bendix-completion.eye) |
|
|
409
413
|
| [`knowledge-engineering-alignment-flow.eye`](../examples/knowledge-engineering-alignment-flow.eye) | Specializes reusable alignment rules into a target-shaped flow view. | [`output/knowledge-engineering-alignment-flow.eye`](../examples/output/knowledge-engineering-alignment-flow.eye) |
|
|
410
414
|
| [`language.eye`](../examples/language.eye) | Shows the modern Eyelang surface syntax in one compact recursive graph example. | [`output/language.eye`](../examples/output/language.eye) |
|
|
411
415
|
| [`law-of-cosines.eye`](../examples/law-of-cosines.eye) | Computes a triangle side by cosine law. | [`output/law-of-cosines.eye`](../examples/output/law-of-cosines.eye) |
|
|
@@ -433,19 +437,23 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
433
437
|
| [`odrl-dpv-risk-ranked.eye`](../examples/odrl-dpv-risk-ranked.eye) | Ranks data-policy risks and mitigations. | [`output/odrl-dpv-risk-ranked.eye`](../examples/output/odrl-dpv-risk-ranked.eye) |
|
|
434
438
|
| [`orbital-transfer-design.eye`](../examples/orbital-transfer-design.eye) | Designs a Hohmann orbital transfer. | [`output/orbital-transfer-design.eye`](../examples/output/orbital-transfer-design.eye) |
|
|
435
439
|
| [`path-discovery.eye`](../examples/path-discovery.eye) | Discovers bounded air-route paths. | [`output/path-discovery.eye`](../examples/output/path-discovery.eye) |
|
|
440
|
+
| [`partial-evaluator.eye`](../examples/partial-evaluator.eye) | Specializes tiny expression programs by folding static inputs into residual code. | [`output/partial-evaluator.eye`](../examples/output/partial-evaluator.eye) |
|
|
436
441
|
| [`peano-arithmetic.eye`](../examples/peano-arithmetic.eye) | Computes Peano addition, multiplication, and factorial. | [`output/peano-arithmetic.eye`](../examples/output/peano-arithmetic.eye) |
|
|
437
442
|
| [`peano-calculus.eye`](../examples/peano-calculus.eye) | Computes Peano addition, multiplication, and factorial. | [`output/peano-calculus.eye`](../examples/output/peano-calculus.eye) |
|
|
438
443
|
| [`peasant.eye`](../examples/peasant.eye) | Performs peasant multiplication and exponentiation. | [`output/peasant.eye`](../examples/output/peasant.eye) |
|
|
439
444
|
| [`pell-equation.eye`](../examples/pell-equation.eye) | Generates Pell-equation solutions by recurrence. | [`output/pell-equation.eye`](../examples/output/pell-equation.eye) |
|
|
440
445
|
| [`pendulum-period.eye`](../examples/pendulum-period.eye) | Computes simple pendulum periods. | [`output/pendulum-period.eye`](../examples/output/pendulum-period.eye) |
|
|
446
|
+
| [`pointer-analysis.eye`](../examples/pointer-analysis.eye) | Computes Andersen-style inclusion-based points-to facts over address, assign, store, and load constraints. | [`output/pointer-analysis.eye`](../examples/output/pointer-analysis.eye) |
|
|
441
447
|
| [`polynomial.eye`](../examples/polynomial.eye) | Finds complex integer polynomial roots. | [`output/polynomial.eye`](../examples/output/polynomial.eye) |
|
|
442
448
|
| [`prime-range.eye`](../examples/prime-range.eye) | Finds primes in a finite range and computes a totient value. | [`output/prime-range.eye`](../examples/output/prime-range.eye) |
|
|
443
449
|
| [`proof-contrapositive.eye`](../examples/proof-contrapositive.eye) | Models proof by contrapositive. | [`output/proof-contrapositive.eye`](../examples/output/proof-contrapositive.eye) |
|
|
444
450
|
| [`quadratic-formula.eye`](../examples/quadratic-formula.eye) | Solves sample quadratic equations. | [`output/quadratic-formula.eye`](../examples/output/quadratic-formula.eye) |
|
|
445
451
|
| [`radioactive-decay.eye`](../examples/radioactive-decay.eye) | Computes radioactive decay over time. | [`output/radioactive-decay.eye`](../examples/output/radioactive-decay.eye) |
|
|
452
|
+
| [`register-allocation.eye`](../examples/register-allocation.eye) | Allocates temporaries to two registers with spilling by bounded graph-coloring search. | [`output/register-allocation.eye`](../examples/output/register-allocation.eye) |
|
|
446
453
|
| [`reusable-builtins.eye`](../examples/reusable-builtins.eye) | Tours reusable numeric, list, and string builtins. | [`output/reusable-builtins.eye`](../examples/output/reusable-builtins.eye) |
|
|
447
454
|
| [`riemann-hypothesis.eye`](../examples/riemann-hypothesis.eye) | Checks a finite catalogue of non-trivial zeta zeros against the Riemann-hypothesis condition. | [`output/riemann-hypothesis.eye`](../examples/output/riemann-hypothesis.eye) |
|
|
448
455
|
| [`route-planning.eye`](../examples/route-planning.eye) | Finds routes and records them as explicit route terms. | [`output/route-planning.eye`](../examples/output/route-planning.eye) |
|
|
456
|
+
| [`sat-solver-dpll.eye`](../examples/sat-solver-dpll.eye) | Searches a CNF formula with DPLL-style recursive decisions and early contradiction pruning. | [`output/sat-solver-dpll.eye`](../examples/output/sat-solver-dpll.eye) |
|
|
449
457
|
| [`security-incident-correlation.eye`](../examples/security-incident-correlation.eye) | Correlates security incidents across signals. | [`output/security-incident-correlation.eye`](../examples/output/security-incident-correlation.eye) |
|
|
450
458
|
| [`send-more-money.eye`](../examples/send-more-money.eye) | Solves the SEND + MORE = MONEY cryptarithm. | [`output/send-more-money.eye`](../examples/output/send-more-money.eye) |
|
|
451
459
|
| [`service-impact.eye`](../examples/service-impact.eye) | Analyzes service impact over cyclic dependencies. | [`output/service-impact.eye`](../examples/output/service-impact.eye) |
|
|
@@ -464,6 +472,8 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
464
472
|
| [`term-tools.eye`](../examples/term-tools.eye) | Inspects, builds, renders, and validates terms with reusable term/control builtins. | [`output/term-tools.eye`](../examples/output/term-tools.eye) |
|
|
465
473
|
| [`totient-summatory.eye`](../examples/totient-summatory.eye) | Computes Euler totients and their summatory function. | [`output/totient-summatory.eye`](../examples/output/totient-summatory.eye) |
|
|
466
474
|
| [`trust-flow-provenance-threshold.eye`](../examples/trust-flow-provenance-threshold.eye) | Classifies message trust from provenance confidence scores. | [`output/trust-flow-provenance-threshold.eye`](../examples/output/trust-flow-provenance-threshold.eye) |
|
|
475
|
+
| [`truth-maintenance-system.eye`](../examples/truth-maintenance-system.eye) | Tracks assumptions, justifications, supported beliefs, and inconsistent environments in a tiny TMS. | [`output/truth-maintenance-system.eye`](../examples/output/truth-maintenance-system.eye) |
|
|
476
|
+
| [`type-inference.eye`](../examples/type-inference.eye) | Infers/checks types for a tiny lambda language using logic unification over expression syntax trees. | [`output/type-inference.eye`](../examples/output/type-inference.eye) |
|
|
467
477
|
| [`turing.eye`](../examples/turing.eye) | Simulates a binary-increment Turing machine. | [`output/turing.eye`](../examples/output/turing.eye) |
|
|
468
478
|
| [`vector-similarity.eye`](../examples/vector-similarity.eye) | Computes dot product, norm, and cosine similarity. | [`output/vector-similarity.eye`](../examples/output/vector-similarity.eye) |
|
|
469
479
|
| [`vulnerability-impact.eye`](../examples/vulnerability-impact.eye) | Analyzes vulnerable transitive dependencies and urgent patch impact. | [`output/vulnerability-impact.eye`](../examples/output/vulnerability-impact.eye) |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
% Abstract interpretation over a tiny imperative program.
|
|
2
|
+
%
|
|
3
|
+
% The concrete program is:
|
|
4
|
+
%
|
|
5
|
+
% x := input();
|
|
6
|
+
% if x < 0 then y := -x else y := x;
|
|
7
|
+
% z := 10 / y;
|
|
8
|
+
%
|
|
9
|
+
% Instead of executing the program for every integer input, this example tracks
|
|
10
|
+
% only the abstract sign of each variable: neg, zero, or pos. The analysis is
|
|
11
|
+
% deliberately conservative: if the join point can see y = zero on any path, the
|
|
12
|
+
% division is reported as a possible division-by-zero warning.
|
|
13
|
+
|
|
14
|
+
materialize(absState, 3).
|
|
15
|
+
materialize(absWarning, 2).
|
|
16
|
+
materialize(absConclusion, 2).
|
|
17
|
+
|
|
18
|
+
table(abs_state, 3).
|
|
19
|
+
|
|
20
|
+
% The abstract domain.
|
|
21
|
+
input_sign(neg).
|
|
22
|
+
input_sign(zero).
|
|
23
|
+
input_sign(pos).
|
|
24
|
+
|
|
25
|
+
% The input statement gives x any of the three abstract signs.
|
|
26
|
+
abs_state(input, x, ?sign) :- input_sign(?sign).
|
|
27
|
+
|
|
28
|
+
% The branch refines the sign of x. The negative branch only receives neg; the
|
|
29
|
+
% non-negative branch receives zero or pos.
|
|
30
|
+
abs_state(negative_branch, x, neg) :- abs_state(input, x, neg).
|
|
31
|
+
abs_state(nonnegative_branch, x, zero) :- abs_state(input, x, zero).
|
|
32
|
+
abs_state(nonnegative_branch, x, pos) :- abs_state(input, x, pos).
|
|
33
|
+
|
|
34
|
+
% Transfer functions for assignments. In the negative branch, y := -x turns a
|
|
35
|
+
% negative x into a positive y. In the non-negative branch, y := x preserves the
|
|
36
|
+
% zero/positive information.
|
|
37
|
+
abs_state(negative_branch, y, pos) :- abs_state(negative_branch, x, neg).
|
|
38
|
+
abs_state(nonnegative_branch, y, ?sign) :- abs_state(nonnegative_branch, x, ?sign).
|
|
39
|
+
|
|
40
|
+
% The join point merges abstract states from both branches.
|
|
41
|
+
abs_state(join, ?var, ?sign) :- abs_state(negative_branch, ?var, ?sign).
|
|
42
|
+
abs_state(join, ?var, ?sign) :- abs_state(nonnegative_branch, ?var, ?sign).
|
|
43
|
+
|
|
44
|
+
% A possible zero denominator is enough to raise a conservative warning.
|
|
45
|
+
possible_division_by_zero(join) :- abs_state(join, y, zero).
|
|
46
|
+
|
|
47
|
+
absState(?point, ?var, sign(?sign)) :- abs_state(?point, ?var, ?sign).
|
|
48
|
+
absWarning(division_by_zero, ?point) :- possible_division_by_zero(?point).
|
|
49
|
+
absConclusion(case, "abstract interpretation keeps all feasible signs and warns because y may be zero") :-
|
|
50
|
+
possible_division_by_zero(join).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
% A tiny CDCL-style SAT trace with one learned clause.
|
|
2
|
+
%
|
|
3
|
+
% Industrial CDCL solvers use watched literals, mutable trails, non-chronological
|
|
4
|
+
% backjumping, clause databases, restarts, and activity heuristics. Eyelang has
|
|
5
|
+
% no mutable state or destructive trail updates, so this example models one small
|
|
6
|
+
% conflict-analysis episode as relations over immutable terms.
|
|
7
|
+
%
|
|
8
|
+
% Formula:
|
|
9
|
+
% c1: not(a) or c
|
|
10
|
+
% c2: not(c)
|
|
11
|
+
% c3: a or b
|
|
12
|
+
%
|
|
13
|
+
% Decision a=true forces c=true by c1, which conflicts with c2. Resolving the
|
|
14
|
+
% reason c1 with the conflict c2 learns not(a). After backjumping, learned
|
|
15
|
+
% not(a) forces a=false, c2 gives c=false, and c3 forces b=true.
|
|
16
|
+
|
|
17
|
+
materialize(cdclAnswer, 2).
|
|
18
|
+
|
|
19
|
+
clause(c1, [neg(a), pos(c)]).
|
|
20
|
+
clause(c2, [neg(c)]).
|
|
21
|
+
clause(c3, [pos(a), pos(b)]).
|
|
22
|
+
|
|
23
|
+
% Initial trail before conflict analysis.
|
|
24
|
+
initial_value(a, true, decision(level1)).
|
|
25
|
+
initial_value(c, true, implied_by(c1)).
|
|
26
|
+
|
|
27
|
+
% The current trail makes a literal true or false.
|
|
28
|
+
lit_true(pos(?var), ?value_rel) :- call_value(?value_rel, ?var, true, ?).
|
|
29
|
+
lit_true(neg(?var), ?value_rel) :- call_value(?value_rel, ?var, false, ?).
|
|
30
|
+
lit_false(pos(?var), ?value_rel) :- call_value(?value_rel, ?var, false, ?).
|
|
31
|
+
lit_false(neg(?var), ?value_rel) :- call_value(?value_rel, ?var, true, ?).
|
|
32
|
+
|
|
33
|
+
% Eyelang cannot pass predicates as first-class values, so this small dispatcher
|
|
34
|
+
% lets the same literal helpers inspect either the initial or final trail.
|
|
35
|
+
call_value(initial, ?var, ?value, ?reason) :- initial_value(?var, ?value, ?reason).
|
|
36
|
+
call_value(final, ?var, ?value, ?reason) :- final_value(?var, ?value, ?reason).
|
|
37
|
+
|
|
38
|
+
% A clause is conflicting when all of its literals are false under a trail.
|
|
39
|
+
conflict(?trail, ?clause) :-
|
|
40
|
+
clause(?clause, ?literals),
|
|
41
|
+
forall(member(?literal, ?literals), lit_false(?literal, ?trail)).
|
|
42
|
+
|
|
43
|
+
% The learned clause for this tiny implication graph is obtained by resolving
|
|
44
|
+
% the conflict clause not(c) with c's reason not(a) or c, yielding not(a).
|
|
45
|
+
learned_clause(l1, [neg(a)]).
|
|
46
|
+
learned_from(l1, resolve(c2, c1, pivot(c))).
|
|
47
|
+
|
|
48
|
+
% After backjumping, the learned unit clause fixes a=false. Then the original
|
|
49
|
+
% clauses imply c=false and b=true.
|
|
50
|
+
final_value(a, false, learned(l1)).
|
|
51
|
+
final_value(c, false, unit(c2)).
|
|
52
|
+
final_value(b, true, unit(c3)).
|
|
53
|
+
|
|
54
|
+
model_satisfies_clause(?trail, ?clause) :-
|
|
55
|
+
clause(?clause, ?literals),
|
|
56
|
+
member(?literal, ?literals),
|
|
57
|
+
lit_true(?literal, ?trail).
|
|
58
|
+
|
|
59
|
+
final_model_ok(ok) :- forall(clause(?name, ?), model_satisfies_clause(final, ?name)).
|
|
60
|
+
|
|
61
|
+
cdclAnswer(conflict_clause, ?clause) :- conflict(initial, ?clause).
|
|
62
|
+
cdclAnswer(learned_clause, ?literals) :- learned_clause(l1, ?literals).
|
|
63
|
+
cdclAnswer(learned_from, ?reason) :- learned_from(l1, ?reason).
|
|
64
|
+
cdclAnswer(final_value(?var), ?value) :- final_model_ok(ok), final_value(?var, ?value, ?).
|
|
65
|
+
cdclAnswer(note, "one learned clause makes the final model satisfy all original clauses") :- final_model_ok(ok).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
% Bounded equality saturation over tiny arithmetic expression terms.
|
|
2
|
+
%
|
|
3
|
+
% Real equality-saturation engines use mutable e-graphs, union-find classes,
|
|
4
|
+
% congruence closure, rewrite scheduling, and cost-based extraction. Eyelang has
|
|
5
|
+
% none of those primitives, so this example simulates the idea relationally: it
|
|
6
|
+
% enumerates expressions reachable within a small rewrite-fuel bound, scores the
|
|
7
|
+
% generated terms, and extracts the cheapest equivalent expression.
|
|
8
|
+
%
|
|
9
|
+
% The point is not to be fast. The point is to show the declarative shape of an
|
|
10
|
+
% e-graph optimizer in a language that was not designed for it.
|
|
11
|
+
|
|
12
|
+
materialize(egraphAnswer, 2).
|
|
13
|
+
|
|
14
|
+
table(equivalent_at_depth, 3).
|
|
15
|
+
table(expr_cost, 2).
|
|
16
|
+
|
|
17
|
+
% Start expression:
|
|
18
|
+
% ((x + 0) * 1) + 2 * (1 + 2)
|
|
19
|
+
% The best bounded rewrite result should be x + 6.
|
|
20
|
+
expr(start, add(mul(add(x, 0), 1), mul(2, add(1, 2)))).
|
|
21
|
+
fuel(6).
|
|
22
|
+
|
|
23
|
+
% Directed rewrite rules. A true e-graph would keep equalities in equivalence
|
|
24
|
+
% classes. This bounded version uses oriented rewrites so search terminates.
|
|
25
|
+
rewrite(add(?x, 0), ?x).
|
|
26
|
+
rewrite(add(0, ?x), ?x).
|
|
27
|
+
rewrite(mul(?x, 1), ?x).
|
|
28
|
+
rewrite(mul(1, ?x), ?x).
|
|
29
|
+
rewrite(mul(?x, 0), 0).
|
|
30
|
+
rewrite(mul(0, ?x), 0).
|
|
31
|
+
|
|
32
|
+
% Constant folding and one distributivity rule make the search space less toyish.
|
|
33
|
+
rewrite(add(?a, ?b), ?c) :- add(?a, ?b, ?c).
|
|
34
|
+
rewrite(mul(?a, ?b), ?c) :- mul(?a, ?b, ?c).
|
|
35
|
+
rewrite(mul(?x, add(?y, ?z)), add(mul(?x, ?y), mul(?x, ?z))).
|
|
36
|
+
|
|
37
|
+
% Apply a rewrite at the root or inside one subterm.
|
|
38
|
+
rewrite_anywhere(?in, ?out) :- rewrite(?in, ?out).
|
|
39
|
+
rewrite_anywhere(add(?a, ?b), add(?new_a, ?b)) :- rewrite_anywhere(?a, ?new_a).
|
|
40
|
+
rewrite_anywhere(add(?a, ?b), add(?a, ?new_b)) :- rewrite_anywhere(?b, ?new_b).
|
|
41
|
+
rewrite_anywhere(mul(?a, ?b), mul(?new_a, ?b)) :- rewrite_anywhere(?a, ?new_a).
|
|
42
|
+
rewrite_anywhere(mul(?a, ?b), mul(?a, ?new_b)) :- rewrite_anywhere(?b, ?new_b).
|
|
43
|
+
|
|
44
|
+
% Fuel-bounded closure. Every depth represents exactly that many rewrite steps;
|
|
45
|
+
% candidate_expression/1 looks across all depths from zero to the fuel limit.
|
|
46
|
+
equivalent_at_depth(0, ?expr, ?expr).
|
|
47
|
+
equivalent_at_depth(?depth, ?expr, ?out) :-
|
|
48
|
+
gt(?depth, 0),
|
|
49
|
+
sub(?depth, 1, ?previous_depth),
|
|
50
|
+
equivalent_at_depth(?previous_depth, ?expr, ?mid),
|
|
51
|
+
rewrite_anywhere(?mid, ?out).
|
|
52
|
+
|
|
53
|
+
candidate_expression(?candidate) :-
|
|
54
|
+
expr(start, ?expr),
|
|
55
|
+
fuel(?fuel),
|
|
56
|
+
between(0, ?fuel, ?depth),
|
|
57
|
+
equivalent_at_depth(?depth, ?expr, ?candidate).
|
|
58
|
+
|
|
59
|
+
% A tiny cost model for extraction. Leaves cost 1; compound nodes cost 1 plus
|
|
60
|
+
% their children. The numeric range is deliberately bounded for the generated
|
|
61
|
+
% constants in this example.
|
|
62
|
+
expr_cost(x, 1).
|
|
63
|
+
expr_cost(?n, 1) :- between(0, 20, ?n).
|
|
64
|
+
expr_cost(add(?a, ?b), ?cost) :-
|
|
65
|
+
expr_cost(?a, ?a_cost),
|
|
66
|
+
expr_cost(?b, ?b_cost),
|
|
67
|
+
add(?a_cost, ?b_cost, ?children),
|
|
68
|
+
add(?children, 1, ?cost).
|
|
69
|
+
expr_cost(mul(?a, ?b), ?cost) :-
|
|
70
|
+
expr_cost(?a, ?a_cost),
|
|
71
|
+
expr_cost(?b, ?b_cost),
|
|
72
|
+
add(?a_cost, ?b_cost, ?children),
|
|
73
|
+
add(?children, 1, ?cost).
|
|
74
|
+
|
|
75
|
+
best_expression(?expr, ?cost) :-
|
|
76
|
+
aggregate_min([?candidate_cost, ?candidate], ?candidate,
|
|
77
|
+
(candidate_expression(?candidate), expr_cost(?candidate, ?candidate_cost)),
|
|
78
|
+
[?cost, ?expr], ?expr).
|
|
79
|
+
|
|
80
|
+
egraphAnswer(start, ?expr) :- expr(start, ?expr).
|
|
81
|
+
egraphAnswer(best, ?expr) :- best_expression(?expr, ?).
|
|
82
|
+
egraphAnswer(cost, ?cost) :- best_expression(?, ?cost).
|
|
83
|
+
egraphAnswer(candidate_count, ?count) :- countall(candidate_expression(?), ?count).
|
|
84
|
+
egraphAnswer(note, "bounded equality saturation extracts the cheapest term without a real e-graph") :- best_expression(?, ?).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
% Bounded Knuth-Bendix-style completion for append/2 terms.
|
|
2
|
+
%
|
|
3
|
+
% Full Knuth-Bendix completion orients equations, generates all critical pairs,
|
|
4
|
+
% reduces them, and may add new rules until all overlaps are joinable. That is
|
|
5
|
+
% a difficult global search problem. This example keeps the recognizable shape
|
|
6
|
+
% but bounds the hard part: the rewrite system is fixed, and a small catalog of
|
|
7
|
+
% critical overlaps is checked for joinability by normalization.
|
|
8
|
+
|
|
9
|
+
materialize(kbAnswer, 2).
|
|
10
|
+
|
|
11
|
+
table(normal_form, 2).
|
|
12
|
+
|
|
13
|
+
% Oriented equations for a monoid-like append constructor.
|
|
14
|
+
% append(nil, x) -> x
|
|
15
|
+
% append(x, nil) -> x
|
|
16
|
+
% append(append(x,y),z)-> append(x, append(y,z))
|
|
17
|
+
% The third rule right-associates terms so normalization terminates here.
|
|
18
|
+
oriented_rule(left_identity, append(nil, ?x), ?x).
|
|
19
|
+
oriented_rule(right_identity, append(?x, nil), ?x).
|
|
20
|
+
oriented_rule(associate_right, append(append(?x, ?y), ?z), append(?x, append(?y, ?z))).
|
|
21
|
+
|
|
22
|
+
% One rewrite at the root or below an append node.
|
|
23
|
+
rewrite_once(?in, ?out, ?rule) :- oriented_rule(?rule, ?in, ?out).
|
|
24
|
+
rewrite_once(append(?a, ?b), append(?new_a, ?b), ?rule) :- rewrite_once(?a, ?new_a, ?rule).
|
|
25
|
+
rewrite_once(append(?a, ?b), append(?a, ?new_b), ?rule) :- rewrite_once(?b, ?new_b, ?rule).
|
|
26
|
+
|
|
27
|
+
% Normalization by repeated rewriting. The rules above are oriented so that the
|
|
28
|
+
% recursive search has a normal form for the bounded terms in this example.
|
|
29
|
+
normal_form(?term, ?term) :- not(rewrite_once(?term, ?, ?)).
|
|
30
|
+
normal_form(?term, ?normal) :- rewrite_once(?term, ?next, ?), normal_form(?next, ?normal).
|
|
31
|
+
|
|
32
|
+
% A few critical pairs that arise from overlapping the three oriented rules.
|
|
33
|
+
% Each pair records the two one-step reducts that must later normalize together.
|
|
34
|
+
critical_pair(left_identity_assoc,
|
|
35
|
+
append(a, b),
|
|
36
|
+
append(nil, append(a, b))).
|
|
37
|
+
critical_pair(right_identity_assoc,
|
|
38
|
+
append(a, b),
|
|
39
|
+
append(a, append(nil, b))).
|
|
40
|
+
critical_pair(nested_assoc,
|
|
41
|
+
append(append(a, append(b, c)), d),
|
|
42
|
+
append(append(a, b), append(c, d))).
|
|
43
|
+
|
|
44
|
+
joined_pair(?name) :-
|
|
45
|
+
critical_pair(?name, ?left, ?right),
|
|
46
|
+
normal_form(?left, ?normal),
|
|
47
|
+
normal_form(?right, ?normal).
|
|
48
|
+
|
|
49
|
+
sample_term(append(append(nil, append(a, nil)), append(b, c))).
|
|
50
|
+
|
|
51
|
+
kbAnswer(sample_normal_form, ?normal) :- sample_term(?term), normal_form(?term, ?normal).
|
|
52
|
+
kbAnswer(joined_critical_pair, ?name) :- joined_pair(?name).
|
|
53
|
+
kbAnswer(oriented_rule_count, ?count) :- countall(oriented_rule(?, ?, ?), ?count).
|
|
54
|
+
kbAnswer(joined_critical_pair_count, ?count) :- countall(joined_pair(?), ?count).
|
|
55
|
+
kbAnswer(note, "a bounded completion check proves the selected critical pairs join") :- joined_pair(nested_assoc).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
absState(input, x, sign(neg)).
|
|
2
|
+
absState(input, x, sign(zero)).
|
|
3
|
+
absState(input, x, sign(pos)).
|
|
4
|
+
absState(negative_branch, x, sign(neg)).
|
|
5
|
+
absState(nonnegative_branch, x, sign(zero)).
|
|
6
|
+
absState(nonnegative_branch, x, sign(pos)).
|
|
7
|
+
absState(negative_branch, y, sign(pos)).
|
|
8
|
+
absState(nonnegative_branch, y, sign(zero)).
|
|
9
|
+
absState(nonnegative_branch, y, sign(pos)).
|
|
10
|
+
absState(join, x, sign(neg)).
|
|
11
|
+
absState(join, y, sign(pos)).
|
|
12
|
+
absState(join, x, sign(zero)).
|
|
13
|
+
absState(join, x, sign(pos)).
|
|
14
|
+
absState(join, y, sign(zero)).
|
|
15
|
+
absWarning(division_by_zero, join).
|
|
16
|
+
absConclusion(case, "abstract interpretation keeps all feasible signs and warns because y may be zero").
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
cdclAnswer(conflict_clause, c2).
|
|
2
|
+
cdclAnswer(learned_clause, [neg(a)]).
|
|
3
|
+
cdclAnswer(learned_from, resolve(c2, c1, pivot(c))).
|
|
4
|
+
cdclAnswer(final_value(a), false).
|
|
5
|
+
cdclAnswer(final_value(c), false).
|
|
6
|
+
cdclAnswer(final_value(b), true).
|
|
7
|
+
cdclAnswer(note, "one learned clause makes the final model satisfy all original clauses").
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
kbAnswer(sample_normal_form, append(a, append(b, c))).
|
|
2
|
+
kbAnswer(joined_critical_pair, left_identity_assoc).
|
|
3
|
+
kbAnswer(joined_critical_pair, right_identity_assoc).
|
|
4
|
+
kbAnswer(joined_critical_pair, nested_assoc).
|
|
5
|
+
kbAnswer(oriented_rule_count, 3).
|
|
6
|
+
kbAnswer(joined_critical_pair_count, 3).
|
|
7
|
+
kbAnswer(note, "a bounded completion check proves the selected critical pairs join").
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
partialEvalAnswer(residual(poly_y), add(mul(const(10), var(y)), const(13))).
|
|
2
|
+
partialEvalAnswer(residual(static_branch), const(11)).
|
|
3
|
+
partialEvalAnswer(residual(dynamic_branch), if(var(flag), const(11), mul(var(y), const(2)))).
|
|
4
|
+
partialEvalAnswer(note, "static inputs are folded while dynamic variables remain as residual code").
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pointsTo(x, object_a).
|
|
2
|
+
pointsTo(z, object_b).
|
|
3
|
+
pointsTo(y, object_a).
|
|
4
|
+
pointsTo(r, object_b).
|
|
5
|
+
pointsTo(q, object_b).
|
|
6
|
+
heapField(object_a, object_b).
|
|
7
|
+
pointerFlow(load_q_from_x, object_b).
|
|
8
|
+
pointerConclusion(case, "the load q = *x recovers object_b through the store *y = z and y = x").
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
registerAnswer(best_allocation, [bind(a, r1), bind(b, spill), bind(c, r2), bind(d, r1)]).
|
|
2
|
+
registerAnswer(spill_cost, 1).
|
|
3
|
+
registerAnswer(place(a), r1).
|
|
4
|
+
registerAnswer(place(b), spill).
|
|
5
|
+
registerAnswer(place(c), r2).
|
|
6
|
+
registerAnswer(place(d), r1).
|
|
7
|
+
registerAnswer(valid_allocation_count, 33).
|
|
8
|
+
registerAnswer(note, "the cheapest solution spills b to color the a-b-c triangle with two registers").
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
satModel([bind(d, true), bind(c, true), bind(b, true), bind(a, false)]).
|
|
2
|
+
satValue(d, true).
|
|
3
|
+
satValue(c, true).
|
|
4
|
+
satValue(b, true).
|
|
5
|
+
satValue(a, false).
|
|
6
|
+
satClauseStatus(c1, satisfied).
|
|
7
|
+
satClauseStatus(c2, satisfied).
|
|
8
|
+
satClauseStatus(c3, satisfied).
|
|
9
|
+
satClauseStatus(c4, satisfied).
|
|
10
|
+
satClauseStatus(c5, satisfied).
|
|
11
|
+
satConclusion(case, "DPLL finds a satisfying assignment after pruning clauses that become impossible").
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
tmsSupport(clear_only, clear_path).
|
|
2
|
+
tmsSupport(conflicting_sensors, clear_path).
|
|
3
|
+
tmsSupport(blocked_only, blocked_path).
|
|
4
|
+
tmsSupport(conflicting_sensors, blocked_path).
|
|
5
|
+
tmsSupport(override_blocked, blocked_path).
|
|
6
|
+
tmsSupport(clear_only, permit_go).
|
|
7
|
+
tmsSupport(conflicting_sensors, permit_go).
|
|
8
|
+
tmsSupport(blocked_only, forbid_go).
|
|
9
|
+
tmsSupport(conflicting_sensors, forbid_go).
|
|
10
|
+
tmsSupport(override_blocked, forbid_go).
|
|
11
|
+
tmsSupport(override_blocked, permit_go).
|
|
12
|
+
tmsJustification(clear_only, j_clear_path, clear_path).
|
|
13
|
+
tmsJustification(conflicting_sensors, j_clear_path, clear_path).
|
|
14
|
+
tmsJustification(blocked_only, j_blocked_path, blocked_path).
|
|
15
|
+
tmsJustification(conflicting_sensors, j_blocked_path, blocked_path).
|
|
16
|
+
tmsJustification(override_blocked, j_blocked_path, blocked_path).
|
|
17
|
+
tmsJustification(clear_only, j_permit_from_clear, permit_go).
|
|
18
|
+
tmsJustification(conflicting_sensors, j_permit_from_clear, permit_go).
|
|
19
|
+
tmsJustification(blocked_only, j_forbid_from_blocked, forbid_go).
|
|
20
|
+
tmsJustification(conflicting_sensors, j_forbid_from_blocked, forbid_go).
|
|
21
|
+
tmsJustification(override_blocked, j_forbid_from_blocked, forbid_go).
|
|
22
|
+
tmsJustification(override_blocked, j_override, permit_go).
|
|
23
|
+
tmsInconsistent(conflicting_sensors).
|
|
24
|
+
tmsInconsistent(override_blocked).
|
|
25
|
+
tmsConclusion(case, "truth maintenance separates support from consistency across assumption environments").
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type_answer(id, fun(t0, t0)).
|
|
2
|
+
type_answer(const, fun(t0, fun(t1, t0))).
|
|
3
|
+
type_answer(apply_id, int).
|
|
4
|
+
type_answer(compose, fun(fun(t1, t2), fun(fun(t0, t1), fun(t0, t2)))).
|
|
5
|
+
type_answer(branch, int).
|
|
6
|
+
type_answer(first_of_pair, bool).
|
|
7
|
+
type_reason(compose, "application unifies f with t1 -> t2 and g with t0 -> t1").
|
|
8
|
+
type_reason(apply_id, "the identity function's parameter type is unified with int").
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
% A tiny partial evaluator for expression terms.
|
|
2
|
+
%
|
|
3
|
+
% Real partial evaluation can specialize interpreters, control unfolding, avoid
|
|
4
|
+
% code explosion, and even approach self-application. This bounded Eyelang
|
|
5
|
+
% version specializes a miniature expression language with known static inputs:
|
|
6
|
+
% constants are folded, known variables are substituted, and dynamic variables
|
|
7
|
+
% remain as residual code.
|
|
8
|
+
|
|
9
|
+
materialize(partialEvalAnswer, 2).
|
|
10
|
+
|
|
11
|
+
table(pe, 3).
|
|
12
|
+
|
|
13
|
+
% Expression language: const/1, bool/1, var/1, add/2, mul/2, and if/3.
|
|
14
|
+
% Static environments are lists of bind(Name, ResidualValue) terms.
|
|
15
|
+
program(poly_y,
|
|
16
|
+
add(mul(var(x), var(y)), add(var(x), const(3))),
|
|
17
|
+
[bind(x, const(10))]).
|
|
18
|
+
program(static_branch,
|
|
19
|
+
if(bool(true), add(var(x), const(1)), mul(var(y), const(999))),
|
|
20
|
+
[bind(x, const(10))]).
|
|
21
|
+
program(dynamic_branch,
|
|
22
|
+
if(var(flag), add(var(x), const(1)), mul(var(y), const(2))),
|
|
23
|
+
[bind(x, const(10))]).
|
|
24
|
+
|
|
25
|
+
lookup(?name, [bind(?name, ?value) | ?], ?value).
|
|
26
|
+
lookup(?name, [bind(?, ?) | ?rest], ?value) :- lookup(?name, ?rest, ?value).
|
|
27
|
+
|
|
28
|
+
known_var(?env, ?name, ?value) :- lookup(?name, ?env, ?value).
|
|
29
|
+
unknown_var(?env, ?name) :- not(known_var(?env, ?name, ?)).
|
|
30
|
+
|
|
31
|
+
pe(?, const(?n), const(?n)).
|
|
32
|
+
pe(?, bool(?b), bool(?b)).
|
|
33
|
+
pe(?env, var(?name), ?value) :- known_var(?env, ?name, ?value).
|
|
34
|
+
pe(?env, var(?name), var(?name)) :- unknown_var(?env, ?name).
|
|
35
|
+
|
|
36
|
+
% Constant folding for arithmetic when both residual operands became constants.
|
|
37
|
+
pe(?env, add(?left, ?right), const(?sum)) :-
|
|
38
|
+
pe(?env, ?left, const(?a)),
|
|
39
|
+
pe(?env, ?right, const(?b)),
|
|
40
|
+
add(?a, ?b, ?sum).
|
|
41
|
+
pe(?env, mul(?left, ?right), const(?product)) :-
|
|
42
|
+
pe(?env, ?left, const(?a)),
|
|
43
|
+
pe(?env, ?right, const(?b)),
|
|
44
|
+
mul(?a, ?b, ?product).
|
|
45
|
+
|
|
46
|
+
% Residual arithmetic when at least one operand remains dynamic.
|
|
47
|
+
pe(?env, add(?left, ?right), add(?left_residual, ?right_residual)) :-
|
|
48
|
+
pe(?env, ?left, ?left_residual),
|
|
49
|
+
pe(?env, ?right, ?right_residual),
|
|
50
|
+
not((eq(?left_residual, const(?a)), eq(?right_residual, const(?b)))).
|
|
51
|
+
pe(?env, mul(?left, ?right), mul(?left_residual, ?right_residual)) :-
|
|
52
|
+
pe(?env, ?left, ?left_residual),
|
|
53
|
+
pe(?env, ?right, ?right_residual),
|
|
54
|
+
not((eq(?left_residual, const(?a)), eq(?right_residual, const(?b)))).
|
|
55
|
+
|
|
56
|
+
% Static conditionals choose a branch; dynamic conditionals keep both residual
|
|
57
|
+
% branches after specializing their contents.
|
|
58
|
+
pe(?env, if(?cond, ?then, ?else), ?residual) :-
|
|
59
|
+
pe(?env, ?cond, bool(true)),
|
|
60
|
+
pe(?env, ?then, ?residual).
|
|
61
|
+
pe(?env, if(?cond, ?then, ?else), ?residual) :-
|
|
62
|
+
pe(?env, ?cond, bool(false)),
|
|
63
|
+
pe(?env, ?else, ?residual).
|
|
64
|
+
pe(?env, if(?cond, ?then, ?else), if(?cond_residual, ?then_residual, ?else_residual)) :-
|
|
65
|
+
pe(?env, ?cond, ?cond_residual),
|
|
66
|
+
not(eq(?cond_residual, bool(true))),
|
|
67
|
+
not(eq(?cond_residual, bool(false))),
|
|
68
|
+
pe(?env, ?then, ?then_residual),
|
|
69
|
+
pe(?env, ?else, ?else_residual).
|
|
70
|
+
|
|
71
|
+
residual_program(?name, ?residual) :- program(?name, ?expr, ?env), pe(?env, ?expr, ?residual).
|
|
72
|
+
|
|
73
|
+
partialEvalAnswer(residual(?name), ?residual) :- residual_program(?name, ?residual).
|
|
74
|
+
partialEvalAnswer(note, "static inputs are folded while dynamic variables remain as residual code") :- residual_program(poly_y, ?).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
% Andersen-style inclusion-based pointer analysis.
|
|
2
|
+
%
|
|
3
|
+
% The program being analyzed has address-taking, assignment, store, and load
|
|
4
|
+
% statements. The logic rules compute a fixed point of points_to/2 and
|
|
5
|
+
% field_points_to/2 facts. This is the classic Datalog shape used in scalable
|
|
6
|
+
% pointer-analysis papers, reduced to a small readable instance.
|
|
7
|
+
|
|
8
|
+
materialize(pointsTo, 2).
|
|
9
|
+
materialize(heapField, 2).
|
|
10
|
+
materialize(pointerFlow, 2).
|
|
11
|
+
materialize(pointerConclusion, 2).
|
|
12
|
+
|
|
13
|
+
table(points_to, 2).
|
|
14
|
+
table(field_points_to, 2).
|
|
15
|
+
|
|
16
|
+
% Source-program statements:
|
|
17
|
+
% x = &object_a
|
|
18
|
+
% z = &object_b
|
|
19
|
+
% y = x
|
|
20
|
+
% *y = z
|
|
21
|
+
% q = *x
|
|
22
|
+
% r = q
|
|
23
|
+
addr(x, object_a).
|
|
24
|
+
addr(z, object_b).
|
|
25
|
+
assign(y, x).
|
|
26
|
+
store(y, z).
|
|
27
|
+
load(q, x).
|
|
28
|
+
assign(r, q).
|
|
29
|
+
|
|
30
|
+
% Address-taking and assignment constraints.
|
|
31
|
+
points_to(?var, ?object) :- addr(?var, ?object).
|
|
32
|
+
points_to(?to, ?object) :- assign(?to, ?from), points_to(?from, ?object).
|
|
33
|
+
|
|
34
|
+
% Store and load constraints. If y may point to object_a and z may point to
|
|
35
|
+
% object_b, then object_a's abstract field may point to object_b. A later load
|
|
36
|
+
% from x therefore gives q the same target.
|
|
37
|
+
field_points_to(?heap_object, ?value_object) :-
|
|
38
|
+
store(?pointer, ?value),
|
|
39
|
+
points_to(?pointer, ?heap_object),
|
|
40
|
+
points_to(?value, ?value_object).
|
|
41
|
+
points_to(?to, ?value_object) :-
|
|
42
|
+
load(?to, ?pointer),
|
|
43
|
+
points_to(?pointer, ?heap_object),
|
|
44
|
+
field_points_to(?heap_object, ?value_object).
|
|
45
|
+
|
|
46
|
+
pointsTo(?var, ?object) :- points_to(?var, ?object).
|
|
47
|
+
heapField(?heap_object, ?value_object) :- field_points_to(?heap_object, ?value_object).
|
|
48
|
+
pointerFlow(load_q_from_x, ?object) :- points_to(q, ?object).
|
|
49
|
+
pointerConclusion(case, "the load q = *x recovers object_b through the store *y = z and y = x") :-
|
|
50
|
+
points_to(q, object_b).
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
% Register allocation as bounded graph coloring with spilling.
|
|
2
|
+
%
|
|
3
|
+
% Production allocators combine liveness analysis, interference graphs, register
|
|
4
|
+
% classes, coalescing, rematerialization, and spill-code insertion. This Eyelang
|
|
5
|
+
% example reduces the problem to its logical core: enumerate assignments of a
|
|
6
|
+
% few temporaries to two registers or memory, reject register conflicts, and use
|
|
7
|
+
% aggregate_min/5 to choose the cheapest spill plan.
|
|
8
|
+
|
|
9
|
+
materialize(registerAnswer, 2).
|
|
10
|
+
|
|
11
|
+
% Two physical registers are available. The synthetic place spill means the
|
|
12
|
+
% temporary is kept in memory instead of a register.
|
|
13
|
+
register(r1).
|
|
14
|
+
register(r2).
|
|
15
|
+
place(?reg) :- register(?reg).
|
|
16
|
+
place(spill).
|
|
17
|
+
|
|
18
|
+
% Temporaries and the cost of spilling each one. The triangle a-b-c cannot be
|
|
19
|
+
% colored with only two registers, so at least one of them must spill.
|
|
20
|
+
temporary(a, 10).
|
|
21
|
+
temporary(b, 1).
|
|
22
|
+
temporary(c, 10).
|
|
23
|
+
temporary(d, 2).
|
|
24
|
+
|
|
25
|
+
interferes(a, b).
|
|
26
|
+
interferes(b, c).
|
|
27
|
+
interferes(c, a).
|
|
28
|
+
interferes(c, d).
|
|
29
|
+
|
|
30
|
+
% A candidate allocation is an immutable list of bindings. This is deliberately
|
|
31
|
+
% brute force: three choices for each of four temporaries.
|
|
32
|
+
candidate_allocation([
|
|
33
|
+
bind(a, ?a_place),
|
|
34
|
+
bind(b, ?b_place),
|
|
35
|
+
bind(c, ?c_place),
|
|
36
|
+
bind(d, ?d_place)
|
|
37
|
+
]) :-
|
|
38
|
+
place(?a_place),
|
|
39
|
+
place(?b_place),
|
|
40
|
+
place(?c_place),
|
|
41
|
+
place(?d_place).
|
|
42
|
+
|
|
43
|
+
assigned(?var, [[?var, ?place] | ?], ?place).
|
|
44
|
+
assigned(?var, [bind(?var, ?place) | ?], ?place).
|
|
45
|
+
assigned(?var, [bind(?, ?) | ?rest], ?place) :- assigned(?var, ?rest, ?place).
|
|
46
|
+
|
|
47
|
+
% A conflict exists only when both interfering temporaries choose the same real
|
|
48
|
+
% register. Spilled temporaries do not occupy registers.
|
|
49
|
+
allocation_conflict(?allocation) :-
|
|
50
|
+
interferes(?left, ?right),
|
|
51
|
+
assigned(?left, ?allocation, ?reg),
|
|
52
|
+
assigned(?right, ?allocation, ?reg),
|
|
53
|
+
register(?reg).
|
|
54
|
+
|
|
55
|
+
valid_allocation(?allocation) :-
|
|
56
|
+
candidate_allocation(?allocation),
|
|
57
|
+
not(allocation_conflict(?allocation)).
|
|
58
|
+
|
|
59
|
+
spill_cost_of_place(?var, spill, ?cost) :- temporary(?var, ?cost).
|
|
60
|
+
spill_cost_of_place(?var, ?reg, 0) :- temporary(?var, ?), register(?reg).
|
|
61
|
+
|
|
62
|
+
allocation_cost(?allocation, ?cost) :-
|
|
63
|
+
findall(?item_cost,
|
|
64
|
+
(member(bind(?var, ?place), ?allocation), spill_cost_of_place(?var, ?place, ?item_cost)),
|
|
65
|
+
?costs),
|
|
66
|
+
sum_list(?costs, ?cost).
|
|
67
|
+
|
|
68
|
+
best_allocation(?allocation, ?cost) :-
|
|
69
|
+
aggregate_min([?candidate_cost, ?candidate], ?candidate,
|
|
70
|
+
(valid_allocation(?candidate), allocation_cost(?candidate, ?candidate_cost)),
|
|
71
|
+
[?cost, ?allocation], ?allocation).
|
|
72
|
+
|
|
73
|
+
registerAnswer(best_allocation, ?allocation) :- best_allocation(?allocation, ?).
|
|
74
|
+
registerAnswer(spill_cost, ?cost) :- best_allocation(?, ?cost).
|
|
75
|
+
registerAnswer(place(?var), ?place) :- best_allocation(?allocation, ?), assigned(?var, ?allocation, ?place).
|
|
76
|
+
registerAnswer(valid_allocation_count, ?count) :- countall(valid_allocation(?), ?count).
|
|
77
|
+
registerAnswer(note, "the cheapest solution spills b to color the a-b-c triangle with two registers") :- best_allocation(?, ?).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
% DPLL-style SAT solving for a small CNF formula.
|
|
2
|
+
%
|
|
3
|
+
% The example keeps the solver itself in Eyelang. It recursively assigns
|
|
4
|
+
% variables in a fixed order, prunes a branch as soon as any clause is already
|
|
5
|
+
% impossible, and accepts a complete assignment when every clause is satisfied.
|
|
6
|
+
% aggregate_min/5 is then used only to choose one canonical satisfying model.
|
|
7
|
+
|
|
8
|
+
materialize(satModel, 1).
|
|
9
|
+
materialize(satValue, 2).
|
|
10
|
+
materialize(satClauseStatus, 2).
|
|
11
|
+
materialize(satConclusion, 2).
|
|
12
|
+
|
|
13
|
+
% CNF formula:
|
|
14
|
+
% (a or b)
|
|
15
|
+
% (not a or c)
|
|
16
|
+
% (not b or c)
|
|
17
|
+
% (not c or d)
|
|
18
|
+
% (c or not d)
|
|
19
|
+
variable_order([a, b, c, d]).
|
|
20
|
+
clause(c1, [pos(a), pos(b)]).
|
|
21
|
+
clause(c2, [neg(a), pos(c)]).
|
|
22
|
+
clause(c3, [neg(b), pos(c)]).
|
|
23
|
+
clause(c4, [neg(c), pos(d)]).
|
|
24
|
+
clause(c5, [pos(c), neg(d)]).
|
|
25
|
+
|
|
26
|
+
bool(false).
|
|
27
|
+
bool(true).
|
|
28
|
+
bit(false, 0).
|
|
29
|
+
bit(true, 1).
|
|
30
|
+
|
|
31
|
+
% Look up a variable inside a partial or complete assignment represented as a
|
|
32
|
+
% list of bind(Name, Bool) terms.
|
|
33
|
+
lookup_bool(?name, [bind(?name, ?value) | ?], ?value).
|
|
34
|
+
lookup_bool(?name, [bind(?, ?) | ?rest], ?value) :- lookup_bool(?name, ?rest, ?value).
|
|
35
|
+
|
|
36
|
+
literal_true(pos(?var), ?assignment) :- lookup_bool(?var, ?assignment, true).
|
|
37
|
+
literal_true(neg(?var), ?assignment) :- lookup_bool(?var, ?assignment, false).
|
|
38
|
+
literal_false(pos(?var), ?assignment) :- lookup_bool(?var, ?assignment, false).
|
|
39
|
+
literal_false(neg(?var), ?assignment) :- lookup_bool(?var, ?assignment, true).
|
|
40
|
+
|
|
41
|
+
clause_satisfied(?assignment, ?clause_name) :-
|
|
42
|
+
clause(?clause_name, ?literals),
|
|
43
|
+
member(?literal, ?literals),
|
|
44
|
+
literal_true(?literal, ?assignment).
|
|
45
|
+
|
|
46
|
+
% A partial branch is impossible when every literal in a clause is already false.
|
|
47
|
+
% Unassigned literals keep the branch alive, just as in DPLL.
|
|
48
|
+
clause_impossible(?assignment, ?clause_name) :-
|
|
49
|
+
clause(?clause_name, ?literals),
|
|
50
|
+
forall(member(?literal, ?literals), literal_false(?literal, ?assignment)).
|
|
51
|
+
partial_consistent(?assignment) :- not((clause(?name, ?), clause_impossible(?assignment, ?name))).
|
|
52
|
+
complete_model(?assignment) :- forall(clause(?name, ?), clause_satisfied(?assignment, ?name)).
|
|
53
|
+
|
|
54
|
+
% Recursive DPLL search: choose a truth value, prune if inconsistent, then
|
|
55
|
+
% continue with the remaining variables.
|
|
56
|
+
dpll([], ?assignment, ?assignment) :- complete_model(?assignment).
|
|
57
|
+
dpll([?var | ?rest], ?partial, ?model) :-
|
|
58
|
+
bool(?value),
|
|
59
|
+
partial_consistent([bind(?var, ?value) | ?partial]),
|
|
60
|
+
dpll(?rest, [bind(?var, ?value) | ?partial], ?model).
|
|
61
|
+
|
|
62
|
+
satisfying_model(?model) :- variable_order(?vars), dpll(?vars, [], ?model).
|
|
63
|
+
|
|
64
|
+
% Rank models so the materialized output shows one deterministic answer. The
|
|
65
|
+
% model list is in reverse decision order because each decision is pushed onto
|
|
66
|
+
% the front during recursion.
|
|
67
|
+
model_rank(?model, ?rank) :-
|
|
68
|
+
lookup_bool(a, ?model, ?a), bit(?a, ?abit),
|
|
69
|
+
lookup_bool(b, ?model, ?b), bit(?b, ?bbit),
|
|
70
|
+
lookup_bool(c, ?model, ?c), bit(?c, ?cbit),
|
|
71
|
+
lookup_bool(d, ?model, ?d), bit(?d, ?dbit),
|
|
72
|
+
mul(?abit, 8, ?arank),
|
|
73
|
+
mul(?bbit, 4, ?brank),
|
|
74
|
+
mul(?cbit, 2, ?crank),
|
|
75
|
+
add(?arank, ?brank, ?ab),
|
|
76
|
+
add(?crank, ?dbit, ?cd),
|
|
77
|
+
add(?ab, ?cd, ?rank).
|
|
78
|
+
|
|
79
|
+
best_model(?model, ?rank) :-
|
|
80
|
+
aggregate_min(?candidate_rank, ?candidate_model,
|
|
81
|
+
(satisfying_model(?candidate_model), model_rank(?candidate_model, ?candidate_rank)),
|
|
82
|
+
?rank, ?model).
|
|
83
|
+
|
|
84
|
+
satModel(?model) :- best_model(?model, ?).
|
|
85
|
+
satValue(?var, ?value) :- best_model(?model, ?), lookup_bool(?var, ?model, ?value).
|
|
86
|
+
satClauseStatus(?clause, satisfied) :- best_model(?model, ?), clause_satisfied(?model, ?clause).
|
|
87
|
+
satConclusion(case, "DPLL finds a satisfying assignment after pruning clauses that become impossible") :-
|
|
88
|
+
best_model(?, ?).
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
% A tiny assumption-based truth maintenance system.
|
|
2
|
+
%
|
|
3
|
+
% An environment is a set of assumptions. Justifications derive beliefs from
|
|
4
|
+
% assumptions and from other derived beliefs. The TMS can therefore explain
|
|
5
|
+
% which environments support a belief and which environments are inconsistent
|
|
6
|
+
% because they support contradictory conclusions.
|
|
7
|
+
|
|
8
|
+
materialize(tmsSupport, 2).
|
|
9
|
+
materialize(tmsJustification, 3).
|
|
10
|
+
materialize(tmsInconsistent, 1).
|
|
11
|
+
materialize(tmsConclusion, 2).
|
|
12
|
+
|
|
13
|
+
table(supported, 2).
|
|
14
|
+
|
|
15
|
+
% Candidate environments.
|
|
16
|
+
environment(clear_only, [sensor_clear]).
|
|
17
|
+
environment(blocked_only, [sensor_blocked]).
|
|
18
|
+
environment(conflicting_sensors, [sensor_clear, sensor_blocked]).
|
|
19
|
+
environment(override_blocked, [sensor_blocked, operator_override]).
|
|
20
|
+
|
|
21
|
+
assumes(?environment, ?assumption) :-
|
|
22
|
+
environment(?environment, ?assumptions),
|
|
23
|
+
member(?assumption, ?assumptions).
|
|
24
|
+
|
|
25
|
+
% Justifications. Preconditions are either assumption(Name) or another derived
|
|
26
|
+
% belief. The last justification says an operator override can permit motion
|
|
27
|
+
% even when the blocked-path belief is also present.
|
|
28
|
+
justification(j_clear_path, [assumption(sensor_clear)], clear_path).
|
|
29
|
+
justification(j_blocked_path, [assumption(sensor_blocked)], blocked_path).
|
|
30
|
+
justification(j_permit_from_clear, [clear_path], permit_go).
|
|
31
|
+
justification(j_forbid_from_blocked, [blocked_path], forbid_go).
|
|
32
|
+
justification(j_override, [assumption(operator_override), blocked_path], permit_go).
|
|
33
|
+
|
|
34
|
+
all_hold(?, []).
|
|
35
|
+
all_hold(?environment, [assumption(?assumption) | ?rest]) :-
|
|
36
|
+
assumes(?environment, ?assumption),
|
|
37
|
+
all_hold(?environment, ?rest).
|
|
38
|
+
all_hold(?environment, [?belief | ?rest]) :-
|
|
39
|
+
supported(?environment, ?belief),
|
|
40
|
+
all_hold(?environment, ?rest).
|
|
41
|
+
|
|
42
|
+
supported(?environment, ?belief) :-
|
|
43
|
+
justification(?, ?preconditions, ?belief),
|
|
44
|
+
all_hold(?environment, ?preconditions).
|
|
45
|
+
|
|
46
|
+
contradicts(permit_go, forbid_go).
|
|
47
|
+
contradicts(forbid_go, permit_go).
|
|
48
|
+
inconsistent(?environment) :-
|
|
49
|
+
supported(?environment, ?left),
|
|
50
|
+
supported(?environment, ?right),
|
|
51
|
+
contradicts(?left, ?right).
|
|
52
|
+
|
|
53
|
+
% Show the actual justifications that fired, not just the final supported beliefs.
|
|
54
|
+
fires(?environment, ?justification, ?belief) :-
|
|
55
|
+
justification(?justification, ?preconditions, ?belief),
|
|
56
|
+
all_hold(?environment, ?preconditions).
|
|
57
|
+
|
|
58
|
+
tmsSupport(?environment, ?belief) :- supported(?environment, ?belief).
|
|
59
|
+
tmsJustification(?environment, ?justification, ?belief) :- fires(?environment, ?justification, ?belief).
|
|
60
|
+
tmsInconsistent(?environment) :- inconsistent(?environment).
|
|
61
|
+
tmsConclusion(case, "truth maintenance separates support from consistency across assumption environments") :-
|
|
62
|
+
inconsistent(conflicting_sensors).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
% Hindley-Milner-style type inference for a tiny lambda language.
|
|
2
|
+
%
|
|
3
|
+
% The example is intentionally small and deterministic. Lambda binders carry
|
|
4
|
+
% explicit type variables or annotations, and ordinary logic unification solves
|
|
5
|
+
% the constraints created by application, arithmetic, conditionals, and pairs.
|
|
6
|
+
% The symbolic names t0, t1, and t2 stand for schematic type variables in the
|
|
7
|
+
% displayed answers; concrete examples such as apply_id annotate the argument as
|
|
8
|
+
% int so the application can be checked.
|
|
9
|
+
materialize(type_answer, 2).
|
|
10
|
+
materialize(type_reason, 2).
|
|
11
|
+
|
|
12
|
+
table(type_expr, 3).
|
|
13
|
+
|
|
14
|
+
% Tiny expression language: int_lit/1, bool_lit/1, var/1, lam/3, app/2,
|
|
15
|
+
% add/2, if/3, pair/2, fst/1, and snd/1.
|
|
16
|
+
program(id, lam(x, t0, var(x))).
|
|
17
|
+
program(const, lam(x, t0, lam(y, t1, var(x)))).
|
|
18
|
+
program(apply_id, app(lam(x, int, var(x)), int_lit(42))).
|
|
19
|
+
program(compose,
|
|
20
|
+
lam(f, fun(t1, t2),
|
|
21
|
+
lam(g, fun(t0, t1),
|
|
22
|
+
lam(x, t0,
|
|
23
|
+
app(var(f), app(var(g), var(x))))))).
|
|
24
|
+
program(branch,
|
|
25
|
+
if(bool_lit(true), add(int_lit(20), int_lit(22)), int_lit(0))).
|
|
26
|
+
program(first_of_pair, fst(pair(bool_lit(true), int_lit(7)))).
|
|
27
|
+
|
|
28
|
+
lookup(?name, [[?name, ?type] | ?], ?type).
|
|
29
|
+
lookup(?name, [[?, ?] | ?rest], ?type) :- lookup(?name, ?rest, ?type).
|
|
30
|
+
|
|
31
|
+
type_expr(?, int_lit(?), int).
|
|
32
|
+
type_expr(?, bool_lit(?), bool).
|
|
33
|
+
type_expr(?env, var(?name), ?type) :- lookup(?name, ?env, ?type).
|
|
34
|
+
type_expr(?env, lam(?name, ?arg_type, ?body), fun(?arg_type, ?body_type)) :-
|
|
35
|
+
type_expr([[?name, ?arg_type] | ?env], ?body, ?body_type).
|
|
36
|
+
type_expr(?env, app(?fn, ?arg), ?result_type) :-
|
|
37
|
+
type_expr(?env, ?fn, fun(?arg_type, ?result_type)),
|
|
38
|
+
type_expr(?env, ?arg, ?arg_type).
|
|
39
|
+
type_expr(?env, add(?left, ?right), int) :-
|
|
40
|
+
type_expr(?env, ?left, int),
|
|
41
|
+
type_expr(?env, ?right, int).
|
|
42
|
+
type_expr(?env, if(?cond, ?then, ?else), ?type) :-
|
|
43
|
+
type_expr(?env, ?cond, bool),
|
|
44
|
+
type_expr(?env, ?then, ?type),
|
|
45
|
+
type_expr(?env, ?else, ?type).
|
|
46
|
+
type_expr(?env, pair(?left, ?right), pair(?left_type, ?right_type)) :-
|
|
47
|
+
type_expr(?env, ?left, ?left_type),
|
|
48
|
+
type_expr(?env, ?right, ?right_type).
|
|
49
|
+
type_expr(?env, fst(?pair), ?left_type) :-
|
|
50
|
+
type_expr(?env, ?pair, pair(?left_type, ?)).
|
|
51
|
+
type_expr(?env, snd(?pair), ?right_type) :-
|
|
52
|
+
type_expr(?env, ?pair, pair(?, ?right_type)).
|
|
53
|
+
|
|
54
|
+
type_answer(?name, ?type) :- program(?name, ?expr), type_expr([], ?expr, ?type).
|
|
55
|
+
type_reason(compose, "application unifies f with t1 -> t2 and g with t0 -> t1") :-
|
|
56
|
+
type_answer(compose, ?).
|
|
57
|
+
type_reason(apply_id, "the identity function's parameter type is unified with int") :-
|
|
58
|
+
type_answer(apply_id, int).
|
package/package.json
CHANGED
package/playground.html
CHANGED
|
@@ -434,6 +434,7 @@
|
|
|
434
434
|
|
|
435
435
|
<script type="module">
|
|
436
436
|
const EXAMPLES = [
|
|
437
|
+
"abstract-interpretation",
|
|
437
438
|
"access-control-policy",
|
|
438
439
|
"ackermann",
|
|
439
440
|
"age",
|
|
@@ -458,6 +459,7 @@
|
|
|
458
459
|
"canary-release",
|
|
459
460
|
"cat-koko",
|
|
460
461
|
"catalan-convolution",
|
|
462
|
+
"cdcl-sat-solver",
|
|
461
463
|
"chart-parser",
|
|
462
464
|
"clinical-trial-screening",
|
|
463
465
|
"collatz-1000",
|
|
@@ -493,6 +495,7 @@
|
|
|
493
495
|
"drone-corridor-planner",
|
|
494
496
|
"easter-computus",
|
|
495
497
|
"electrical-rc-filter",
|
|
498
|
+
"equality-saturation",
|
|
496
499
|
"epidemic-policy",
|
|
497
500
|
"equivalence-classes-overlap-implies-same-class",
|
|
498
501
|
"eulerian-path",
|
|
@@ -530,6 +533,7 @@
|
|
|
530
533
|
"intuitionistic-logic-kripke",
|
|
531
534
|
"job-shop-scheduling",
|
|
532
535
|
"knapsack-optimization",
|
|
536
|
+
"knuth-bendix-completion",
|
|
533
537
|
"knowledge-engineering-alignment-flow",
|
|
534
538
|
"language",
|
|
535
539
|
"law-of-cosines",
|
|
@@ -557,19 +561,23 @@
|
|
|
557
561
|
"odrl-dpv-risk-ranked",
|
|
558
562
|
"orbital-transfer-design",
|
|
559
563
|
"path-discovery",
|
|
564
|
+
"partial-evaluator",
|
|
560
565
|
"peano-arithmetic",
|
|
561
566
|
"peano-calculus",
|
|
562
567
|
"peasant",
|
|
563
568
|
"pell-equation",
|
|
564
569
|
"pendulum-period",
|
|
570
|
+
"pointer-analysis",
|
|
565
571
|
"polynomial",
|
|
566
572
|
"prime-range",
|
|
567
573
|
"proof-contrapositive",
|
|
568
574
|
"quadratic-formula",
|
|
569
575
|
"radioactive-decay",
|
|
576
|
+
"register-allocation",
|
|
570
577
|
"reusable-builtins",
|
|
571
578
|
"riemann-hypothesis",
|
|
572
579
|
"route-planning",
|
|
580
|
+
"sat-solver-dpll",
|
|
573
581
|
"security-incident-correlation",
|
|
574
582
|
"send-more-money",
|
|
575
583
|
"service-impact",
|
|
@@ -588,6 +596,8 @@
|
|
|
588
596
|
"term-tools",
|
|
589
597
|
"totient-summatory",
|
|
590
598
|
"trust-flow-provenance-threshold",
|
|
599
|
+
"truth-maintenance-system",
|
|
600
|
+
"type-inference",
|
|
591
601
|
"turing",
|
|
592
602
|
"vector-similarity",
|
|
593
603
|
"vulnerability-impact",
|