eyeling 1.33.7 → 1.33.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -829,7 +829,7 @@ The eyelang engine has its own built-in registry under `lib/eyelang/builtins/`.
829
829
  | Aggregation | `findall/3`, `countall/2`, `sumall/3`, `aggregate_min/5`, `aggregate_max/5` |
830
830
  | Control | `not/1`, `once/1` |
831
831
  | Context terms | `holds/2`, `holds/3` |
832
- | Search and optimization helpers | `n_queens/2`, `weighted_hamiltonian_cycle/4`, `weighted_hamiltonian_path/4`, `hamiltonian_cycle/3`, `fixed_length_cycle/4`, `bounded_path/5`, `bounded_subset/7`, `cnf_model/3`, `qm_prime_implicants/4`, `qm_minimal_cover/4`, `alphametic_sum/5` |
832
+ | Search and optimization helpers | `n_queens/2`, `weighted_hamiltonian_cycle/4`, `weighted_hamiltonian_path/4`, `hamiltonian_cycle/3`, `fixed_length_cycle/4`, `bounded_path/5`, `cnf_model/3`, `qm_prime_implicants/4`, `qm_minimal_cover/4` |
833
833
  | Numeric extension helpers | `extended_gcd/5`, `collatz_trajectory/2`, `kaprekar_steps/2`, `goldbach_pair/3` |
834
834
  | Matrix helpers | `matrix_sum/2`, `matrix_multiply/2`, `cholesky_decomposition/2`, `determinant/2`, `matrix_inv_triang/2`, `matrix_inversion/2` |
835
835
 
@@ -261,7 +261,7 @@ best(Cycle, Cost) :-
261
261
  weighted_hamiltonian_cycle(edge, Cities, Cycle, Cost).
262
262
  ```
263
263
 
264
- The reusable search and numeric helpers include `n_queens/2`, Hamiltonian path/cycle helpers, `cnf_model/3`, Quine-McCluskey helpers, bounded subset/path helpers, number-theory helpers such as `extended_gcd/5`, matrix helpers such as `matrix_multiply/2`, and `alphametic_sum/5`. These helpers are extension builtins of this implementation; [the eyelang language reference](eyelang-language-reference.md) defines the portable core and standard builtin profile.
264
+ The reusable search and numeric helpers include `n_queens/2`, Hamiltonian path/cycle helpers, `bounded_path/5`, `cnf_model/3`, Quine-McCluskey helpers, number-theory helpers such as `extended_gcd/5`, and matrix helpers such as `matrix_multiply/2`. These helpers are extension builtins of this implementation; [the eyelang language reference](eyelang-language-reference.md) defines the portable core and standard builtin profile.
265
265
 
266
266
  To add a builtin, create or extend a module with `register(registry)` and call `registry.add(name, arity, handler, options)`. The default registry is assembled in [`lib/eyelang/builtins/registry.js`](../lib/eyelang/builtins/registry.js). Builtins that are only safe for specific argument modes should provide a `ready` predicate and `fallbackWhenNotReady: true`, so user-defined clauses remain visible until the builtin is applicable.
267
267
 
@@ -336,7 +336,6 @@ The repository includes examples for recursion, graph reachability, finite searc
336
336
  | [`composition-of-injective-functions-is-injective.pl`](../examples/eyelang/composition-of-injective-functions-is-injective.pl) | Encodes composition and injectivity of finite functions. | [`output/composition-of-injective-functions-is-injective.pl`](../examples/eyelang/output/composition-of-injective-functions-is-injective.pl) |
337
337
  | [`context-association.pl`](../examples/eyelang/context-association.pl) | Associates named contexts with their contents. | [`output/context-association.pl`](../examples/eyelang/output/context-association.pl) |
338
338
  | [`control-system.pl`](../examples/eyelang/control-system.pl) | Evaluates control-system measurements and targets. | [`output/control-system.pl`](../examples/eyelang/output/control-system.pl) |
339
- | [`cryptarithmetic-send-more-money.pl`](../examples/eyelang/cryptarithmetic-send-more-money.pl) | Solves SEND+MORE and related puzzles. | [`output/cryptarithmetic-send-more-money.pl`](../examples/eyelang/output/cryptarithmetic-send-more-money.pl) |
340
339
  | [`cyclic-path.pl`](../examples/eyelang/cyclic-path.pl) | Computes paths in a cyclic graph. | [`output/cyclic-path.pl`](../examples/eyelang/output/cyclic-path.pl) |
341
340
  | [`d3-group.pl`](../examples/eyelang/d3-group.pl) | Enumerates subgroups of the D3 group. | [`output/d3-group.pl`](../examples/eyelang/output/d3-group.pl) |
342
341
  | [`dairy-energy-balance.pl`](../examples/eyelang/dairy-energy-balance.pl) | Classifies dairy cow energy balance. | [`output/dairy-energy-balance.pl`](../examples/eyelang/output/dairy-energy-balance.pl) |
@@ -415,12 +414,10 @@ The repository includes examples for recursion, graph reachability, finite searc
415
414
  | [`peasant.pl`](../examples/eyelang/peasant.pl) | Performs peasant multiplication and exponentiation. | [`output/peasant.pl`](../examples/eyelang/output/peasant.pl) |
416
415
  | [`pendulum-period.pl`](../examples/eyelang/pendulum-period.pl) | Computes simple pendulum periods. | [`output/pendulum-period.pl`](../examples/eyelang/output/pendulum-period.pl) |
417
416
  | [`polynomial.pl`](../examples/eyelang/polynomial.pl) | Finds complex integer polynomial roots. | [`output/polynomial.pl`](../examples/eyelang/output/polynomial.pl) |
418
- | [`project-portfolio-optimization.pl`](../examples/eyelang/project-portfolio-optimization.pl) | Optimizes a constrained project portfolio with pruning and aggregate builtins. | [`output/project-portfolio-optimization.pl`](../examples/eyelang/output/project-portfolio-optimization.pl) |
419
417
  | [`proof-contrapositive.pl`](../examples/eyelang/proof-contrapositive.pl) | Models proof by contrapositive. | [`output/proof-contrapositive.pl`](../examples/eyelang/output/proof-contrapositive.pl) |
420
418
  | [`quadratic-formula.pl`](../examples/eyelang/quadratic-formula.pl) | Solves sample quadratic equations. | [`output/quadratic-formula.pl`](../examples/eyelang/output/quadratic-formula.pl) |
421
419
  | [`quine-mccluskey.pl`](../examples/eyelang/quine-mccluskey.pl) | Minimizes Boolean terms with Quine-McCluskey. | [`output/quine-mccluskey.pl`](../examples/eyelang/output/quine-mccluskey.pl) |
422
420
  | [`radioactive-decay.pl`](../examples/eyelang/radioactive-decay.pl) | Computes radioactive decay over time. | [`output/radioactive-decay.pl`](../examples/eyelang/output/radioactive-decay.pl) |
423
- | [`resilient-city-orchestration.pl`](../examples/eyelang/resilient-city-orchestration.pl) | Orchestrates storm-response missions from signals, policy, routes, teams, and portfolio optimization. | [`output/resilient-city-orchestration.pl`](../examples/eyelang/output/resilient-city-orchestration.pl) |
424
421
  | [`riemann-hypothesis.pl`](../examples/eyelang/riemann-hypothesis.pl) | Checks a finite catalogue of non-trivial zeta zeros against the Riemann-hypothesis condition. | [`output/riemann-hypothesis.pl`](../examples/eyelang/output/riemann-hypothesis.pl) |
425
422
  | [`sat-dpll.pl`](../examples/eyelang/sat-dpll.pl) | Solves a finite SAT instance. | [`output/sat-dpll.pl`](../examples/eyelang/output/sat-dpll.pl) |
426
423
  | [`security-incident-correlation.pl`](../examples/eyelang/security-incident-correlation.pl) | Correlates security incidents across signals. | [`output/security-incident-correlation.pl`](../examples/eyelang/output/security-incident-correlation.pl) |
@@ -468,7 +468,7 @@ An extension built-in SHOULD obey the same surface-language discipline as standa
468
468
  - it SHOULD document its intended modes, especially which arguments must be ground before it runs deterministically;
469
469
  - it MUST NOT change the meaning of ordinary facts, rules, unification, or standard built-ins.
470
470
 
471
- For example, an implementation may include extension modules for portfolio selection, number-theory algorithms, graph search, matrix operations, or alphametic puzzles. Those modules may be valuable and may make example programs much faster, but their predicate names, arities, algorithms, and modes are implementation-defined unless they are separately standardized.
471
+ For example, an implementation may include extension modules for number-theory algorithms, graph search, or matrix operations. Those modules may be valuable and may make example programs much faster, but their predicate names, arities, algorithms, and modes are implementation-defined unless they are separately standardized.
472
472
 
473
473
  An implementation that provides explanation output SHOULD make extension built-ins explainable at least as opaque successful or failed built-in calls, so that proof traces do not incorrectly report "no clauses" for a host-provided relation.
474
474
 
@@ -7,11 +7,9 @@ import { listBuiltins } from './lists.js';
7
7
  import { aggregationBuiltins } from './aggregation.js';
8
8
  import { contextBuiltins } from './context.js';
9
9
  import { controlBuiltins } from './control.js';
10
- import { portfolioBuiltins } from './portfolio.js';
11
10
  import { searchBuiltins } from './search.js';
12
11
  import { numberTheoryBuiltins } from './number-theory.js';
13
12
  import { matrixBuiltins } from './matrix.js';
14
- import { alphameticBuiltins } from './alphametic.js';
15
13
 
16
14
  export class BuiltinRegistry {
17
15
  constructor() {
@@ -38,7 +36,7 @@ export class BuiltinRegistry {
38
36
 
39
37
  export function createDefaultRegistry() {
40
38
  const registry = new BuiltinRegistry();
41
- for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, contextBuiltins, controlBuiltins, portfolioBuiltins, searchBuiltins, numberTheoryBuiltins, matrixBuiltins, alphameticBuiltins]) {
39
+ for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, contextBuiltins, controlBuiltins, searchBuiltins, numberTheoryBuiltins, matrixBuiltins]) {
42
40
  mod.register(registry);
43
41
  }
44
42
  return registry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.33.7",
3
+ "version": "1.33.9",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
@@ -1,49 +0,0 @@
1
- % Cryptarithmetic without cut.
2
- %
3
- % Two column-pruned puzzles are included. SEND + MORE = MONEY is the classic
4
- % eight-letter puzzle, and DONALD + GERALD = ROBERT uses all ten digits across
5
- % a six-column addition. Each column constraint is applied as soon as possible
6
- % so the finite digit search prunes early without cut.
7
-
8
- % Output declarations: materialize/2 selects the relations written to this example's golden output.
9
- materialize(status, 2).
10
- materialize(assignment, 2).
11
- materialize(equation, 2).
12
-
13
- % Program structure: facts set up the scenario, and rules derive the materialized conclusions.
14
- % Derivation rules: each rule below contributes one logical step toward the displayed results.
15
- send_more_money(solution(S, E, N, D, M, O, R, Y), Send, More, Money) :-
16
- alphametic_sum(
17
- [s, e, n, d, m, o, r, y],
18
- [[s, e, n, d], [m, o, r, e]],
19
- [m, o, n, e, y],
20
- [S, E, N, D, M, O, R, Y],
21
- [Send, More, Money]
22
- ).
23
-
24
- donald_gerald_robert(solution(D, O, N, A, L, G, E, R, B, T), Donald, Gerald, Robert) :-
25
- alphametic_sum(
26
- [d, o, n, a, l, g, e, r, b, t],
27
- [[d, o, n, a, l, d], [g, e, r, a, l, d]],
28
- [r, o, b, e, r, t],
29
- [D, O, N, A, L, G, E, R, B, T],
30
- [Donald, Gerald, Robert]
31
- ).
32
-
33
- status(send_more_money, solved) :-
34
- once(send_more_money(_Solution, _Send, _More, _Money)).
35
-
36
- assignment(send_more_money, Solution) :-
37
- once(send_more_money(Solution, _Send, _More, _Money)).
38
-
39
- equation(send_more_money, plus(Send, More, Money)) :-
40
- once(send_more_money(_Solution, Send, More, Money)).
41
-
42
- status(donald_gerald_robert, solved) :-
43
- once(donald_gerald_robert(_Solution, _Donald, _Gerald, _Robert)).
44
-
45
- assignment(donald_gerald_robert, Solution) :-
46
- once(donald_gerald_robert(Solution, _Donald, _Gerald, _Robert)).
47
-
48
- equation(donald_gerald_robert, plus(Donald, Gerald, Robert)) :-
49
- once(donald_gerald_robert(_Solution, Donald, Gerald, Robert)).
@@ -1,6 +0,0 @@
1
- status(send_more_money, solved).
2
- status(donald_gerald_robert, solved).
3
- assignment(send_more_money, solution(9, 5, 6, 7, 1, 0, 8, 2)).
4
- assignment(donald_gerald_robert, solution(5, 2, 6, 4, 8, 1, 9, 7, 3, 0)).
5
- equation(send_more_money, plus(9567, 1085, 10652)).
6
- equation(donald_gerald_robert, plus(526485, 197485, 723970)).
@@ -1,6 +0,0 @@
1
- bestPortfolio(portfolio2026, result(137, 75, 28, [solar, hvac, training, quality, recycling, cloud, security])).
2
- lowRiskTarget(portfolio2026, result(126, 74, 23, [solar, battery, hvac, training, quality, cloud])).
3
- feasibleCount(portfolio2026, 1390).
4
- projectCount(portfolio2026, 12).
5
- totalAvailableValue(portfolio2026, 268).
6
- note(portfolio2026, "aggregate builtins combine with pruning and memoization to avoid sorted candidate bags").
@@ -1,67 +0,0 @@
1
- incidentSummary(civic_storm, summary("CivicStorm Alpha", "protect people, medicine, and power without using prohibited surveillance", budget(105), riskCap(60))).
2
- activeSignal(civic_storm, river_surge).
3
- activeSignal(civic_storm, hospital_power_risk).
4
- activeSignal(civic_storm, medicine_cold_chain_risk).
5
- activeSignal(civic_storm, grid_stress).
6
- criticalNeed(civic_storm, evacuate_hospital).
7
- criticalNeed(civic_storm, deliver_medicine).
8
- criticalNeed(civic_storm, stabilize_substation).
9
- criticalNeed(civic_storm, open_shelter).
10
- criticalNeed(civic_storm, map_flood_front).
11
- policyClearance(medical_transport, deploy).
12
- policyClearance(cold_chain, deploy).
13
- policyClearance(grid_repair, deploy).
14
- policyClearance(shelter_ops, deploy).
15
- policyClearance(drone_mapping, deploy).
16
- policyClearance(public_info, deploy).
17
- usableRoute(hospital_quay, route([base, north_gate, hospital_quay], minutes(22), risk(9))).
18
- usableRoute(clinic_east, route([base, cold_depot, clinic_east], minutes(19), risk(5))).
19
- usableRoute(substation_east, route([base, north_gate, substation_east], minutes(31), risk(10))).
20
- usableRoute(high_school, route([base, civic_center, high_school], minutes(17), risk(4))).
21
- usableRoute(riverside, route([base, civic_center, riverside], minutes(21), risk(6))).
22
- usableRoute(civic_square, route([base, civic_center, civic_square], minutes(15), risk(3))).
23
- eligibleAssignment(evacuate_hospital, assignment(alpha_ambulance, [base, north_gate, hospital_quay])).
24
- eligibleAssignment(deliver_insulin, assignment(beta_coldchain, [base, cold_depot, clinic_east])).
25
- eligibleAssignment(stabilize_substation, assignment(delta_grid, [base, north_gate, substation_east])).
26
- eligibleAssignment(open_school_shelter, assignment(gamma_shelter, [base, civic_center, high_school])).
27
- eligibleAssignment(map_flood_front, assignment(echo_drone, [base, civic_center, riverside])).
28
- eligibleAssignment(public_dashboard, assignment(foxtrot_comms, [base, civic_center, civic_square])).
29
- candidateMission(evacuate_hospital, score(95, 34, 14, alpha_ambulance, [base, north_gate, hospital_quay])).
30
- candidateMission(deliver_insulin, score(70, 16, 9, beta_coldchain, [base, cold_depot, clinic_east])).
31
- candidateMission(stabilize_substation, score(85, 25, 18, delta_grid, [base, north_gate, substation_east])).
32
- candidateMission(open_school_shelter, score(60, 14, 6, gamma_shelter, [base, civic_center, high_school])).
33
- candidateMission(map_flood_front, score(45, 8, 8, echo_drone, [base, civic_center, riverside])).
34
- candidateMission(public_dashboard, score(28, 12, 4, foxtrot_comms, [base, civic_center, civic_square])).
35
- blockedMission(face_scan_crowds, policy_prohibition).
36
- blockedMission(resupply_west_bank, route_risk_too_high).
37
- bestResponse(civic_storm, response(value(355), cost(97), risk(55), missions([evacuate_hospital, deliver_insulin, stabilize_substation, open_school_shelter, map_flood_front]))).
38
- selectedMission(civic_storm, evacuate_hospital).
39
- selectedMission(civic_storm, deliver_insulin).
40
- selectedMission(civic_storm, stabilize_substation).
41
- selectedMission(civic_storm, open_school_shelter).
42
- selectedMission(civic_storm, map_flood_front).
43
- selectedTeam(evacuate_hospital, alpha_ambulance).
44
- selectedTeam(deliver_insulin, beta_coldchain).
45
- selectedTeam(stabilize_substation, delta_grid).
46
- selectedTeam(open_school_shelter, gamma_shelter).
47
- selectedTeam(map_flood_front, echo_drone).
48
- selectedRoute(evacuate_hospital, [base, north_gate, hospital_quay]).
49
- selectedRoute(deliver_insulin, [base, cold_depot, clinic_east]).
50
- selectedRoute(stabilize_substation, [base, north_gate, substation_east]).
51
- selectedRoute(open_school_shelter, [base, civic_center, high_school]).
52
- selectedRoute(map_flood_front, [base, civic_center, riverside]).
53
- coveredNeed(civic_storm, evacuate_hospital).
54
- coveredNeed(civic_storm, deliver_medicine).
55
- coveredNeed(civic_storm, stabilize_substation).
56
- coveredNeed(civic_storm, open_shelter).
57
- coveredNeed(civic_storm, map_flood_front).
58
- unmetNeed(civic_storm, none).
59
- readinessCheck(civic_storm, all_critical_needs_covered).
60
- readinessCheck(civic_storm, budget_and_risk_caps_respected).
61
- readinessCheck(civic_storm, prohibited_surveillance_rejected).
62
- readinessCheck(civic_storm, dangerous_west_bank_route_rejected).
63
- auditTrail(civic_storm, "raw sensor thresholds derive operational needs before search").
64
- auditTrail(civic_storm, "policy formula data is projected into deployable skill clearances").
65
- auditTrail(civic_storm, "bounded route search and team capabilities create candidate missions").
66
- auditTrail(civic_storm, "bounded_subset and aggregate_max choose the highest-value safe portfolio").
67
- recommendation(civic_storm, "activate the selected mission portfolio; do not deploy face recognition; defer west-bank resupply until route risk drops").
@@ -1,101 +0,0 @@
1
- % Capital project portfolio optimization.
2
- %
3
- % This is a practical finite-search benchmark: enumerate project portfolios
4
- % under budget and risk caps, pruning infeasible branches as cost and risk
5
- % accumulate, then use aggregate builtins to select useful optima without
6
- % building and sorting a large bag of candidate portfolios.
7
-
8
- % Output declarations: materialize/2 selects the relations written to this example's golden output.
9
- materialize(bestPortfolio, 2).
10
- materialize(lowRiskTarget, 2).
11
- materialize(feasibleCount, 2).
12
- materialize(projectCount, 2).
13
- materialize(totalAvailableValue, 2).
14
- materialize(note, 2).
15
-
16
- % Program structure: facts set up the scenario, and rules derive the materialized conclusions.
17
- budget(portfolio2026, 75).
18
- riskCap(portfolio2026, 28).
19
- targetValue(portfolio2026, 125).
20
-
21
- allProjectData([
22
- p(solar, 22, 15, 4),
23
- p(battery, 28, 20, 5),
24
- p(hvac, 20, 13, 3),
25
- p(analytics, 18, 8, 7),
26
- p(training, 16, 6, 2),
27
- p(robotics, 35, 30, 9),
28
- p(iot, 24, 12, 8),
29
- p(quality, 19, 9, 4),
30
- p(resilience, 26, 18, 6),
31
- p(recycling, 14, 5, 3),
32
- p(cloud, 21, 11, 5),
33
- p(security, 25, 16, 7)
34
- ]).
35
-
36
- % Derivation rules: each rule below contributes one logical step toward the displayed results.
37
- project(Name, Value, Cost, Risk) :-
38
- allProjectData(Projects),
39
- member(p(Name, Value, Cost, Risk), Projects).
40
-
41
- % Cache this finite relation so bestPortfolio/2, lowRiskTarget/2, and
42
- % feasibleCount/2 do not re-enumerate the same search space independently.
43
- memoize(feasiblePortfolio, 4).
44
-
45
- choosePortfolio([], _BudgetLeft, _RiskLeft, [], 0, 0, 0).
46
- choosePortfolio([p(Name, ProjectValue, ProjectCost, ProjectRisk) | Rest], BudgetLeft, RiskLeft, [Name | Chosen], Value, Cost, Risk) :-
47
- le(ProjectCost, BudgetLeft),
48
- le(ProjectRisk, RiskLeft),
49
- sub(BudgetLeft, ProjectCost, NextBudget),
50
- sub(RiskLeft, ProjectRisk, NextRisk),
51
- choosePortfolio(Rest, NextBudget, NextRisk, Chosen, RestValue, RestCost, RestRisk),
52
- add(ProjectValue, RestValue, Value),
53
- add(ProjectCost, RestCost, Cost),
54
- add(ProjectRisk, RestRisk, Risk).
55
- choosePortfolio([_Project | Rest], BudgetLeft, RiskLeft, Chosen, Value, Cost, Risk) :-
56
- choosePortfolio(Rest, BudgetLeft, RiskLeft, Chosen, Value, Cost, Risk).
57
-
58
- feasiblePortfolio(Selected, Value, Cost, Risk) :-
59
- budget(portfolio2026, Budget),
60
- riskCap(portfolio2026, Cap),
61
- allProjectData(Projects),
62
- bounded_subset(Projects, Budget, Cap, Selected, Value, Cost, Risk),
63
- gt(Value, 0).
64
-
65
- scoredPortfolio(Selected, Value, Cost, Risk, NegCost, NegRisk) :-
66
- feasiblePortfolio(Selected, Value, Cost, Risk),
67
- neg(Cost, NegCost),
68
- neg(Risk, NegRisk).
69
-
70
- targetPortfolio(Target, Selected, Value, Cost, Risk) :-
71
- feasiblePortfolio(Selected, Value, Cost, Risk),
72
- ge(Value, Target).
73
-
74
- bestPortfolio(portfolio2026, result(Value, Cost, Risk, Selected)) :-
75
- aggregate_max(
76
- [Value, NegCost, NegRisk, Selected],
77
- result(Value, Cost, Risk, Selected),
78
- scoredPortfolio(Selected, Value, Cost, Risk, NegCost, NegRisk),
79
- _Key,
80
- result(Value, Cost, Risk, Selected)).
81
-
82
- lowRiskTarget(portfolio2026, result(Value, Cost, Risk, Selected)) :-
83
- targetValue(portfolio2026, Target),
84
- aggregate_min(
85
- [Risk, Cost, Selected],
86
- result(Value, Cost, Risk, Selected),
87
- targetPortfolio(Target, Selected, Value, Cost, Risk),
88
- _Key,
89
- result(Value, Cost, Risk, Selected)).
90
-
91
- feasibleCount(portfolio2026, Count) :-
92
- countall(feasiblePortfolio(_Selected, _Value, _Cost, _Risk), Count).
93
-
94
- projectCount(portfolio2026, Count) :-
95
- countall(project(_Name, _Value, _Cost, _Risk), Count).
96
-
97
- totalAvailableValue(portfolio2026, Total) :-
98
- sumall(Value, project(_Name, Value, _Cost, _Risk), Total).
99
-
100
- note(portfolio2026, "aggregate builtins combine with pruning and memoization to avoid sorted candidate bags") :-
101
- eq(ok, ok).
@@ -1,303 +0,0 @@
1
- % Resilient-city orchestration scenario.
2
- %
3
- % This example is intentionally richer than a single puzzle. It combines raw
4
- % incident signals, policy-as-data, route search, team capabilities, negation,
5
- % aggregation, finite optimization, and materialized audit output. The result is
6
- % a compact declarative emergency plan: facts describe the world; rules decide
7
- % which missions are lawful, reachable, and worth funding under cost/risk caps.
8
-
9
- % Output declarations: materialize/2 selects the relations written to this example's golden output.
10
- materialize(incidentSummary, 2).
11
- materialize(activeSignal, 2).
12
- materialize(criticalNeed, 2).
13
- materialize(policyClearance, 2).
14
- materialize(usableRoute, 2).
15
- materialize(eligibleAssignment, 2).
16
- materialize(candidateMission, 2).
17
- materialize(blockedMission, 2).
18
- materialize(bestResponse, 2).
19
- materialize(selectedMission, 2).
20
- materialize(selectedTeam, 2).
21
- materialize(selectedRoute, 2).
22
- materialize(coveredNeed, 2).
23
- materialize(unmetNeed, 2).
24
- materialize(readinessCheck, 2).
25
- materialize(auditTrail, 2).
26
- materialize(recommendation, 2).
27
-
28
- % Program structure: facts set up the storm response, and rules derive the final plan.
29
- incident(civic_storm).
30
- incident_label(civic_storm, "CivicStorm Alpha").
31
- incident_goal(civic_storm, "protect people, medicine, and power without using prohibited surveillance").
32
- budget_cap(civic_storm, 105).
33
- risk_cap(civic_storm, 60).
34
- route_risk_cap(civic_storm, 20).
35
- route_minutes_cap(civic_storm, 45).
36
-
37
- % Sensor readings are deliberately low-level; rules below turn them into needs.
38
- reading(river_gauge_cm, 318).
39
- threshold(river_gauge_cm, 280).
40
- reading(hospital_generator_hours, 5).
41
- threshold_low(hospital_generator_hours, 8).
42
- reading(clinic_refrigerator_hours, 4).
43
- threshold_low(clinic_refrigerator_hours, 6).
44
- reading(substation_load_percent, 94).
45
- threshold(substation_load_percent, 85).
46
-
47
- % The deployable skills are stored as quoted formula data and projected by
48
- % holds/2, showing how policy documents can be reasoned over as data.
49
- policy_bundle(response_policy, (
50
- permission(medical_transport, deploy),
51
- permission(cold_chain, deploy),
52
- permission(grid_repair, deploy),
53
- permission(shelter_ops, deploy),
54
- permission(drone_mapping, deploy),
55
- permission(public_info, deploy),
56
- prohibition(public_face_recognition, deploy)
57
- )).
58
-
59
- % Teams can only serve missions whose skill they possess and whose route is usable.
60
- team(alpha_ambulance).
61
- teamSkill(alpha_ambulance, medical_transport).
62
- teamStatus(alpha_ambulance, ready).
63
- team(beta_coldchain).
64
- teamSkill(beta_coldchain, cold_chain).
65
- teamStatus(beta_coldchain, ready).
66
- team(delta_grid).
67
- teamSkill(delta_grid, grid_repair).
68
- teamStatus(delta_grid, ready).
69
- team(gamma_shelter).
70
- teamSkill(gamma_shelter, shelter_ops).
71
- teamStatus(gamma_shelter, ready).
72
- team(echo_drone).
73
- teamSkill(echo_drone, drone_mapping).
74
- teamStatus(echo_drone, ready).
75
- team(foxtrot_comms).
76
- teamSkill(foxtrot_comms, public_info).
77
- teamStatus(foxtrot_comms, ready).
78
- team(omega_vision).
79
- teamSkill(omega_vision, public_face_recognition).
80
- teamStatus(omega_vision, ready).
81
-
82
- % The road graph is directed. bounded_path/5 discovers simple bounded routes.
83
- road(base, north_gate).
84
- road(north_gate, hospital_quay).
85
- road(base, cold_depot).
86
- road(cold_depot, clinic_east).
87
- road(north_gate, substation_east).
88
- road(base, civic_center).
89
- road(civic_center, high_school).
90
- road(civic_center, riverside).
91
- road(civic_center, civic_square).
92
- road(base, west_bridge).
93
- road(west_bridge, west_bank).
94
-
95
- zone(hospital_quay).
96
- zone(clinic_east).
97
- zone(substation_east).
98
- zone(high_school).
99
- zone(riverside).
100
- zone(civic_square).
101
- zone(west_bank).
102
-
103
- routeRisk(hospital_quay, 9).
104
- routeRisk(clinic_east, 5).
105
- routeRisk(substation_east, 10).
106
- routeRisk(high_school, 4).
107
- routeRisk(riverside, 6).
108
- routeRisk(civic_square, 3).
109
- routeRisk(west_bank, 24).
110
- routeMinutes(hospital_quay, 22).
111
- routeMinutes(clinic_east, 19).
112
- routeMinutes(substation_east, 31).
113
- routeMinutes(high_school, 17).
114
- routeMinutes(riverside, 21).
115
- routeMinutes(civic_square, 15).
116
- routeMinutes(west_bank, 42).
117
-
118
- % Mission facts carry the operational need, location, required skill, value,
119
- % budget cost, and base risk. Route risk is added by candidateMission/2.
120
- missionBase(evacuate_hospital, evacuate_hospital, hospital_quay, medical_transport, 95, 34, 5).
121
- missionBase(deliver_insulin, deliver_medicine, clinic_east, cold_chain, 70, 16, 4).
122
- missionBase(stabilize_substation, stabilize_substation, substation_east, grid_repair, 85, 25, 8).
123
- missionBase(open_school_shelter, open_shelter, high_school, shelter_ops, 60, 14, 2).
124
- missionBase(map_flood_front, map_flood_front, riverside, drone_mapping, 45, 8, 2).
125
- missionBase(public_dashboard, public_information, civic_square, public_info, 28, 12, 1).
126
- missionBase(face_scan_crowds, situational_awareness, civic_square, public_face_recognition, 90, 20, 2).
127
- missionBase(resupply_west_bank, shelter_supply, west_bank, shelter_ops, 50, 20, 5).
128
-
129
- % Memoized derived predicates keep the example readable while avoiding repeated finite searches.
130
- memoize(usableRoute, 2).
131
- memoize(candidateMission, 2).
132
- memoize(bestResponse, 2).
133
-
134
- % Derivation rules: each rule below contributes one logical step toward the displayed results.
135
- incidentSummary(Incident, summary(Label, Goal, budget(Budget), riskCap(RiskCap))) :-
136
- incident_label(Incident, Label),
137
- incident_goal(Incident, Goal),
138
- budget_cap(Incident, Budget),
139
- risk_cap(Incident, RiskCap).
140
-
141
- activeSignal(civic_storm, river_surge) :-
142
- reading(river_gauge_cm, Value),
143
- threshold(river_gauge_cm, Threshold),
144
- ge(Value, Threshold).
145
- activeSignal(civic_storm, hospital_power_risk) :-
146
- reading(hospital_generator_hours, Value),
147
- threshold_low(hospital_generator_hours, Threshold),
148
- le(Value, Threshold).
149
- activeSignal(civic_storm, medicine_cold_chain_risk) :-
150
- reading(clinic_refrigerator_hours, Value),
151
- threshold_low(clinic_refrigerator_hours, Threshold),
152
- le(Value, Threshold).
153
- activeSignal(civic_storm, grid_stress) :-
154
- reading(substation_load_percent, Value),
155
- threshold(substation_load_percent, Threshold),
156
- ge(Value, Threshold).
157
-
158
- criticalNeed(civic_storm, evacuate_hospital) :-
159
- activeSignal(civic_storm, river_surge),
160
- activeSignal(civic_storm, hospital_power_risk).
161
- criticalNeed(civic_storm, deliver_medicine) :-
162
- activeSignal(civic_storm, medicine_cold_chain_risk).
163
- criticalNeed(civic_storm, stabilize_substation) :-
164
- activeSignal(civic_storm, grid_stress).
165
- criticalNeed(civic_storm, open_shelter) :-
166
- activeSignal(civic_storm, river_surge).
167
- criticalNeed(civic_storm, map_flood_front) :-
168
- activeSignal(civic_storm, river_surge).
169
-
170
- policyClearance(Skill, deploy) :-
171
- policy_bundle(response_policy, Context),
172
- holds(Context, permission(Skill, deploy)),
173
- not(policyBlocked(Skill, deploy)).
174
-
175
- policyBlocked(Skill, deploy) :-
176
- policy_bundle(response_policy, Context),
177
- holds(Context, prohibition(Skill, deploy)).
178
-
179
- usableRoute(Zone, route(Path, minutes(Minutes), risk(RouteRisk))) :-
180
- zone(Zone),
181
- bounded_path(road, base, Zone, 3, Path),
182
- routeMinutes(Zone, Minutes),
183
- routeRisk(Zone, RouteRisk),
184
- route_minutes_cap(civic_storm, MinutesCap),
185
- route_risk_cap(civic_storm, RiskCap),
186
- le(Minutes, MinutesCap),
187
- le(RouteRisk, RiskCap).
188
-
189
- eligibleAssignment(Mission, assignment(Team, Path)) :-
190
- missionBase(Mission, _Need, Zone, Skill, _Value, _Cost, _BaseRisk),
191
- policyClearance(Skill, deploy),
192
- teamSkill(Team, Skill),
193
- teamStatus(Team, ready),
194
- usableRoute(Zone, route(Path, minutes(_Minutes), risk(_RouteRisk))).
195
-
196
- candidateMission(Mission, score(Value, Cost, TotalRisk, Team, Path)) :-
197
- missionBase(Mission, _Need, Zone, Skill, Value, Cost, BaseRisk),
198
- policyClearance(Skill, deploy),
199
- teamSkill(Team, Skill),
200
- teamStatus(Team, ready),
201
- usableRoute(Zone, route(Path, minutes(_Minutes), risk(RouteRisk))),
202
- add(BaseRisk, RouteRisk, TotalRisk).
203
-
204
- blockedMission(Mission, policy_prohibition) :-
205
- missionBase(Mission, _Need, _Zone, Skill, _Value, _Cost, _BaseRisk),
206
- policyBlocked(Skill, deploy).
207
- blockedMission(Mission, route_risk_too_high) :-
208
- missionBase(Mission, _Need, Zone, _Skill, _Value, _Cost, _BaseRisk),
209
- routeRisk(Zone, RouteRisk),
210
- route_risk_cap(civic_storm, Cap),
211
- gt(RouteRisk, Cap).
212
- blockedMission(Mission, no_eligible_assignment) :-
213
- missionBase(Mission, _Need, _Zone, _Skill, _Value, _Cost, _BaseRisk),
214
- not(candidateMission(Mission, _Score)),
215
- not(blockedMission(Mission, policy_prohibition)),
216
- not(blockedMission(Mission, route_risk_too_high)).
217
-
218
- missionItem(p(Mission, Value, Cost, Risk)) :-
219
- candidateMission(Mission, score(Value, Cost, Risk, _Team, _Path)).
220
-
221
- missionItems(Items) :-
222
- findall(Item, missionItem(Item), Items).
223
-
224
- missionAddressesNeed(Mission, Need) :-
225
- missionBase(Mission, Need, _Zone, _Skill, _Value, _Cost, _BaseRisk).
226
-
227
- planCoversNeed(Plan, Need) :-
228
- member(Mission, Plan),
229
- missionAddressesNeed(Mission, Need).
230
-
231
- uncoveredNeedInPlan(Plan, Need) :-
232
- criticalNeed(civic_storm, Need),
233
- not(planCoversNeed(Plan, Need)).
234
-
235
- coversAllCriticalNeeds(Plan) :-
236
- not(uncoveredNeedInPlan(Plan, _Need)).
237
-
238
- candidateResponse(Plan, Value, Cost, Risk, NegCost, NegRisk) :-
239
- budget_cap(civic_storm, Budget),
240
- risk_cap(civic_storm, RiskCap),
241
- missionItems(Items),
242
- bounded_subset(Items, Budget, RiskCap, Plan, Value, Cost, Risk),
243
- coversAllCriticalNeeds(Plan),
244
- neg(Cost, NegCost),
245
- neg(Risk, NegRisk).
246
-
247
- bestResponse(civic_storm, response(value(Value), cost(Cost), risk(Risk), missions(Plan))) :-
248
- aggregate_max(
249
- [Value, NegCost, NegRisk, Plan],
250
- response(value(Value), cost(Cost), risk(Risk), missions(Plan)),
251
- candidateResponse(Plan, Value, Cost, Risk, NegCost, NegRisk),
252
- _Key,
253
- response(value(Value), cost(Cost), risk(Risk), missions(Plan))).
254
-
255
- selectedMission(civic_storm, Mission) :-
256
- bestResponse(civic_storm, response(value(_Value), cost(_Cost), risk(_Risk), missions(Plan))),
257
- member(Mission, Plan).
258
-
259
- selectedTeam(Mission, Team) :-
260
- selectedMission(civic_storm, Mission),
261
- candidateMission(Mission, score(_Value, _Cost, _Risk, Team, _Path)).
262
-
263
- selectedRoute(Mission, Path) :-
264
- selectedMission(civic_storm, Mission),
265
- candidateMission(Mission, score(_Value, _Cost, _Risk, _Team, Path)).
266
-
267
- coveredNeed(civic_storm, Need) :-
268
- selectedMission(civic_storm, Mission),
269
- missionAddressesNeed(Mission, Need).
270
-
271
- unmetNeed(civic_storm, Need) :-
272
- bestResponse(civic_storm, response(value(_Value), cost(_Cost), risk(_Risk), missions(Plan))),
273
- uncoveredNeedInPlan(Plan, Need).
274
- unmetNeed(civic_storm, none) :-
275
- bestResponse(civic_storm, response(value(_Value), cost(_Cost), risk(_Risk), missions(Plan))),
276
- coversAllCriticalNeeds(Plan).
277
-
278
- readinessCheck(civic_storm, all_critical_needs_covered) :-
279
- unmetNeed(civic_storm, none).
280
- readinessCheck(civic_storm, budget_and_risk_caps_respected) :-
281
- bestResponse(civic_storm, response(value(_Value), cost(Cost), risk(Risk), missions(_Plan))),
282
- budget_cap(civic_storm, Budget),
283
- risk_cap(civic_storm, Cap),
284
- le(Cost, Budget),
285
- le(Risk, Cap).
286
- readinessCheck(civic_storm, prohibited_surveillance_rejected) :-
287
- blockedMission(face_scan_crowds, policy_prohibition).
288
- readinessCheck(civic_storm, dangerous_west_bank_route_rejected) :-
289
- blockedMission(resupply_west_bank, route_risk_too_high).
290
-
291
- auditTrail(civic_storm, "raw sensor thresholds derive operational needs before search") :-
292
- eq(ok, ok).
293
- auditTrail(civic_storm, "policy formula data is projected into deployable skill clearances") :-
294
- eq(ok, ok).
295
- auditTrail(civic_storm, "bounded route search and team capabilities create candidate missions") :-
296
- eq(ok, ok).
297
- auditTrail(civic_storm, "bounded_subset and aggregate_max choose the highest-value safe portfolio") :-
298
- eq(ok, ok).
299
-
300
- recommendation(civic_storm, "activate the selected mission portfolio; do not deploy face recognition; defer west-bank resupply until route risk drops") :-
301
- readinessCheck(civic_storm, all_critical_needs_covered),
302
- readinessCheck(civic_storm, prohibited_surveillance_rejected),
303
- readinessCheck(civic_storm, dangerous_west_bank_route_rejected).
@@ -1,144 +0,0 @@
1
- // Reusable alphametic addition solver.
2
- // It evaluates column constraints right-to-left, so examples such as
3
- // SEND+MORE=MONEY and DONALD+GERALD=ROBERT do not need to express digit search
4
- // with many relational select/3 and arithmetic goals.
5
- import { atom, deref, listFromItems, numberTerm, properListItems, unify } from '../term.js';
6
-
7
- export const alphameticBuiltins = {
8
- register(registry) {
9
- registry.add('alphametic_sum', 5, alphameticSum, {
10
- fallbackWhenNotReady: true,
11
- ready: alphameticReady,
12
- });
13
- }
14
- };
15
-
16
- function alphameticReady(goal, env) {
17
- return atomList(goal.args[0], env) !== null && wordList(goal.args[1], env) !== null && atomList(goal.args[2], env) !== null;
18
- }
19
-
20
- function* alphameticSum({ goal, env }) {
21
- const letters = atomList(goal.args[0], env);
22
- const addends = wordList(goal.args[1], env);
23
- const result = atomList(goal.args[2], env);
24
- if (!letters || !addends || !result || letters.length > 10 || addends.length === 0) return;
25
-
26
- const letterSet = new Set(letters);
27
- for (const word of [...addends, result]) for (const letter of word) if (!letterSet.has(letter)) return;
28
-
29
- const leading = new Set();
30
- for (const word of [...addends, result]) if (word.length > 1) leading.add(word[0]);
31
- const maxLen = Math.max(result.length, ...addends.map((word) => word.length));
32
- const assignment = new Map();
33
- const used = Array(10).fill(false);
34
-
35
- function canUse(letter, digit) {
36
- return !used[digit] && !(digit === 0 && leading.has(letter));
37
- }
38
-
39
- function assignDigit(letter, digit) {
40
- assignment.set(letter, digit);
41
- used[digit] = true;
42
- }
43
-
44
- function unassignDigit(letter, digit) {
45
- assignment.delete(letter);
46
- used[digit] = false;
47
- }
48
-
49
- function* assignAddends(column, carry, index, sum) {
50
- if (index >= addends.length) {
51
- yield* finishColumn(column, sum);
52
- return;
53
- }
54
- const word = addends[index];
55
- const letter = word[word.length - 1 - column];
56
- if (letter === undefined) {
57
- yield* assignAddends(column, carry, index + 1, sum);
58
- return;
59
- }
60
- const assigned = assignment.get(letter);
61
- if (assigned !== undefined) {
62
- yield* assignAddends(column, carry, index + 1, sum + assigned);
63
- return;
64
- }
65
- for (let digit = 0; digit <= 9; digit++) {
66
- if (!canUse(letter, digit)) continue;
67
- assignDigit(letter, digit);
68
- yield* assignAddends(column, carry, index + 1, sum + digit);
69
- unassignDigit(letter, digit);
70
- }
71
- }
72
-
73
- function* finishColumn(column, sum) {
74
- const resultLetter = result[result.length - 1 - column];
75
- const digit = sum % 10;
76
- const nextCarry = Math.floor(sum / 10);
77
- if (resultLetter === undefined) {
78
- if (digit === 0) yield* solveColumn(column + 1, nextCarry);
79
- return;
80
- }
81
- const assigned = assignment.get(resultLetter);
82
- if (assigned !== undefined) {
83
- if (assigned === digit) yield* solveColumn(column + 1, nextCarry);
84
- return;
85
- }
86
- if (!canUse(resultLetter, digit)) return;
87
- assignDigit(resultLetter, digit);
88
- yield* solveColumn(column + 1, nextCarry);
89
- unassignDigit(resultLetter, digit);
90
- }
91
-
92
- function* solveColumn(column, carry) {
93
- if (column >= maxLen) {
94
- if (carry !== 0) return;
95
- if (assignment.size !== letters.length) return;
96
- yield new Map(assignment);
97
- return;
98
- }
99
- yield* assignAddends(column, carry, 0, carry);
100
- }
101
-
102
- for (const solution of solveColumn(0, 0)) {
103
- const digitTerms = letters.map((letter) => numberTerm(String(solution.get(letter))));
104
- const values = [...addends, result].map((word) => wordValue(word, solution));
105
- const valueTerms = values.map((value) => numberTerm(String(value)));
106
- const next = env.clone();
107
- if (unify(goal.args[3], listFromItems(digitTerms), next) && unify(goal.args[4], listFromItems(valueTerms), next)) yield next;
108
- }
109
- }
110
-
111
- function wordValue(word, assignment) {
112
- let value = 0;
113
- for (const letter of word) value = value * 10 + assignment.get(letter);
114
- return value;
115
- }
116
-
117
- function atomList(term, env) {
118
- const items = properListItems(term, env);
119
- if (!items) return null;
120
- const out = [];
121
- for (const item of items) {
122
- const text = atomKey(deref(item, env));
123
- if (text == null) return null;
124
- out.push(text);
125
- }
126
- return out;
127
- }
128
-
129
- function wordList(term, env) {
130
- const items = properListItems(term, env);
131
- if (!items) return null;
132
- const out = [];
133
- for (const item of items) {
134
- const word = atomList(item, env);
135
- if (!word) return null;
136
- out.push(word);
137
- }
138
- return out;
139
- }
140
-
141
- function atomKey(term) {
142
- if (term.type === 'atom' || term.type === 'string' || term.type === 'number') return term.name;
143
- return null;
144
- }
@@ -1,73 +0,0 @@
1
- // Reusable bounded-subset optimizer for finite knapsack-style examples.
2
- // Items are p(Name, Value, Cost, Risk) terms; the builtin enumerates every
3
- // subset whose total cost/risk stays within the supplied caps.
4
- import { deref, listFromItems, numberTerm, properListItems, unify } from '../term.js';
5
-
6
- export const portfolioBuiltins = {
7
- register(registry) {
8
- registry.add('bounded_subset', 7, boundedSubset, {
9
- fallbackWhenNotReady: true,
10
- ready: boundedSubsetReady,
11
- });
12
- }
13
- };
14
-
15
- function boundedSubsetReady(goal, env) {
16
- return parseItems(goal.args[0], env) !== null && intArg(goal.args[1], env) !== null && intArg(goal.args[2], env) !== null;
17
- }
18
-
19
- function* boundedSubset({ goal, env }) {
20
- const items = parseItems(goal.args[0], env);
21
- const budget = intArg(goal.args[1], env);
22
- const riskCap = intArg(goal.args[2], env);
23
- if (!items || budget == null || riskCap == null) return;
24
- for (const answer of enumerate(items, 0, budget, riskCap)) {
25
- const next = env.clone();
26
- if (unify(goal.args[3], listFromItems(answer.names), next) &&
27
- unify(goal.args[4], numberTerm(answer.value), next) &&
28
- unify(goal.args[5], numberTerm(answer.cost), next) &&
29
- unify(goal.args[6], numberTerm(answer.risk), next)) {
30
- yield next;
31
- }
32
- }
33
- }
34
-
35
- function* enumerate(items, index, budget, riskLeft) {
36
- if (index >= items.length) {
37
- yield { names: [], value: 0, cost: 0, risk: 0 };
38
- return;
39
- }
40
- const item = items[index];
41
- if (item.cost <= budget && item.risk <= riskLeft) {
42
- for (const rest of enumerate(items, index + 1, budget - item.cost, riskLeft - item.risk)) {
43
- yield {
44
- names: [item.name, ...rest.names],
45
- value: item.value + rest.value,
46
- cost: item.cost + rest.cost,
47
- risk: item.risk + rest.risk,
48
- };
49
- }
50
- }
51
- yield* enumerate(items, index + 1, budget, riskLeft);
52
- }
53
-
54
- function parseItems(term, env) {
55
- const list = properListItems(term, env);
56
- if (!list) return null;
57
- const items = [];
58
- for (const itemTerm of list) {
59
- const item = deref(itemTerm, env);
60
- if (item.type !== 'compound' || item.name !== 'p' || item.arity !== 4) return null;
61
- const value = intArg(item.args[1], env), cost = intArg(item.args[2], env), risk = intArg(item.args[3], env);
62
- if (value == null || cost == null || risk == null) return null;
63
- items.push({ name: item.args[0], value, cost, risk });
64
- }
65
- return items;
66
- }
67
-
68
- function intArg(term, env) {
69
- const value = deref(term, env);
70
- if (value.type !== 'number' || !/^-?\d+$/.test(value.name)) return null;
71
- const n = Number(value.name);
72
- return Number.isSafeInteger(n) ? n : null;
73
- }
@@ -1,3 +0,0 @@
1
- % Reference 9.5: alphametic_sum/5 enumerates unique digit assignments for column addition.
2
- answer(solution, result(Digits, Values)) :- alphametic_sum([a, b], [[a], [a]], [b], Digits, Values).
3
- materialize(answer, 2).
@@ -1,4 +0,0 @@
1
- % Reference 9.5: bounded_subset/7 enumerates subsets within budget and risk caps.
2
- projects([p(a, 5, 3, 1), p(b, 4, 2, 2), p(c, 7, 5, 3)]).
3
- answer(selection, result(Names, Value, Cost, Risk)) :- projects(Ps), bounded_subset(Ps, 5, 3, Names, Value, Cost, Risk).
4
- materialize(answer, 2).
@@ -1,4 +0,0 @@
1
- answer(solution, result([1, 2], [1, 1, 2])).
2
- answer(solution, result([2, 4], [2, 2, 4])).
3
- answer(solution, result([3, 6], [3, 3, 6])).
4
- answer(solution, result([4, 8], [4, 4, 8])).
@@ -1,5 +0,0 @@
1
- answer(selection, result([a, b], 9, 5, 3)).
2
- answer(selection, result([a], 5, 3, 1)).
3
- answer(selection, result([b], 4, 2, 2)).
4
- answer(selection, result([c], 7, 5, 3)).
5
- answer(selection, result([], 0, 0, 0)).