kibi-core 0.26.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/schema/entities.pl +12 -0
- package/src/cases.pl +311 -0
- package/src/checks.pl +357 -17
- package/src/claim_obligations.pl +16 -1
- package/src/code_certificates.pl +4 -0
- package/src/discovery.pl +65 -23
- package/src/intervals.pl +35 -14
- package/src/kb.pl +288 -36
- package/src/kb_consistency.pl +15 -0
- package/src/logic_ir.pl +130 -161
- package/src/model_check.pl +54 -6
- package/src/requirement_proof.pl +535 -14
- package/src/rule_registry.pl +6 -0
- package/src/status.pl +16 -0
- package/src/units.pl +1 -3
package/src/discovery.pl
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
coverage_report_json/12,
|
|
10
10
|
coverage_report_json/13,
|
|
11
11
|
coverage_evidence_json/5,
|
|
12
|
+
coverage_evidence_json/7,
|
|
12
13
|
evidence_floor_json/6,
|
|
13
14
|
requirement_proof_json/5,
|
|
14
15
|
requirement_proof_json/7,
|
|
@@ -155,12 +156,14 @@ symbol_explain_role(_SymbolId, unknown).
|
|
|
155
156
|
% not used: they take seconds on a large KB. The functional-predicate
|
|
156
157
|
% declarations a rule comparison reads are collected once per call rather
|
|
157
158
|
% than once per compared pair, which dominated the cost for requirements with
|
|
158
|
-
% many rules
|
|
159
|
-
%
|
|
160
|
-
%
|
|
159
|
+
% many rules; the infeasible success scenarios are likewise analysed once per
|
|
160
|
+
% call rather than once per requirement. A requirement whose checks raise an
|
|
161
|
+
% error reports that error instead of failing the answer. Scope names the
|
|
162
|
+
% snapshot the verdicts were computed from.
|
|
161
163
|
search_answer_verdicts_json(ReqIds, JsonString) :-
|
|
162
164
|
search_answer_functional(Functional),
|
|
163
|
-
|
|
165
|
+
search_answer_infeasible(Infeasible),
|
|
166
|
+
maplist(search_answer_verdict(Functional, Infeasible), ReqIds, Verdicts),
|
|
164
167
|
status_scope_dict(Scope),
|
|
165
168
|
dict_json_string(_{requirements: Verdicts, scope: Scope}, JsonString).
|
|
166
169
|
|
|
@@ -171,14 +174,27 @@ search_answer_functional(some(Functional)) :-
|
|
|
171
174
|
!.
|
|
172
175
|
search_answer_functional(none).
|
|
173
176
|
|
|
177
|
+
% Every infeasible success scenario, analysed once per call: the analysis
|
|
178
|
+
% walks every success scenario, so running it per requirement multiplied a
|
|
179
|
+
% whole-KB pass by the number of requirements in the answer. When it raises,
|
|
180
|
+
% each requirement's forbids check raises the same error itself and reports
|
|
181
|
+
% it as that requirement's error, as before.
|
|
182
|
+
search_answer_infeasible(some(Infeasible)) :-
|
|
183
|
+
catch(findall(infeasible(ScenarioId, ReqIds, AssumedFacts, ReqFacts, Reason),
|
|
184
|
+
infeasible_scenario(ScenarioId, ReqIds, AssumedFacts, ReqFacts, Reason),
|
|
185
|
+
Infeasible),
|
|
186
|
+
_, fail),
|
|
187
|
+
!.
|
|
188
|
+
search_answer_infeasible(none).
|
|
189
|
+
|
|
174
190
|
search_answer_rule_status(some(Functional), RuleA, RuleB, Status) :-
|
|
175
191
|
!,
|
|
176
192
|
logic_rule_conflict(RuleA, RuleB, Functional, Status).
|
|
177
193
|
search_answer_rule_status(none, RuleA, RuleB, Status) :-
|
|
178
194
|
logic_rule_conflict(RuleA, RuleB, Status).
|
|
179
195
|
|
|
180
|
-
search_answer_verdict(Functional, ReqId, Verdict) :-
|
|
181
|
-
catch(search_answer_verdict_(Functional, ReqId, Verdict0), Error, true),
|
|
196
|
+
search_answer_verdict(Functional, Infeasible, ReqId, Verdict) :-
|
|
197
|
+
catch(search_answer_verdict_(Functional, Infeasible, ReqId, Verdict0), Error, true),
|
|
182
198
|
( var(Error)
|
|
183
199
|
-> Verdict = Verdict0
|
|
184
200
|
; format(string(Text0), "~q", [Error]),
|
|
@@ -186,7 +202,7 @@ search_answer_verdict(Functional, ReqId, Verdict) :-
|
|
|
186
202
|
Verdict = _{id: ReqId, error: Text}
|
|
187
203
|
).
|
|
188
204
|
|
|
189
|
-
search_answer_verdict_(Functional, ReqId, _{
|
|
205
|
+
search_answer_verdict_(Functional, Infeasible, ReqId, _{
|
|
190
206
|
id: ReqId,
|
|
191
207
|
contradictions: Contradictions,
|
|
192
208
|
scenarios: Scenarios,
|
|
@@ -197,7 +213,7 @@ search_answer_verdict_(Functional, ReqId, _{
|
|
|
197
213
|
sort(Contradictions0, Contradictions),
|
|
198
214
|
findall(S, search_answer_scenario_outcome(ReqId, S), Scenarios0),
|
|
199
215
|
sort(Scenarios0, Scenarios),
|
|
200
|
-
findall(F, search_answer_forbidden_scenario(ReqId, F), Forbids0),
|
|
216
|
+
findall(F, search_answer_forbidden_scenario(Infeasible, ReqId, F), Forbids0),
|
|
201
217
|
sort(Forbids0, Forbids),
|
|
202
218
|
search_answer_inventory(ReqId, Inventory).
|
|
203
219
|
|
|
@@ -291,7 +307,18 @@ search_answer_outcome(ScenarioId, Result, _{scenario: ScenarioId, outcome: Outco
|
|
|
291
307
|
; format(atom(Outcome), "~q", [Result])
|
|
292
308
|
).
|
|
293
309
|
|
|
294
|
-
search_answer_forbidden_scenario(ReqId, _{
|
|
310
|
+
search_answer_forbidden_scenario(some(Infeasible), ReqId, _{
|
|
311
|
+
scenario: ScenarioId,
|
|
312
|
+
assumed: AssumedFacts,
|
|
313
|
+
fact: ReqFacts,
|
|
314
|
+
reason: Reason
|
|
315
|
+
}) :-
|
|
316
|
+
member(infeasible(ScenarioId, ReqIds, AssumedFacts, ReqFacts, RawReason), Infeasible),
|
|
317
|
+
memberchk(ReqId, ReqIds),
|
|
318
|
+
\+ kb_relationship(specified_by, ReqId, ScenarioId),
|
|
319
|
+
search_answer_text(RawReason, Reason).
|
|
320
|
+
|
|
321
|
+
search_answer_forbidden_scenario(none, ReqId, _{
|
|
295
322
|
scenario: ScenarioId,
|
|
296
323
|
assumed: AssumedFacts,
|
|
297
324
|
fact: ReqFacts,
|
|
@@ -352,6 +379,16 @@ search_answer_clip(Text, Max, Clipped) :-
|
|
|
352
379
|
% the full coverage row set, keeping the response small on large KBs.
|
|
353
380
|
coverage_evidence_json(Tags, VerificationSnapshot, CheckedAt, MaxAgeSeconds, JsonString) :-
|
|
354
381
|
requirement_proof_context(VerificationSnapshot, CheckedAt, MaxAgeSeconds, ProofContext),
|
|
382
|
+
coverage_evidence_rows_json(Tags, ProofContext, JsonString).
|
|
383
|
+
|
|
384
|
+
% The same rows under a receipt binding mode, so kb_check judges receipts
|
|
385
|
+
% like kb_coverage and kibi proof explain: per_contract with the TestId ->
|
|
386
|
+
% binding hash dict, or strict_snapshot.
|
|
387
|
+
coverage_evidence_json(Tags, BindingMode, TestBindings, VerificationSnapshot, CheckedAt, MaxAgeSeconds, JsonString) :-
|
|
388
|
+
requirement_proof_context(VerificationSnapshot, CheckedAt, MaxAgeSeconds, BindingMode, TestBindings, ProofContext),
|
|
389
|
+
coverage_evidence_rows_json(Tags, ProofContext, JsonString).
|
|
390
|
+
|
|
391
|
+
coverage_evidence_rows_json(Tags, ProofContext, JsonString) :-
|
|
355
392
|
findall(Evidence,
|
|
356
393
|
( kb_entity(Id, req, Props),
|
|
357
394
|
matches_tags(Tags, Props),
|
|
@@ -479,9 +516,9 @@ coverage_report_json(By, Tags, IncludePassing, BindingMode, TestBindings, Includ
|
|
|
479
516
|
binding(By, Tags, IncludePassing, BindingMode, TestBindings, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
480
517
|
binding_coverage_rows(By, Tags, IncludePassing, BindingMode, TestBindings, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
481
518
|
SortedRows,
|
|
482
|
-
Summary
|
|
519
|
+
Summary,
|
|
520
|
+
Meta),
|
|
483
521
|
paginate_rows(SortedRows, Offset, Limit, Rows),
|
|
484
|
-
status_meta_dict(Meta),
|
|
485
522
|
Response = _{summary: Summary, rows: Rows, meta: Meta},
|
|
486
523
|
dict_json_string(Response, JsonString).
|
|
487
524
|
|
|
@@ -497,9 +534,9 @@ coverage_report_json(By, Tags, IncludePassing, StatusFilter, IncludeTransitive,
|
|
|
497
534
|
status(By, Tags, IncludePassing, StatusFilter, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
498
535
|
status_filtered_coverage_rows(By, Tags, IncludePassing, StatusFilter, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
499
536
|
SortedRows,
|
|
500
|
-
Summary
|
|
537
|
+
Summary,
|
|
538
|
+
Meta),
|
|
501
539
|
paginate_rows(SortedRows, Offset, Limit, Rows),
|
|
502
|
-
status_meta_dict(Meta),
|
|
503
540
|
Response = _{summary: Summary, rows: Rows, meta: Meta},
|
|
504
541
|
dict_json_string(Response, JsonString).
|
|
505
542
|
|
|
@@ -512,9 +549,9 @@ coverage_report_json(By, Tags, IncludePassing, StatusFilter, BindingMode, TestBi
|
|
|
512
549
|
status_binding(By, Tags, IncludePassing, StatusFilter, BindingMode, TestBindings, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
513
550
|
status_binding_coverage_rows(By, Tags, IncludePassing, StatusFilter, BindingMode, TestBindings, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds),
|
|
514
551
|
SortedRows,
|
|
515
|
-
Summary
|
|
552
|
+
Summary,
|
|
553
|
+
Meta),
|
|
516
554
|
paginate_rows(SortedRows, Offset, Limit, Rows),
|
|
517
|
-
status_meta_dict(Meta),
|
|
518
555
|
Response = _{summary: Summary, rows: Rows, meta: Meta},
|
|
519
556
|
dict_json_string(Response, JsonString).
|
|
520
557
|
|
|
@@ -531,26 +568,31 @@ binding_coverage_rows(req, Tags, IncludePassing, BindingMode, TestBindings, Incl
|
|
|
531
568
|
binding_coverage_rows(By, Tags, IncludePassing, _BindingMode, _TestBindings, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds, Rows, Summary) :-
|
|
532
569
|
coverage_rows(By, Tags, IncludePassing, IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds, Rows, Summary).
|
|
533
570
|
|
|
534
|
-
:- dynamic coverage_memo/
|
|
571
|
+
:- dynamic coverage_memo/4.
|
|
535
572
|
|
|
536
|
-
%% memo_sorted_coverage(+Args, :Compute, -SortedRows, -Summary)
|
|
573
|
+
%% memo_sorted_coverage(+Args, :Compute, -SortedRows, -Summary, -Meta)
|
|
537
574
|
% Large coverage reports are fetched in bounded pages so no single answer
|
|
538
575
|
% approaches the engine's output cap. Every page would otherwise recompute
|
|
539
576
|
% the whole report; keep the most recent sorted result for the exact
|
|
540
577
|
% arguments, graph, and RDF generation. Coverage reads only the store and its
|
|
541
|
-
% arguments, so the memo is invalidated by any store change.
|
|
542
|
-
|
|
578
|
+
% arguments, so the memo is invalidated by any store change. The status meta
|
|
579
|
+
% is kept with it: its freshness check stats every indexed source, which cost
|
|
580
|
+
% more than the page itself, and the pages of one report share its arguments
|
|
581
|
+
% (including the check time), so they describe the same snapshot.
|
|
582
|
+
memo_sorted_coverage(Args, Compute, SortedRows, Summary, Meta) :-
|
|
543
583
|
(kb:kb_graph(Graph) -> true ; Graph = none),
|
|
544
584
|
rdf_generation(Generation),
|
|
545
585
|
Key = key(Args, Graph, Generation),
|
|
546
|
-
( coverage_memo(Stored, StoredRows, StoredSummary),
|
|
586
|
+
( coverage_memo(Stored, StoredRows, StoredSummary, StoredMeta),
|
|
547
587
|
Stored =@= Key
|
|
548
588
|
-> SortedRows = StoredRows,
|
|
549
|
-
Summary = StoredSummary
|
|
589
|
+
Summary = StoredSummary,
|
|
590
|
+
Meta = StoredMeta
|
|
550
591
|
; call(Compute, Rows0, Summary),
|
|
551
592
|
sort_dict_rows(Rows0, SortedRows),
|
|
552
|
-
|
|
553
|
-
|
|
593
|
+
status_meta_dict(Meta),
|
|
594
|
+
retractall(coverage_memo(_, _, _, _)),
|
|
595
|
+
assertz(coverage_memo(Key, SortedRows, Summary, Meta))
|
|
554
596
|
).
|
|
555
597
|
|
|
556
598
|
status_filtered_coverage_rows(By, Tags, IncludePassing, [], IncludeTransitive, VerificationSnapshot, CheckedAt, MaxAgeSeconds, Rows, Summary) :-
|
package/src/intervals.pl
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
%% numeric_constraints_satisfiable(+Constraints)
|
|
23
23
|
% True when some assignment of reals satisfies every constraint.
|
|
24
24
|
numeric_constraints_satisfiable(Constraints) :-
|
|
25
|
+
% mutalog-disable-next-line literal: [_] names no variable, so it equals []
|
|
25
26
|
numeric_constraints_satisfiable(Constraints, []).
|
|
26
27
|
|
|
27
28
|
%% numeric_constraints_satisfiable(+Constraints, +IntegerVariables)
|
|
@@ -43,6 +44,7 @@ numeric_constraints_satisfiable(Constraints, IntegerVariables) :-
|
|
|
43
44
|
%% numeric_constraint_entailed(+Premises, +Constraint)
|
|
44
45
|
% True when every assignment that satisfies Premises satisfies Constraint.
|
|
45
46
|
numeric_constraint_entailed(Premises, Constraint) :-
|
|
47
|
+
% mutalog-disable-next-line literal: [_] names no variable, so it equals []
|
|
46
48
|
numeric_constraint_entailed(Premises, Constraint, []).
|
|
47
49
|
|
|
48
50
|
%% numeric_constraint_entailed(+Premises, +Constraint, +IntegerVariables)
|
|
@@ -60,12 +62,12 @@ finite_constraint(c(_Op, _Variable, Value)) :-
|
|
|
60
62
|
; true
|
|
61
63
|
).
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
% Only called as an if-then-else condition, which keeps the first answer.
|
|
66
|
+
integer_variable(_, all).
|
|
64
67
|
integer_variable(Variable, IntegerVariables) :-
|
|
65
68
|
is_list(IntegerVariables),
|
|
66
69
|
member(Candidate, IntegerVariables),
|
|
67
|
-
Candidate == Variable
|
|
68
|
-
!.
|
|
70
|
+
Candidate == Variable.
|
|
69
71
|
|
|
70
72
|
%% numeric_constraint_negation(+Constraint, -Negated)
|
|
71
73
|
numeric_constraint_negation(c(Op, Variable, Value), c(Negated, Variable, Value)) :-
|
|
@@ -80,10 +82,15 @@ negated_operator(gt, lte).
|
|
|
80
82
|
|
|
81
83
|
%% numeric_constraint_holds(+Op, +Left, +Right)
|
|
82
84
|
% Evaluate a comparison between two numbers.
|
|
85
|
+
% mutalog-disable-next-line cut_insert: a comparison has one answer and the operators are distinct
|
|
83
86
|
numeric_constraint_holds(eq, Left, Right) :- Left =:= Right.
|
|
87
|
+
% mutalog-disable-next-line cut_insert: a comparison has one answer and the operators are distinct
|
|
84
88
|
numeric_constraint_holds(neq, Left, Right) :- Left =\= Right.
|
|
89
|
+
% mutalog-disable-next-line cut_insert: a comparison has one answer and the operators are distinct
|
|
85
90
|
numeric_constraint_holds(lt, Left, Right) :- Left < Right.
|
|
91
|
+
% mutalog-disable-next-line cut_insert: a comparison has one answer and the operators are distinct
|
|
86
92
|
numeric_constraint_holds(lte, Left, Right) :- Left =< Right.
|
|
93
|
+
% mutalog-disable-next-line cut_insert: a comparison has one answer and the operators are distinct
|
|
87
94
|
numeric_constraint_holds(gt, Left, Right) :- Left > Right.
|
|
88
95
|
numeric_constraint_holds(gte, Left, Right) :- Left >= Right.
|
|
89
96
|
|
|
@@ -94,14 +101,18 @@ variable_feasible(Variable, Constraints) :-
|
|
|
94
101
|
|
|
95
102
|
% interval(Low, LowKind, High, HighKind, Excluded)
|
|
96
103
|
apply_bound(eq-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo1, LoK1, Hi1, HiK1, Ex)) :-
|
|
104
|
+
% mutalog-disable-next-line cut_insert: raise_low/6 and lower_high/6 are det and the operators are distinct
|
|
97
105
|
raise_low(Lo, LoK, Value, closed, Lo1, LoK1),
|
|
98
106
|
lower_high(Hi, HiK, Value, closed, Hi1, HiK1).
|
|
99
107
|
apply_bound(neq-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo, LoK, Hi, HiK, [Value|Ex])).
|
|
100
108
|
apply_bound(lt-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo, LoK, Hi1, HiK1, Ex)) :-
|
|
109
|
+
% mutalog-disable-next-line cut_insert: raise_low/6 and lower_high/6 are det and the operators are distinct
|
|
101
110
|
lower_high(Hi, HiK, Value, open, Hi1, HiK1).
|
|
102
111
|
apply_bound(lte-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo, LoK, Hi1, HiK1, Ex)) :-
|
|
112
|
+
% mutalog-disable-next-line cut_insert: raise_low/6 and lower_high/6 are det and the operators are distinct
|
|
103
113
|
lower_high(Hi, HiK, Value, closed, Hi1, HiK1).
|
|
104
114
|
apply_bound(gt-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo1, LoK1, Hi, HiK, Ex)) :-
|
|
115
|
+
% mutalog-disable-next-line cut_insert: raise_low/6 and lower_high/6 are det and the operators are distinct
|
|
105
116
|
raise_low(Lo, LoK, Value, open, Lo1, LoK1).
|
|
106
117
|
apply_bound(gte-Value, interval(Lo, LoK, Hi, HiK, Ex), interval(Lo1, LoK1, Hi, HiK, Ex)) :-
|
|
107
118
|
raise_low(Lo, LoK, Value, closed, Lo1, LoK1).
|
|
@@ -116,13 +127,18 @@ lower_high(Hi, _, Value, Kind, Value, Kind) :- Value < Hi, !.
|
|
|
116
127
|
lower_high(Hi, HiK, Value, Kind, Hi, Kind1) :- Value =:= Hi, !, tighter_kind(HiK, Kind, Kind1).
|
|
117
128
|
lower_high(Hi, HiK, _, _, Hi, HiK).
|
|
118
129
|
|
|
130
|
+
% mutalog-disable-next-line cut: the second answer, open, only shrinks the interval
|
|
119
131
|
tighter_kind(closed, closed, closed) :- !.
|
|
120
132
|
tighter_kind(_, _, open).
|
|
121
133
|
|
|
122
134
|
% An unbounded or non-degenerate real interval cannot be emptied by finitely
|
|
123
135
|
% many excluded points. A degenerate interval is a single closed point.
|
|
136
|
+
% The callers keep only the first answer, so the cuts are not observable.
|
|
137
|
+
% mutalog-disable-next-line cut
|
|
124
138
|
interval_non_empty(interval(ninf, _, _, _, _)) :- !.
|
|
139
|
+
% mutalog-disable-next-line cut
|
|
125
140
|
interval_non_empty(interval(_, _, pinf, _, _)) :- !.
|
|
141
|
+
% mutalog-disable-next-line cut
|
|
126
142
|
interval_non_empty(interval(Lo, _, Hi, _, _)) :- Lo < Hi, !.
|
|
127
143
|
interval_non_empty(interval(Lo, closed, Hi, closed, Excluded)) :-
|
|
128
144
|
Lo =:= Hi,
|
|
@@ -131,34 +147,37 @@ interval_non_empty(interval(Lo, closed, Hi, closed, Excluded)) :-
|
|
|
131
147
|
% Integer variables: every strict or fractional bound is tightened to the
|
|
132
148
|
% nearest admissible integer, so the set is an integer range [Lo, Hi] minus
|
|
133
149
|
% finitely many excluded integers. An eq bound with a fractional value admits
|
|
134
|
-
% no integer at all.
|
|
150
|
+
% no integer at all, so the fold fails. The operators are distinct, so the
|
|
151
|
+
% cuts after the heads are not observable.
|
|
135
152
|
integer_variable_feasible(Variable, Constraints) :-
|
|
136
153
|
findall(Op-Value, (member(c(Op, Other, Value), Constraints), Other == Variable), Bounds),
|
|
137
154
|
foldl(apply_integer_bound, Bounds, ibox(ninf, pinf, []), Box),
|
|
138
155
|
integer_box_non_empty(Box).
|
|
139
156
|
|
|
140
|
-
|
|
141
|
-
apply_integer_bound(eq-Value, ibox(Lo, Hi, Ex),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
; Box = empty
|
|
147
|
-
).
|
|
157
|
+
% mutalog-disable-next-line cut
|
|
158
|
+
apply_integer_bound(eq-Value, ibox(Lo, Hi, Ex), ibox(Lo1, Hi1, Ex)) :- !,
|
|
159
|
+
integral_value(Value, Integer),
|
|
160
|
+
integer_raise_low(Lo, Integer, Lo1),
|
|
161
|
+
integer_lower_high(Hi, Integer, Hi1).
|
|
162
|
+
% mutalog-disable-next-line cut
|
|
148
163
|
apply_integer_bound(neq-Value, ibox(Lo, Hi, Ex), ibox(Lo, Hi, Ex1)) :- !,
|
|
149
164
|
( integral_value(Value, Integer)
|
|
150
165
|
-> Ex1 = [Integer|Ex]
|
|
151
166
|
; Ex1 = Ex
|
|
152
167
|
).
|
|
168
|
+
% mutalog-disable-next-line cut
|
|
153
169
|
apply_integer_bound(gt-Value, ibox(Lo, Hi, Ex), ibox(Lo1, Hi, Ex)) :- !,
|
|
154
170
|
Bound is floor(Value) + 1,
|
|
155
171
|
integer_raise_low(Lo, Bound, Lo1).
|
|
172
|
+
% mutalog-disable-next-line cut
|
|
156
173
|
apply_integer_bound(gte-Value, ibox(Lo, Hi, Ex), ibox(Lo1, Hi, Ex)) :- !,
|
|
157
174
|
Bound is ceiling(Value),
|
|
158
175
|
integer_raise_low(Lo, Bound, Lo1).
|
|
176
|
+
% mutalog-disable-next-line cut
|
|
159
177
|
apply_integer_bound(lt-Value, ibox(Lo, Hi, Ex), ibox(Lo, Hi1, Ex)) :- !,
|
|
160
178
|
Bound is ceiling(Value) - 1,
|
|
161
179
|
integer_lower_high(Hi, Bound, Hi1).
|
|
180
|
+
% mutalog-disable-next-line cut
|
|
162
181
|
apply_integer_bound(lte-Value, ibox(Lo, Hi, Ex), ibox(Lo, Hi1, Ex)) :- !,
|
|
163
182
|
Bound is floor(Value),
|
|
164
183
|
integer_lower_high(Hi, Bound, Hi1).
|
|
@@ -175,11 +194,13 @@ integer_lower_high(pinf, Bound, Bound) :- !.
|
|
|
175
194
|
integer_lower_high(Hi, Bound, Hi1) :- Hi1 is min(Hi, Bound).
|
|
176
195
|
|
|
177
196
|
% An unbounded integer range cannot be emptied by finitely many exclusions.
|
|
178
|
-
|
|
197
|
+
% A range with Lo above Hi has a non-positive size, so it fails the count.
|
|
198
|
+
% The callers keep only the first answer, so the cuts are not observable.
|
|
199
|
+
% mutalog-disable-next-line cut
|
|
179
200
|
integer_box_non_empty(ibox(ninf, _, _)) :- !.
|
|
201
|
+
% mutalog-disable-next-line cut
|
|
180
202
|
integer_box_non_empty(ibox(_, pinf, _)) :- !.
|
|
181
203
|
integer_box_non_empty(ibox(Lo, Hi, Excluded)) :-
|
|
182
|
-
Lo =< Hi,
|
|
183
204
|
findall(Value, (member(Value, Excluded), Value >= Lo, Value =< Hi), Inside0),
|
|
184
205
|
sort(Inside0, Inside),
|
|
185
206
|
length(Inside, ExcludedCount),
|