eyeling 1.33.7 → 1.33.8
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 +1 -1
- package/docs/eyelang-guide.md +0 -2
- package/docs/eyelang-language-reference.md +1 -1
- package/lib/eyelang/builtins/registry.js +1 -2
- package/package.json +1 -1
- package/examples/eyelang/output/project-portfolio-optimization.pl +0 -6
- package/examples/eyelang/output/resilient-city-orchestration.pl +0 -67
- package/examples/eyelang/project-portfolio-optimization.pl +0 -101
- package/examples/eyelang/resilient-city-orchestration.pl +0 -303
- package/lib/eyelang/builtins/portfolio.js +0 -73
- package/test/eyelang/conformance/cases/extension/046_bounded_subset.pl +0 -4
- package/test/eyelang/conformance/expected/extension/046_bounded_subset.out +0 -5
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`, `
|
|
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`, `alphametic_sum/5` |
|
|
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
|
|
package/docs/eyelang-guide.md
CHANGED
|
@@ -415,12 +415,10 @@ The repository includes examples for recursion, graph reachability, finite searc
|
|
|
415
415
|
| [`peasant.pl`](../examples/eyelang/peasant.pl) | Performs peasant multiplication and exponentiation. | [`output/peasant.pl`](../examples/eyelang/output/peasant.pl) |
|
|
416
416
|
| [`pendulum-period.pl`](../examples/eyelang/pendulum-period.pl) | Computes simple pendulum periods. | [`output/pendulum-period.pl`](../examples/eyelang/output/pendulum-period.pl) |
|
|
417
417
|
| [`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
418
|
| [`proof-contrapositive.pl`](../examples/eyelang/proof-contrapositive.pl) | Models proof by contrapositive. | [`output/proof-contrapositive.pl`](../examples/eyelang/output/proof-contrapositive.pl) |
|
|
420
419
|
| [`quadratic-formula.pl`](../examples/eyelang/quadratic-formula.pl) | Solves sample quadratic equations. | [`output/quadratic-formula.pl`](../examples/eyelang/output/quadratic-formula.pl) |
|
|
421
420
|
| [`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
421
|
| [`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
422
|
| [`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
423
|
| [`sat-dpll.pl`](../examples/eyelang/sat-dpll.pl) | Solves a finite SAT instance. | [`output/sat-dpll.pl`](../examples/eyelang/output/sat-dpll.pl) |
|
|
426
424
|
| [`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
|
|
471
|
+
For example, an implementation may include extension modules for 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.
|
|
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,7 +7,6 @@ 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';
|
|
@@ -38,7 +37,7 @@ export class BuiltinRegistry {
|
|
|
38
37
|
|
|
39
38
|
export function createDefaultRegistry() {
|
|
40
39
|
const registry = new BuiltinRegistry();
|
|
41
|
-
for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, contextBuiltins, controlBuiltins,
|
|
40
|
+
for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, contextBuiltins, controlBuiltins, searchBuiltins, numberTheoryBuiltins, matrixBuiltins, alphameticBuiltins]) {
|
|
42
41
|
mod.register(registry);
|
|
43
42
|
}
|
|
44
43
|
return registry;
|
package/package.json
CHANGED
|
@@ -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,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,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).
|