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/kb.pl
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
kb_indexed_sources/1,
|
|
28
28
|
kb_query_entities/8,
|
|
29
29
|
kb_search_entities/6,
|
|
30
|
+
kb_relationship_edges/3,
|
|
30
31
|
kb_list_search_candidates/5,
|
|
31
32
|
kb_list_search_candidates/6,
|
|
32
33
|
kb_entity_ids/1,
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
kb_entity/3,
|
|
35
36
|
kb_entities_by_source/2,
|
|
36
37
|
kb_assert_relationship/4,
|
|
38
|
+
kb_assert_relationships_reporting/2,
|
|
37
39
|
kb_query_proof_contracts/4,
|
|
38
40
|
kb_assert_relationship_no_audit/4,
|
|
39
41
|
kb_log_relationship_upsert/4,
|
|
@@ -88,6 +90,8 @@
|
|
|
88
90
|
:- use_module(library(aggregate), [aggregate_all/3]).
|
|
89
91
|
:- use_module(library(lists), [sum_list/2, subtract/3, intersection/3]).
|
|
90
92
|
:- use_module(library(ordsets)).
|
|
93
|
+
:- use_module(library(assoc), [list_to_assoc/2, get_assoc/3]).
|
|
94
|
+
:- use_module(library(pairs), [group_pairs_by_key/2, pairs_values/2]).
|
|
91
95
|
:- use_module(library(solution_sequences), [distinct/1, limit/2, offset/2, order_by/2]).
|
|
92
96
|
:- use_module('../schema/entities.pl', [entity_type/1, entity_property/3, required_property/2]).
|
|
93
97
|
:- use_module('../schema/relationships.pl', [relationship_type/1, valid_relationship/3]).
|
|
@@ -140,6 +144,17 @@ kb_uri('urn-kibi:').
|
|
|
140
144
|
:- dynamic kb_entity_props_memo/2.
|
|
141
145
|
:- dynamic kb_entity_props_memo_key/1.
|
|
142
146
|
:- dynamic kb_decision_signature_memo/2.
|
|
147
|
+
:- dynamic kb_req_predicate_memo/2.
|
|
148
|
+
:- dynamic kb_req_subject_memo/2.
|
|
149
|
+
:- dynamic kb_contradiction_witness_memo/2.
|
|
150
|
+
:- dynamic kb_consistency_memo/3.
|
|
151
|
+
:- dynamic kb_predicate_schema_memo/2.
|
|
152
|
+
:- dynamic kb_requirement_proof_memo/3.
|
|
153
|
+
:- dynamic kb_requirement_ladder_memo/3.
|
|
154
|
+
:- dynamic kb_status_source_index_memo/2.
|
|
155
|
+
:- dynamic kb_scenario_feasibility_memo/3.
|
|
156
|
+
:- dynamic kb_search_ids_memo/4.
|
|
157
|
+
:- dynamic kb_query_ids_memo/3.
|
|
143
158
|
:- dynamic kb_index_verified_key/1.
|
|
144
159
|
:- dynamic entity/4. % Support legacy .pl file format (Type, Id, Title, Props)
|
|
145
160
|
|
|
@@ -367,6 +382,17 @@ kb_detach :-
|
|
|
367
382
|
retractall(kb_entity_props_memo(_, _)),
|
|
368
383
|
retractall(kb_entity_props_memo_key(_)),
|
|
369
384
|
retractall(kb_decision_signature_memo(_, _)),
|
|
385
|
+
retractall(kb_req_predicate_memo(_, _)),
|
|
386
|
+
retractall(kb_req_subject_memo(_, _)),
|
|
387
|
+
retractall(kb_contradiction_witness_memo(_, _)),
|
|
388
|
+
retractall(kb_consistency_memo(_, _, _)),
|
|
389
|
+
retractall(kb_predicate_schema_memo(_, _)),
|
|
390
|
+
retractall(kb_requirement_proof_memo(_, _, _)),
|
|
391
|
+
retractall(kb_requirement_ladder_memo(_, _, _)),
|
|
392
|
+
retractall(kb_status_source_index_memo(_, _)),
|
|
393
|
+
retractall(kb_scenario_feasibility_memo(_, _, _)),
|
|
394
|
+
retractall(kb_search_ids_memo(_, _, _, _)),
|
|
395
|
+
retractall(kb_query_ids_memo(_, _, _)),
|
|
370
396
|
retractall(kb_index_entity(_, _)),
|
|
371
397
|
retractall(kb_index_type(_, _)),
|
|
372
398
|
retractall(kb_index_tag(_, _)),
|
|
@@ -1698,10 +1724,7 @@ kb_query_entities(TypeFilter, IdFilter, Tags, SourceFilter, Limit, Offset, Rows,
|
|
|
1698
1724
|
Offset >= 0,
|
|
1699
1725
|
is_list(Tags),
|
|
1700
1726
|
kb_ensure_indexes,
|
|
1701
|
-
|
|
1702
|
-
indexed_entity_match(TypeFilter, IdFilter, Tags, SourceFilter, Id),
|
|
1703
|
-
RawIds),
|
|
1704
|
-
sort(RawIds, Ids),
|
|
1727
|
+
query_index_ids(TypeFilter, IdFilter, Tags, SourceFilter, Ids),
|
|
1705
1728
|
length(Ids, Count),
|
|
1706
1729
|
drop_index_ids(Offset, Ids, Remaining),
|
|
1707
1730
|
take_index_ids(Limit, Remaining, PageIds),
|
|
@@ -1710,6 +1733,25 @@ kb_query_entities(TypeFilter, IdFilter, Tags, SourceFilter, Limit, Offset, Rows,
|
|
|
1710
1733
|
kb_entity(Id, Type, Props) ),
|
|
1711
1734
|
Rows).
|
|
1712
1735
|
|
|
1736
|
+
% Clients read a large result in bounded pages, each page a separate query,
|
|
1737
|
+
% so the ids matched for the last filter are kept for its next pages instead
|
|
1738
|
+
% of matching and sorting the whole index again per page. Keyed like the
|
|
1739
|
+
% search memo, so any write starts a fresh match.
|
|
1740
|
+
% The caller ensured the indexes, so the entity count is known.
|
|
1741
|
+
query_index_ids(TypeFilter, IdFilter, Tags, SourceFilter, Ids) :-
|
|
1742
|
+
kb_index_entity_count(IndexCount),
|
|
1743
|
+
index_verification_key(IndexCount, Key),
|
|
1744
|
+
Filters = filters(TypeFilter, IdFilter, Tags, SourceFilter),
|
|
1745
|
+
( kb_query_ids_memo(Key, Filters, Cached)
|
|
1746
|
+
-> Ids = Cached
|
|
1747
|
+
; findall(Id,
|
|
1748
|
+
indexed_entity_match(TypeFilter, IdFilter, Tags, SourceFilter, Id),
|
|
1749
|
+
RawIds),
|
|
1750
|
+
sort(RawIds, Ids),
|
|
1751
|
+
retractall(kb_query_ids_memo(_, _, _)),
|
|
1752
|
+
assertz(kb_query_ids_memo(Key, Filters, Ids))
|
|
1753
|
+
).
|
|
1754
|
+
|
|
1713
1755
|
%% kb_query_proof_contracts(+Id, +Limit, +Offset, -Rows)
|
|
1714
1756
|
% Page proof-campaign candidates while reading only contract and binding RDF
|
|
1715
1757
|
% properties. In particular, do not call kb_entity/3 here: that materializes
|
|
@@ -1848,19 +1890,37 @@ kb_search_entities(TypeFilter, Query, Limit, Offset, Rows, Count) :-
|
|
|
1848
1890
|
kb_ensure_indexes,
|
|
1849
1891
|
index_text_tokens(Query, QueryTokens),
|
|
1850
1892
|
QueryTokens \= [],
|
|
1851
|
-
|
|
1852
|
-
( kb_index_entity(Id, _),
|
|
1853
|
-
(TypeFilter == none -> true ; kb_index_type(TypeFilter, Id)),
|
|
1854
|
-
( indexed_markdown_source(Id)
|
|
1855
|
-
; forall(member(QueryToken, QueryTokens),
|
|
1856
|
-
indexed_token_match(QueryToken, Id)) ) ),
|
|
1857
|
-
RawIds),
|
|
1858
|
-
sort(RawIds, Ids),
|
|
1893
|
+
search_index_ids(TypeFilter, QueryTokens, Ids),
|
|
1859
1894
|
length(Ids, Count),
|
|
1860
1895
|
drop_index_ids(Offset, Ids, Remaining),
|
|
1861
1896
|
take_index_ids(Limit, Remaining, PageIds),
|
|
1862
1897
|
search_candidate_rows(PageIds, Rows).
|
|
1863
1898
|
|
|
1899
|
+
% Callers read a large candidate set page by page, each page a separate
|
|
1900
|
+
% query, so the ids matched for the last query are kept for its next pages
|
|
1901
|
+
% instead of scanning the token index again. The memo is keyed like the index
|
|
1902
|
+
% verification (graph, RDF generation and index size), so any write starts a
|
|
1903
|
+
% fresh scan.
|
|
1904
|
+
search_index_ids(TypeFilter, QueryTokens, Ids) :-
|
|
1905
|
+
( kb_index_entity_count(IndexCount)
|
|
1906
|
+
-> true
|
|
1907
|
+
; IndexCount = none
|
|
1908
|
+
),
|
|
1909
|
+
index_verification_key(IndexCount, Key),
|
|
1910
|
+
( kb_search_ids_memo(Key, TypeFilter, QueryTokens, Cached)
|
|
1911
|
+
-> Ids = Cached
|
|
1912
|
+
; findall(Id,
|
|
1913
|
+
( kb_index_entity(Id, _),
|
|
1914
|
+
(TypeFilter == none -> true ; kb_index_type(TypeFilter, Id)),
|
|
1915
|
+
( indexed_markdown_source(Id)
|
|
1916
|
+
; forall(member(QueryToken, QueryTokens),
|
|
1917
|
+
indexed_token_match(QueryToken, Id)) ) ),
|
|
1918
|
+
RawIds),
|
|
1919
|
+
sort(RawIds, Ids),
|
|
1920
|
+
retractall(kb_search_ids_memo(_, _, _, _)),
|
|
1921
|
+
assertz(kb_search_ids_memo(Key, TypeFilter, QueryTokens, Ids))
|
|
1922
|
+
).
|
|
1923
|
+
|
|
1864
1924
|
%% kb_list_search_candidates(+Type, +Limit, +Offset, -Rows, -Count)
|
|
1865
1925
|
% Page every indexed entity (optionally of one type) as projected search
|
|
1866
1926
|
% candidate rows, ordered by id. Semantic discovery uses it when no lexical
|
|
@@ -1978,6 +2038,25 @@ kb_assert_relationship(RelType, FromId, ToId, Metadata) :-
|
|
|
1978
2038
|
kb_log_relationship_upsert(RelType, FromId, ToId, Metadata)
|
|
1979
2039
|
).
|
|
1980
2040
|
|
|
2041
|
+
%% kb_assert_relationships_reporting(+Relationships, -FailedPositions)
|
|
2042
|
+
% Assert each rel(Type, From, To) of Relationships with kb_assert_relationship/4
|
|
2043
|
+
% (empty metadata), in order, keeping every one that succeeds. FailedPositions
|
|
2044
|
+
% lists the 1-based positions of those that failed or raised; their writes are
|
|
2045
|
+
% rolled back with their own transaction. Sync uses it after a batch
|
|
2046
|
+
% transaction fails, so one dangling link no longer sends the whole batch
|
|
2047
|
+
% through one round trip per relationship.
|
|
2048
|
+
kb_assert_relationships_reporting(Relationships, FailedPositions) :-
|
|
2049
|
+
foldl(assert_relationship_reporting, Relationships, 1-[], _-Failed0),
|
|
2050
|
+
reverse(Failed0, FailedPositions).
|
|
2051
|
+
|
|
2052
|
+
assert_relationship_reporting(rel(RelType, FromId, ToId), Position-Failed0, Next-Failed) :-
|
|
2053
|
+
Next is Position + 1,
|
|
2054
|
+
% mutalog-disable-next-line literal: an unbound metadata entry is ignored like an empty list
|
|
2055
|
+
( catch(kb_assert_relationship(RelType, FromId, ToId, []), _, fail)
|
|
2056
|
+
-> Failed = Failed0
|
|
2057
|
+
; Failed = [Position|Failed0]
|
|
2058
|
+
).
|
|
2059
|
+
|
|
1981
2060
|
%% kb_assert_relationship_no_audit(+Type, +From, +To, +Metadata)
|
|
1982
2061
|
% Assert a relationship RDF payload without recording audit side effects.
|
|
1983
2062
|
% Used by write-gated MCP transactions so failed contradiction checks do not
|
|
@@ -2181,6 +2260,37 @@ kb_relationship_with_reluri(RelURI, Graph, FromId, ToId) :-
|
|
|
2181
2260
|
entity_uri_to_id(FromURI, FromId),
|
|
2182
2261
|
entity_uri_to_id(ToURI, ToId).
|
|
2183
2262
|
|
|
2263
|
+
%% kb_relationship_edges(+Types, +Ids, -Edges)
|
|
2264
|
+
% implements REQ-mcp-search-discovery
|
|
2265
|
+
% Every [Type, From, To] relationship of one of Types that starts or ends at
|
|
2266
|
+
% one of Ids (a set), in the order and with the multiplicity of
|
|
2267
|
+
% findall([T,F,O], (member(T, Types), kb_relationship(T, F, O),
|
|
2268
|
+
% (member(F, Ids) ; member(O, Ids))), Edges)
|
|
2269
|
+
% Search reads the graph around its results this way. Ends are compared as
|
|
2270
|
+
% URIs, so only the matching edges are converted back to ids rather than
|
|
2271
|
+
% every edge of every type.
|
|
2272
|
+
kb_relationship_edges(Types, Ids, Edges) :-
|
|
2273
|
+
kb_graph(Graph),
|
|
2274
|
+
kb_uri(BaseURI),
|
|
2275
|
+
atom_concat(BaseURI, 'entity/', Prefix),
|
|
2276
|
+
findall(URI,
|
|
2277
|
+
( member(Id, Ids),
|
|
2278
|
+
( atom_concat(Prefix, Id, URI)
|
|
2279
|
+
; atom_concat('kb:entity/', Id, URI)
|
|
2280
|
+
) ),
|
|
2281
|
+
URIs0),
|
|
2282
|
+
sort(URIs0, URIs),
|
|
2283
|
+
findall([Type, From, To],
|
|
2284
|
+
( member(Type, Types),
|
|
2285
|
+
atom_concat(BaseURI, Type, RelURI),
|
|
2286
|
+
rdf(FromURI, RelURI, ToURI, Graph),
|
|
2287
|
+
( ord_memberchk(FromURI, URIs)
|
|
2288
|
+
; ord_memberchk(ToURI, URIs)
|
|
2289
|
+
),
|
|
2290
|
+
entity_uri_to_id(FromURI, From),
|
|
2291
|
+
entity_uri_to_id(ToURI, To) ),
|
|
2292
|
+
Edges).
|
|
2293
|
+
|
|
2184
2294
|
% Helper predicates
|
|
2185
2295
|
|
|
2186
2296
|
%% entity_id_to_uri(+Id, -URI)
|
|
@@ -2639,13 +2749,7 @@ contradicting_reqs(ReqA, ReqB, Reason) :-
|
|
|
2639
2749
|
% contradiction. This remains deliberately syntactic: differently shaped
|
|
2640
2750
|
% terms are never treated as equivalent merely because their prose is similar.
|
|
2641
2751
|
req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
2642
|
-
|
|
2643
|
-
current_req(ReqB),
|
|
2644
|
-
ReqA @< ReqB,
|
|
2645
|
-
kb_relationship(constrains, ReqA, SubjectFactA),
|
|
2646
|
-
kb_relationship(constrains, ReqB, SubjectFactB),
|
|
2647
|
-
fact_subject_key(SubjectFactA, SubjectKey),
|
|
2648
|
-
fact_subject_key(SubjectFactB, SubjectKey),
|
|
2752
|
+
subject_conflict_pair(ReqA, ReqB, SubjectKey),
|
|
2649
2753
|
effective_req_property_fact(ReqA, SubjectKey, FactA, PropertyKey, OpA, ValTypeA, ValA, UnitA, ScopeA, PolarityA, ValidFromA, ValidToA),
|
|
2650
2754
|
effective_req_property_fact(ReqB, SubjectKey, FactB, PropertyKey, OpB, ValTypeB, ValB, UnitB, ScopeB, PolarityB, ValidFromB, ValidToB),
|
|
2651
2755
|
FactA \= FactB,
|
|
@@ -2673,11 +2777,7 @@ req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
|
2673
2777
|
right: Right
|
|
2674
2778
|
}.
|
|
2675
2779
|
req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
2676
|
-
|
|
2677
|
-
current_req(ReqB),
|
|
2678
|
-
ReqA @< ReqB,
|
|
2679
|
-
effective_req_predicate(ReqA, FactA, Namespace, Name, Args, PolarityA),
|
|
2680
|
-
effective_req_predicate(ReqB, FactB, Namespace, Name, Args, PolarityB),
|
|
2780
|
+
predicate_conflict_pair(ReqA, ReqB, FactA, FactB, Namespace, Name, Args, PolarityA, PolarityB),
|
|
2681
2781
|
FactA \= FactB,
|
|
2682
2782
|
opposite_predicate_polarity(PolarityA, PolarityB),
|
|
2683
2783
|
atomic_list_concat(Args, ',', ArgsText),
|
|
@@ -2757,6 +2857,143 @@ req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
|
2757
2857
|
right: Right
|
|
2758
2858
|
}.
|
|
2759
2859
|
|
|
2860
|
+
% Cost: the search answer layer and the upsert contradiction check ask for
|
|
2861
|
+
% the witnesses of one requirement with the other side unbound, and kb_check
|
|
2862
|
+
% asks for every pair. Enumerating every current requirement as the partner
|
|
2863
|
+
% and only then reading either side's facts cost a full requirement scan per
|
|
2864
|
+
% requirement (quadratic for kb_check). The pairings below return the same
|
|
2865
|
+
% solutions in the same order as that enumeration: partners come from an
|
|
2866
|
+
% index of the current requirements constraining each subject or stating
|
|
2867
|
+
% each predicate, visited in the order current_req/1 enumerates them, so a
|
|
2868
|
+
% requirement without such facts has no partners at all.
|
|
2869
|
+
subject_conflict_pair(ReqA, ReqB, SubjectKey) :-
|
|
2870
|
+
% The mode tests only pick the cheapest route: every route gives the
|
|
2871
|
+
% same solutions in the same order for the arguments it is given.
|
|
2872
|
+
% mutalog-disable-next-line negate,goal_true,goal_fail: routing only; the later branches give the same pairs
|
|
2873
|
+
( nonvar(ReqA), nonvar(ReqB)
|
|
2874
|
+
-> current_req(ReqA),
|
|
2875
|
+
current_req(ReqB),
|
|
2876
|
+
ReqA @< ReqB
|
|
2877
|
+
% mutalog-disable-next-line negate,goal_true,goal_fail: routing only; the last branch gives the same pairs
|
|
2878
|
+
; nonvar(ReqB)
|
|
2879
|
+
-> current_req(ReqB),
|
|
2880
|
+
req_subject_partners(ReqB, before, Partners),
|
|
2881
|
+
member(ReqA, Partners)
|
|
2882
|
+
; current_req(ReqA),
|
|
2883
|
+
req_subject_partners(ReqA, after, Partners),
|
|
2884
|
+
member(ReqB, Partners)
|
|
2885
|
+
),
|
|
2886
|
+
kb_relationship(constrains, ReqA, SubjectFactA),
|
|
2887
|
+
kb_relationship(constrains, ReqB, SubjectFactB),
|
|
2888
|
+
fact_subject_key(SubjectFactA, SubjectKey),
|
|
2889
|
+
fact_subject_key(SubjectFactB, SubjectKey).
|
|
2890
|
+
|
|
2891
|
+
%% req_subject_partners(+ReqId, +Side, -Partners)
|
|
2892
|
+
% Current requirements constraining a subject that ReqId constrains, in
|
|
2893
|
+
% current_req/1 order: those after ReqId in standard order (Side = after) or
|
|
2894
|
+
% before it (Side = before).
|
|
2895
|
+
req_subject_partners(ReqId, Side, Partners) :-
|
|
2896
|
+
req_subject_index(Index),
|
|
2897
|
+
findall(Position-Partner,
|
|
2898
|
+
( req_subject_fact_key(ReqId, SubjectKey),
|
|
2899
|
+
get_assoc(SubjectKey, Index, Entries),
|
|
2900
|
+
member(Position-Partner, Entries),
|
|
2901
|
+
subject_partner_side(Side, ReqId, Partner) ),
|
|
2902
|
+
Partners0),
|
|
2903
|
+
sort(Partners0, Partners1),
|
|
2904
|
+
pairs_values(Partners1, Partners).
|
|
2905
|
+
|
|
2906
|
+
% mutalog-disable-next-line cut_insert: the comparison has at most one solution
|
|
2907
|
+
subject_partner_side(after, ReqId, Partner) :- ReqId @< Partner.
|
|
2908
|
+
subject_partner_side(before, ReqId, Partner) :- Partner @< ReqId.
|
|
2909
|
+
|
|
2910
|
+
req_subject_fact_key(ReqId, SubjectKey) :-
|
|
2911
|
+
% mutalog-disable-next-line goal_true: extra partners are dropped by the pair's own constrains check
|
|
2912
|
+
kb_relationship(constrains, ReqId, SubjectFactId),
|
|
2913
|
+
fact_subject_key(SubjectFactId, SubjectKey).
|
|
2914
|
+
|
|
2915
|
+
% Memoized per KB generation, like the predicate index below.
|
|
2916
|
+
req_subject_index(Index) :-
|
|
2917
|
+
index_verification_key(req_subjects, Key),
|
|
2918
|
+
( kb_req_subject_memo(Key, Cached)
|
|
2919
|
+
-> Index = Cached
|
|
2920
|
+
; findall(ReqId, current_req(ReqId), ReqIds),
|
|
2921
|
+
findall(SubjectKey-(Position-ReqId),
|
|
2922
|
+
( nth1(Position, ReqIds, ReqId),
|
|
2923
|
+
req_subject_fact_key(ReqId, SubjectKey) ),
|
|
2924
|
+
Pairs0),
|
|
2925
|
+
sort(Pairs0, Pairs),
|
|
2926
|
+
group_pairs_by_key(Pairs, Grouped),
|
|
2927
|
+
list_to_assoc(Grouped, Computed),
|
|
2928
|
+
retractall(kb_req_subject_memo(_, _)),
|
|
2929
|
+
assertz(kb_req_subject_memo(Key, Computed)),
|
|
2930
|
+
Index = Computed
|
|
2931
|
+
).
|
|
2932
|
+
|
|
2933
|
+
predicate_conflict_pair(ReqA, ReqB, FactA, FactB, Namespace, Name, Args, PolarityA, PolarityB) :-
|
|
2934
|
+
( nonvar(ReqA), var(ReqB)
|
|
2935
|
+
-> current_req(ReqA),
|
|
2936
|
+
findall(Position-Partner,
|
|
2937
|
+
( effective_req_predicate(ReqA, _, PartnerNs, PartnerName, PartnerArgs, _),
|
|
2938
|
+
current_req_predicate(PartnerNs-PartnerName-PartnerArgs, Position, Partner),
|
|
2939
|
+
ReqA @< Partner ),
|
|
2940
|
+
Partners0),
|
|
2941
|
+
sort(Partners0, Partners),
|
|
2942
|
+
member(_-ReqB, Partners)
|
|
2943
|
+
; nonvar(ReqB), var(ReqA)
|
|
2944
|
+
-> current_req(ReqB),
|
|
2945
|
+
findall(Position-Partner,
|
|
2946
|
+
( effective_req_predicate(ReqB, _, PartnerNs, PartnerName, PartnerArgs, _),
|
|
2947
|
+
current_req_predicate(PartnerNs-PartnerName-PartnerArgs, Position, Partner),
|
|
2948
|
+
Partner @< ReqB ),
|
|
2949
|
+
Partners0),
|
|
2950
|
+
sort(Partners0, Partners),
|
|
2951
|
+
member(_-ReqA, Partners)
|
|
2952
|
+
% mutalog-disable-next-line negate,goal_true,goal_fail: routing only; the last branch gives the same pairs
|
|
2953
|
+
; nonvar(ReqA), nonvar(ReqB)
|
|
2954
|
+
-> current_req(ReqA),
|
|
2955
|
+
current_req(ReqB),
|
|
2956
|
+
ReqA @< ReqB
|
|
2957
|
+
; current_req(ReqA),
|
|
2958
|
+
findall(Position-Partner,
|
|
2959
|
+
( effective_req_predicate(ReqA, _, PartnerNs, PartnerName, PartnerArgs, _),
|
|
2960
|
+
current_req_predicate(PartnerNs-PartnerName-PartnerArgs, Position, Partner),
|
|
2961
|
+
ReqA @< Partner ),
|
|
2962
|
+
Partners0),
|
|
2963
|
+
sort(Partners0, Partners),
|
|
2964
|
+
member(_-ReqB, Partners)
|
|
2965
|
+
),
|
|
2966
|
+
effective_req_predicate(ReqA, FactA, Namespace, Name, Args, PolarityA),
|
|
2967
|
+
effective_req_predicate(ReqB, FactB, Namespace, Name, Args, PolarityB).
|
|
2968
|
+
|
|
2969
|
+
%% current_req_predicate(+Signature, -Position, -ReqId)
|
|
2970
|
+
% A current requirement stating a predicate fact with Signature
|
|
2971
|
+
% (Namespace-Name-Args), and its position in current_req/1 order.
|
|
2972
|
+
current_req_predicate(Signature, Position, ReqId) :-
|
|
2973
|
+
req_predicate_index(Index),
|
|
2974
|
+
get_assoc(Signature, Index, Entries),
|
|
2975
|
+
member(Position-ReqId, Entries).
|
|
2976
|
+
|
|
2977
|
+
% Memoized per KB generation, like the decision signatures: reading a
|
|
2978
|
+
% predicate fact decodes its entity, and every lookup would otherwise read
|
|
2979
|
+
% the predicate facts of every requirement.
|
|
2980
|
+
req_predicate_index(Index) :-
|
|
2981
|
+
index_verification_key(req_predicates, Key),
|
|
2982
|
+
( kb_req_predicate_memo(Key, Cached)
|
|
2983
|
+
-> Index = Cached
|
|
2984
|
+
; findall(ReqId, current_req(ReqId), ReqIds),
|
|
2985
|
+
findall((Namespace-Name-Args)-(Position-ReqId),
|
|
2986
|
+
( nth1(Position, ReqIds, ReqId),
|
|
2987
|
+
effective_req_predicate(ReqId, _, Namespace, Name, Args, _) ),
|
|
2988
|
+
Pairs0),
|
|
2989
|
+
sort(Pairs0, Pairs),
|
|
2990
|
+
group_pairs_by_key(Pairs, Grouped),
|
|
2991
|
+
list_to_assoc(Grouped, Computed),
|
|
2992
|
+
retractall(kb_req_predicate_memo(_, _)),
|
|
2993
|
+
assertz(kb_req_predicate_memo(Key, Computed)),
|
|
2994
|
+
Index = Computed
|
|
2995
|
+
).
|
|
2996
|
+
|
|
2760
2997
|
%% kb_domain_contradiction_pairs_examined(-Count)
|
|
2761
2998
|
% implements REQ-search-answer-hygiene
|
|
2762
2999
|
% How many distinct pairs of requirement facts the domain-contradictions
|
|
@@ -2772,22 +3009,12 @@ kb_domain_contradiction_pairs_examined(Count) :-
|
|
|
2772
3009
|
length(Pairs, Count).
|
|
2773
3010
|
|
|
2774
3011
|
domain_contradiction_candidate_pair(FactA, FactB) :-
|
|
2775
|
-
|
|
2776
|
-
current_req(ReqB),
|
|
2777
|
-
ReqA @< ReqB,
|
|
2778
|
-
kb_relationship(constrains, ReqA, SubjectFactA),
|
|
2779
|
-
kb_relationship(constrains, ReqB, SubjectFactB),
|
|
2780
|
-
fact_subject_key(SubjectFactA, SubjectKey),
|
|
2781
|
-
fact_subject_key(SubjectFactB, SubjectKey),
|
|
3012
|
+
subject_conflict_pair(ReqA, ReqB, SubjectKey),
|
|
2782
3013
|
effective_req_property_fact(ReqA, SubjectKey, FactA, PropertyKey, _, _, _, _, _, _, _, _),
|
|
2783
3014
|
effective_req_property_fact(ReqB, SubjectKey, FactB, PropertyKey, _, _, _, _, _, _, _, _),
|
|
2784
3015
|
FactA \= FactB.
|
|
2785
3016
|
domain_contradiction_candidate_pair(FactA, FactB) :-
|
|
2786
|
-
|
|
2787
|
-
current_req(ReqB),
|
|
2788
|
-
ReqA @< ReqB,
|
|
2789
|
-
effective_req_predicate(ReqA, FactA, Namespace, Name, Args, _),
|
|
2790
|
-
effective_req_predicate(ReqB, FactB, Namespace, Name, Args, _),
|
|
3017
|
+
predicate_conflict_pair(_ReqA, _ReqB, FactA, FactB, _Namespace, _Name, _Args, _, _),
|
|
2791
3018
|
FactA \= FactB.
|
|
2792
3019
|
domain_contradiction_candidate_pair(FactA, FactB) :-
|
|
2793
3020
|
decision_signatures(Signatures),
|
|
@@ -3023,7 +3250,32 @@ comparison_quantity(ValType, Value, Unit, Type, CanonValue, CanonUnit) :-
|
|
|
3023
3250
|
|
|
3024
3251
|
%% predicate_schema(+FactId, -Namespace, -Name, -Arity, -ArgumentNames, -ArgumentTypes)
|
|
3025
3252
|
% Read one project-local ontology predicate schema fact.
|
|
3253
|
+
% Finding the schemas of a predicate scans every fact, and contradiction
|
|
3254
|
+
% witnesses, decision signatures and key lookups ask for them per candidate,
|
|
3255
|
+
% so the schema rows are memoized per KB generation (outside RDF
|
|
3256
|
+
% transactions), in the order the scan finds them.
|
|
3026
3257
|
predicate_schema(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes) :-
|
|
3258
|
+
var(FactId),
|
|
3259
|
+
\+ rdf_active_transaction(_),
|
|
3260
|
+
!,
|
|
3261
|
+
predicate_schema_rows(Rows),
|
|
3262
|
+
member(schema(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes), Rows).
|
|
3263
|
+
predicate_schema(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes) :-
|
|
3264
|
+
predicate_schema_scan(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes).
|
|
3265
|
+
|
|
3266
|
+
predicate_schema_rows(Rows) :-
|
|
3267
|
+
index_verification_key(predicate_schemas, Key),
|
|
3268
|
+
( kb_predicate_schema_memo(Key, Cached)
|
|
3269
|
+
-> Rows = Cached
|
|
3270
|
+
; findall(schema(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes),
|
|
3271
|
+
predicate_schema_scan(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes),
|
|
3272
|
+
Computed),
|
|
3273
|
+
retractall(kb_predicate_schema_memo(_, _)),
|
|
3274
|
+
assertz(kb_predicate_schema_memo(Key, Computed)),
|
|
3275
|
+
Rows = Computed
|
|
3276
|
+
).
|
|
3277
|
+
|
|
3278
|
+
predicate_schema_scan(FactId, Namespace, Name, Arity, ArgumentNames, ArgumentTypes) :-
|
|
3027
3279
|
kb_entity(FactId, fact, Props),
|
|
3028
3280
|
memberchk(fact_kind=KindRaw, Props),
|
|
3029
3281
|
normalize_term_atom(KindRaw, predicate_schema),
|
package/src/kb_consistency.pl
CHANGED
|
@@ -58,7 +58,22 @@ check_kb_consistency_unresolved(Violations) :-
|
|
|
58
58
|
Unsorted),
|
|
59
59
|
sort(Unsorted, Violations).
|
|
60
60
|
|
|
61
|
+
% Both rules read the same verification, so it is produced once per KB
|
|
62
|
+
% generation (recomputed inside an RDF transaction).
|
|
61
63
|
consistency_verification(Bundle, Report) :-
|
|
64
|
+
( \+ rdf_db:rdf_active_transaction(_),
|
|
65
|
+
kb:index_verification_key(kb_consistency, Key)
|
|
66
|
+
-> ( kb:kb_consistency_memo(Key, Bundle0, Report0)
|
|
67
|
+
-> Bundle = Bundle0,
|
|
68
|
+
Report = Report0
|
|
69
|
+
; compute_consistency_verification(Bundle, Report),
|
|
70
|
+
retractall(kb:kb_consistency_memo(_, _, _)),
|
|
71
|
+
assertz(kb:kb_consistency_memo(Key, Bundle, Report))
|
|
72
|
+
)
|
|
73
|
+
; compute_consistency_verification(Bundle, Report)
|
|
74
|
+
).
|
|
75
|
+
|
|
76
|
+
compute_consistency_verification(Bundle, Report) :-
|
|
62
77
|
kb_certificates(Produced),
|
|
63
78
|
with_output_to(string(Json), json_write_dict(current_output, Produced, [width(0)])),
|
|
64
79
|
open_string(Json, Stream),
|