001package gudusoft.gsqlparser.lineage.v2.fold; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006import java.util.Map; 007import java.util.Set; 008import java.util.SortedSet; 009import java.util.TreeSet; 010 011/** 012 * What FOLD-V1 yields for one statement ({@code algorithms/fold-v1.md}, Section 2, item 1): the Fact 013 * Occurrences, the FactCandidates, and the requirements on every write of a field. References are the 014 * document-local {@code ref}s of the document the statement was folded from. 015 * 016 * @since 4.2.17 017 */ 018public final class StatementFold { 019 020 private final long statementRef; 021 private final List<FactOccurrence> facts; 022 private final List<Candidate> candidates; 023 private final List<WriteRequirement> writes; 024 025 StatementFold(long statementRef, List<FactOccurrence> facts, List<Candidate> candidates, 026 List<WriteRequirement> writes) { 027 this.statementRef = statementRef; 028 this.facts = Collections.unmodifiableList(new ArrayList<FactOccurrence>(facts)); 029 this.candidates = Collections.unmodifiableList(new ArrayList<Candidate>(candidates)); 030 this.writes = Collections.unmodifiableList(new ArrayList<WriteRequirement>(writes)); 031 } 032 033 public long getStatementRef() { 034 return statementRef; 035 } 036 037 /** One entry per Fact Occurrence (Section 8.1), ordered by source, target, label, path and ordinal. */ 038 public List<FactOccurrence> getFacts() { 039 return facts; 040 } 041 042 /** One entry per FactCandidate (Section 7.1, items 4 to 6). */ 043 public List<Candidate> getCandidates() { 044 return candidates; 045 } 046 047 /** One entry per field the statement writes (Sections 7.4 and 7.5), ordered by target. */ 048 public List<WriteRequirement> getWrites() { 049 return writes; 050 } 051 052 static <T> List<T> frozen(List<T> list) { 053 return Collections.unmodifiableList(new ArrayList<T>(list)); 054 } 055 056 static List<List<Long>> frozenWalks(List<List<Long>> walks) { 057 List<List<Long>> out = new ArrayList<List<Long>>(); 058 for (List<Long> walk : walks) { 059 out.add(Collections.unmodifiableList(new ArrayList<Long>(walk))); 060 } 061 return Collections.unmodifiableList(out); 062 } 063 064 /** A detached, frozen copy of a binding, so that no result aliases the document it was folded from. */ 065 static Map<?, ?> freeze(Map<?, ?> binding) { 066 return binding == null ? null : (Map<?, ?>) gudusoft.gsqlparser.lineage.v2.json.CanonicalJson.immutableCopy(binding); 067 } 068 069 static SortedSet<Long> frozen(Set<Long> set) { 070 return Collections.unmodifiableSortedSet(new TreeSet<Long>(set)); 071 } 072 073 /** One (source, target) pair of an outcome (Section 7.1, item 5). */ 074 public static final class Pair { 075 private final Object source; 076 private final Object target; 077 078 public Pair(Object source, Object target) { 079 this.source = source; 080 this.target = target; 081 } 082 083 /** The source ref; for the candidate set of an {@code UNRESOLVED} reference, that set's ref. */ 084 public Object getSource() { 085 return source; 086 } 087 088 public Object getTarget() { 089 return target; 090 } 091 092 @Override 093 public boolean equals(Object other) { 094 if (!(other instanceof Pair)) { 095 return false; 096 } 097 Pair pair = (Pair) other; 098 return FoldKernel.same(source, pair.source) && FoldKernel.same(target, pair.target); 099 } 100 101 @Override 102 public int hashCode() { 103 return FoldKernel.hash(source) * 31 + FoldKernel.hash(target); 104 } 105 106 @Override 107 public String toString() { 108 return "(" + source + ", " + target + ")"; 109 } 110 } 111 112 /** 113 * One end of a FactCandidate: a fixed endpoint, or a candidate set with its membership, and, when another reference 114 * decides it (fold-v1 Section 7.1, item 5), the decision. 115 */ 116 public static final class End { 117 private final Object endpointRef; 118 private final List<Object> members; 119 private final Object membership; 120 private final Decision decision; 121 122 private End(Object endpointRef, List<Object> members, Object membership, Decision decision) { 123 this.endpointRef = endpointRef; 124 this.members = members; 125 this.membership = membership; 126 this.decision = decision; 127 } 128 129 static End fixed(Object endpointRef) { 130 return new End(endpointRef, null, null, null); 131 } 132 133 static End set(List<Object> members, Object membership) { 134 return set(members, membership, null); 135 } 136 137 static End set(List<Object> members, Object membership, Decision decision) { 138 return new End(null, Collections.unmodifiableList(new ArrayList<Object>(members)), membership, decision); 139 } 140 141 /** How another reference decides this candidate-set end; null when none does (or for a fixed end). */ 142 public Decision getDecision() { 143 return decision; 144 } 145 146 public boolean isFixed() { 147 return members == null; 148 } 149 150 /** The endpoint of a fixed end; null for a candidate set. */ 151 public Object getEndpointRef() { 152 return endpointRef; 153 } 154 155 /** The members of a candidate-set end, sorted; null for a fixed end. */ 156 public List<Object> getMembers() { 157 return members; 158 } 159 160 /** {@code COMPLETE} or {@code INCOMPLETE} for a candidate-set end; null for a fixed end. */ 161 public Object getMembership() { 162 return membership; 163 } 164 165 @Override 166 public boolean equals(Object other) { 167 if (!(other instanceof End)) { 168 return false; 169 } 170 End end = (End) other; 171 if (isFixed() != end.isFixed()) { 172 return false; 173 } 174 if (isFixed()) { 175 return FoldKernel.same(endpointRef, end.endpointRef); 176 } 177 if (members.size() != end.members.size() || !FoldKernel.same(membership, end.membership) 178 || (decision == null ? end.decision != null : !decision.equals(end.decision))) { 179 return false; 180 } 181 for (int i = 0; i < members.size(); i++) { 182 if (!FoldKernel.same(members.get(i), end.members.get(i))) { 183 return false; 184 } 185 } 186 return true; 187 } 188 189 @Override 190 public int hashCode() { 191 if (isFixed()) { 192 return FoldKernel.hash(endpointRef); 193 } 194 int h = FoldKernel.hash(membership); 195 for (Object member : members) { 196 h = h * 31 + FoldKernel.hash(member); 197 } 198 return h; 199 } 200 201 @Override 202 public String toString() { 203 return isFixed() ? String.valueOf(endpointRef) : "SET " + membership + " " + members 204 + (decision == null ? "" : " " + decision); 205 } 206 } 207 208 /** 209 * How a reference decides a FactCandidate's candidate-set end (fold-v1 Section 7.1, item 5): the deciding 210 * reference's candidate set (in the ExplainGraph; at a published end, the document's set with the same members), 211 * and the pairs {alternative, member}, sorted. Two decisions are equal when the deciding sets have the same members 212 * and membership and the pairs are equal. 213 */ 214 public static final class Decision { 215 private final Object decidingRef; 216 private final List<Object> alternatives; 217 private final Object membership; 218 private final List<Pair> alignment; 219 220 Decision(Object decidingRef, List<Object> alternatives, Object membership, List<Pair> alignment) { 221 this.decidingRef = decidingRef; 222 List<Object> sorted = new ArrayList<Object>(alternatives); 223 Collections.sort(sorted, FoldKernel.REF_ORDER); 224 this.alternatives = Collections.unmodifiableList(sorted); 225 this.membership = membership; 226 List<Pair> pairs = new ArrayList<Pair>(alignment); 227 Collections.sort(pairs, new java.util.Comparator<Pair>() { 228 @Override 229 public int compare(Pair a, Pair b) { 230 int c = FoldKernel.REF_ORDER.compare(a.getSource(), b.getSource()); 231 return c != 0 ? c : FoldKernel.REF_ORDER.compare(a.getTarget(), b.getTarget()); 232 } 233 }); 234 this.alignment = Collections.unmodifiableList(pairs); 235 } 236 237 /** The deciding reference's candidate set. */ 238 public Object getDecidingRef() { 239 return decidingRef; 240 } 241 242 /** The members of the deciding set, sorted. */ 243 public List<Object> getAlternatives() { 244 return alternatives; 245 } 246 247 public Object getMembership() { 248 return membership; 249 } 250 251 /** The pairs: source is the alternative, target the member of the end. */ 252 public List<Pair> getAlignment() { 253 return alignment; 254 } 255 256 @Override 257 public boolean equals(Object other) { 258 if (!(other instanceof Decision)) { 259 return false; 260 } 261 Decision d = (Decision) other; 262 return alternatives.equals(d.alternatives) && FoldKernel.same(membership, d.membership) 263 && alignment.equals(d.alignment); 264 } 265 266 @Override 267 public int hashCode() { 268 return alternatives.hashCode() * 31 + alignment.hashCode(); 269 } 270 271 @Override 272 public String toString() { 273 return "DECIDED " + alternatives + " " + membership + " " + alignment; 274 } 275 } 276 277 /** A Fact Occurrence (Section 8.1): the proposition, its path and ordinal, proof, bindings and support. */ 278 public static final class FactOccurrence { 279 private final Object sourceRef; 280 private final Object targetRef; 281 private final FoldLabel label; 282 private final Object path; 283 private final Long offset; 284 private final int ordinal; 285 private final String proofStatus; 286 private final SortedSet<Long> support; 287 private final Map<?, ?> sourceBinding; 288 private final Map<?, ?> targetBinding; 289 290 private final List<List<Long>> supportWalks; 291 292 FactOccurrence(Object sourceRef, Object targetRef, FoldLabel label, Object path, Long offset, int ordinal, 293 String proofStatus, Set<Long> support, Map<?, ?> sourceBinding, Map<?, ?> targetBinding, 294 List<List<Long>> supportWalks) { 295 this.supportWalks = frozenWalks(supportWalks); 296 this.sourceRef = sourceRef; 297 this.targetRef = targetRef; 298 this.label = label; 299 this.path = path; 300 this.offset = offset; 301 this.ordinal = ordinal; 302 this.proofStatus = proofStatus; 303 this.support = frozen(support); 304 this.sourceBinding = freeze(sourceBinding); 305 this.targetBinding = freeze(targetBinding); 306 } 307 308 public Object getSourceRef() { 309 return sourceRef; 310 } 311 312 public Object getTargetRef() { 313 return targetRef; 314 } 315 316 public FoldLabel getLabel() { 317 return label; 318 } 319 320 /** The semantic path of the reference read by the first edge ({@code referencePath}), or null. */ 321 public Object getPath() { 322 return path; 323 } 324 325 /** The UTF-8 offset of that reference ({@code referenceStart}), or null. */ 326 public Long getOffset() { 327 return offset; 328 } 329 330 /** The rank among the Occurrences of the same Fact and path, by the position of the reference. */ 331 public int getOrdinal() { 332 return ordinal; 333 } 334 335 /** {@code PROVEN} or {@code ASSUMED} (Section 7.2, item 2). */ 336 public String getProofStatus() { 337 return proofStatus; 338 } 339 340 /** The micro-edges of the support subgraph (Section 8.2, item 1). */ 341 public SortedSet<Long> getSupport() { 342 return support; 343 } 344 345 /** 346 * Fold walks (micro-edge refs in walk order) that each yield this Occurrence and together cover its support 347 * subgraph: the {@code supportPaths} to publish (Section 8.2, items 3 and 4). 348 */ 349 public List<List<Long>> getSupportWalks() { 350 return supportWalks; 351 } 352 353 /** 354 * The source-side binding of the first edge (Section 8.1, item 2), or null when it has none. When several 355 * walks support the Occurrence, the binding comes from a walk that decides its proof (an unconditional 356 * {@code PROVEN} walk for a {@code PROVEN} Occurrence), and among those from the first edge earliest in 357 * the text. 358 */ 359 public Map<?, ?> getSourceBinding() { 360 return sourceBinding; 361 } 362 363 /** The target-side binding of the last edge, chosen like {@link #getSourceBinding()}. */ 364 public Map<?, ?> getTargetBinding() { 365 return targetBinding; 366 } 367 368 @Override 369 public String toString() { 370 return sourceRef + " -" + label + "-> " + targetRef + " @" + path + "#" + ordinal + " " + proofStatus; 371 } 372 } 373 374 /** 375 * The binding of one side of a FactCandidate Occurrence (Section 7.1, item 6). When 376 * {@link #namesOwnCandidateSet()} is true, the binding's {@code candidateSetRef} stands for the candidate set 377 * of that side of the FactCandidate itself, whose ref the producer assigns. 378 */ 379 public static final class CandidateBinding { 380 private final Map<?, ?> binding; 381 private final boolean ownCandidateSet; 382 383 CandidateBinding(Map<?, ?> binding, boolean ownCandidateSet) { 384 this.binding = freeze(binding); 385 this.ownCandidateSet = ownCandidateSet; 386 } 387 388 /** The binding as found on the micro-edge, or null when the edge has none. */ 389 public Map<?, ?> getBinding() { 390 return binding; 391 } 392 393 public boolean namesOwnCandidateSet() { 394 return ownCandidateSet; 395 } 396 397 @Override 398 public String toString() { 399 return binding + (ownCandidateSet ? " (own candidate set)" : ""); 400 } 401 } 402 403 /** A FactCandidate (Section 7.1, items 4 to 6) with its Occurrence. */ 404 public static final class Candidate { 405 private final FoldLabel label; 406 private final List<Object> references; 407 private final End source; 408 private final End target; 409 private final Set<Set<Pair>> outcomes; 410 private final Set<Set<Pair>> effectiveOutcomes; 411 private final String proofStatus; 412 private final SortedSet<Long> support; 413 private final Object path; 414 private final Long offset; 415 int ordinal; 416 CandidateBinding sourceBinding; 417 CandidateBinding targetBinding; 418 419 private final List<List<Long>> supportWalks; 420 421 Candidate(FoldLabel label, List<Object> references, End source, End target, Set<Set<Pair>> outcomes, 422 Set<Set<Pair>> effectiveOutcomes, String proofStatus, Set<Long> support, Object path, Long offset, 423 List<List<Long>> supportWalks) { 424 this.supportWalks = frozenWalks(supportWalks); 425 this.label = label; 426 this.references = frozen(references); 427 this.source = source; 428 this.target = target; 429 this.outcomes = outcomes == null ? null : FoldKernel.frozenOutcomes(outcomes); 430 this.effectiveOutcomes = FoldKernel.frozenOutcomes(effectiveOutcomes); 431 this.proofStatus = proofStatus; 432 this.support = frozen(support); 433 this.path = path; 434 this.offset = offset; 435 } 436 437 public FoldLabel getLabel() { 438 return label; 439 } 440 441 /** The ambiguous references of the group, named by their candidate sets, sorted. */ 442 public List<Object> getReferences() { 443 return references; 444 } 445 446 public End getSource() { 447 return source; 448 } 449 450 public End getTarget() { 451 return target; 452 } 453 454 /** The outcomes to list in {@code outcomes}; null when they are the implied ones. */ 455 public Set<Set<Pair>> getOutcomes() { 456 return outcomes; 457 } 458 459 /** The outcomes that hold: the listed ones, or the implied ones when none are listed. */ 460 public Set<Set<Pair>> getEffectiveOutcomes() { 461 return effectiveOutcomes; 462 } 463 464 public String getProofStatus() { 465 return proofStatus; 466 } 467 468 public SortedSet<Long> getSupport() { 469 return support; 470 } 471 472 /** Fold walks that each yield this FactCandidate and together cover its support subgraph. */ 473 public List<List<Long>> getSupportWalks() { 474 return supportWalks; 475 } 476 477 /** The semantic path of the deciding reference, or null. */ 478 public Object getPath() { 479 return path; 480 } 481 482 /** The UTF-8 offset of the deciding reference, or null. */ 483 public Long getOffset() { 484 return offset; 485 } 486 487 /** The rank among the FactCandidates of the statement with the same subject and path (identity-v1 5.4). */ 488 public int getOrdinal() { 489 return ordinal; 490 } 491 492 public CandidateBinding getSourceBinding() { 493 return sourceBinding; 494 } 495 496 public CandidateBinding getTargetBinding() { 497 return targetBinding; 498 } 499 500 @Override 501 public String toString() { 502 return source + " -" + label + "-> " + target + " @" + path + "#" + ordinal + " " + proofStatus 503 + (outcomes == null ? "" : " outcomes " + outcomes); 504 } 505 } 506 507 /** 508 * A terminal input of a write (Section 7.5): its kind, disclosure, the literal or hash token, and a parameter's 509 * marker as written with, for an anonymous marker, its position (two parameters of one write are two inputs). 510 */ 511 public static final class TerminalInput { 512 private final Object kind; 513 private final Object disclosure; 514 private final Object value; 515 private final Object parameterText; 516 private final Object parameterOrdinal; 517 518 TerminalInput(Object kind, Object disclosure, Object value, Object parameterText, Object parameterOrdinal) { 519 this.kind = kind; 520 this.disclosure = disclosure; 521 this.value = value; 522 this.parameterText = parameterText; 523 this.parameterOrdinal = parameterOrdinal; 524 } 525 526 /** A PARAMETER's marker or name as written, else null. */ 527 public Object getParameterText() { 528 return parameterText; 529 } 530 531 /** An anonymous PARAMETER marker's position among the statement's anonymous markers, else null. */ 532 public Object getParameterOrdinal() { 533 return parameterOrdinal; 534 } 535 536 public Object getKind() { 537 return kind; 538 } 539 540 public Object getDisclosure() { 541 return disclosure; 542 } 543 544 /** The literal of a {@code PRESENT} literal, the canonical JSON of a {@code HASHED} token, else null. */ 545 public Object getValue() { 546 return value; 547 } 548 549 @Override 550 public boolean equals(Object other) { 551 if (!(other instanceof TerminalInput)) { 552 return false; 553 } 554 TerminalInput input = (TerminalInput) other; 555 return FoldKernel.same(kind, input.kind) && FoldKernel.same(disclosure, input.disclosure) 556 && FoldKernel.same(value, input.value) && FoldKernel.same(parameterText, input.parameterText) 557 && FoldKernel.same(parameterOrdinal, input.parameterOrdinal); 558 } 559 560 @Override 561 public int hashCode() { 562 return (((FoldKernel.hash(kind) * 31 + FoldKernel.hash(disclosure)) * 31 + FoldKernel.hash(value)) * 31 563 + FoldKernel.hash(parameterText)) * 31 + FoldKernel.hash(parameterOrdinal); 564 } 565 566 @Override 567 public String toString() { 568 return kind + " " + disclosure + " " + value + (parameterText == null ? "" : " " + parameterText) 569 + (parameterOrdinal == null ? "" : " #" + parameterOrdinal); 570 } 571 } 572 573 /** What a write of one field must carry (Sections 7.4 and 7.5). */ 574 public static final class WriteRequirement { 575 private final Object targetRef; 576 private final String bound; 577 private final List<FactOccurrence> facts; 578 private final List<Candidate> candidates; 579 private final Set<TerminalInput> terminals; 580 private final SortedSet<Long> diagnosticRefs; 581 582 WriteRequirement(Object targetRef, String bound, List<FactOccurrence> facts, List<Candidate> candidates, 583 Set<TerminalInput> terminals, Set<Long> diagnosticRefs) { 584 this.targetRef = targetRef; 585 this.bound = bound; 586 this.facts = frozen(facts); 587 this.candidates = frozen(candidates); 588 this.terminals = Collections.unmodifiableSet(new java.util.LinkedHashSet<TerminalInput>(terminals)); 589 this.diagnosticRefs = frozen(diagnosticRefs); 590 } 591 592 public Object getTargetRef() { 593 return targetRef; 594 } 595 596 /** The highest {@code upstreamCompleteness} the write may declare: COMPLETE, PARTIAL or UNKNOWN. */ 597 public String getBound() { 598 return bound; 599 } 600 601 /** One Occurrence of each Fact into the field; each Fact is a {@code FIELD_REF} input. */ 602 public List<FactOccurrence> getFacts() { 603 return facts; 604 } 605 606 /** The FactCandidates whose target end is the field or contains it; each is a {@code FIELD_REF} input. */ 607 public List<Candidate> getCandidates() { 608 return candidates; 609 } 610 611 /** The terminals that reach the field through {@code VALUE} micro-edges only. */ 612 public Set<TerminalInput> getTerminals() { 613 return terminals; 614 } 615 616 /** The diagnostics of the nodes and holes that lowered the bound; the write must link them. */ 617 public SortedSet<Long> getDiagnosticRefs() { 618 return diagnosticRefs; 619 } 620 621 @Override 622 public String toString() { 623 return targetRef + " " + bound + " facts " + facts.size() + " candidates " + candidates.size() 624 + " terminals " + terminals + " diagnostics " + diagnosticRefs; 625 } 626 } 627}