tiny.smt.ProofArtifact
Defined in tiny.smt.
The clauses, assumptions and steps behind one unsatisfiable answer, copied out of the solver and owned by the caller.
API (11)
Actions
Public operations.
appendAssumptions: Appendsliteralsto the assumption list.appendClause: Copiesliteralsand adds the copy as the last starting clause.appendStep: Copiesliteralsand adds the copy as the last proof step.deinit: Frees every clause and step copy and the three lists with the artifact's allocator.init: Returns an empty artifact overvariable_countvariables that allocates withallocator.valid: Returns true when every step follows by unit propagation from the starting clauses, the assumptions and the steps before it, and the last step is the empty clause.
Fields and members
Public fields and members.
Source
Source: lib/smt/src/sat/proof.zig:31
zig
/// The clauses, assumptions and steps behind one unsatisfiable answer, copied out of the solver and/// owned by the caller. A caller keeps it as the evidence of an unsatisfiable answer after the/// solver moves on, checks it with `valid`, and writes it out as text. A proof reader and tests/// also build artifacts by hand with `init` and the append functions. The artifact allocates every/// copy with the allocator given to `init` and frees them in `deinit`. The artifact shares no/// memory with the solver, so it stays usable after the solver changes or is freed.pub const ProofArtifact = struct { allocator: std.mem.Allocator, /// The number of variables the artifact covers. Every literal has to name a variable below it, /// or `valid` returns false. `Solver.lastProofArtifact` sets it to the solver's variable count. variable_count: usize, /// The starting clauses, in order. From `Solver.lastProofArtifact` they are every clause the /// solver held when the solve began, learned clauses it kept included, then an empty clause /// when the caller had added one. `appendClause` adds one at the end. clauses: std.ArrayList(ProofClause) = .empty, /// The literals assumed true for the refutation. From `Solver.lastProofArtifact` they are the /// solve's assumptions, cut down to the smaller set that core minimization certified when it /// finished. They can be more than `Solver.lastUnsatCore` reports, because the artifact keeps /// every assumption of the solve unless core minimization certified a smaller set. When the /// clauses were refuted before the search began, as by two opposite unit clauses, the core is /// empty and the artifact keeps every assumption. When a conflict comes while the solver /// assigns the first of two or more assumptions, the core holds that one assumption, core /// minimization leaves it as it is, and the artifact keeps every assumption. When a conflict /// limit runs out during the certifying solve of core minimization, the core is empty and the /// artifact keeps every assumption. assumptions: std.ArrayList(Literal) = .empty, /// The proof steps in order, each checked against the starting clauses, the assumptions and the /// steps before it. `appendStep` adds one at the end. steps: std.ArrayList(ProofStep) = .empty, /// Returns an empty artifact over `variable_count` variables that allocates with `allocator`. /// Code that builds an artifact by hand, such as a proof reader, starts from it. The call /// allocates nothing. pub fn init(allocator: std.mem.Allocator, variable_count: usize) ProofArtifact { return .{ .allocator = allocator, .variable_count = variable_count }; } /// Frees every clause and step copy and the three lists with the artifact's allocator. The /// owner of an artifact calls it once, when it is done with the evidence. The artifact is /// undefined afterward. pub fn deinit(self: *ProofArtifact) void { for (self.clauses.items) |clause| { self.allocator.free(clause.literals); } self.clauses.deinit(self.allocator); self.assumptions.deinit(self.allocator); for (self.steps.items) |step| { self.allocator.free(step.literals); } self.steps.deinit(self.allocator); self.* = undefined; } /// Copies `literals` and adds the copy as the last starting clause. A proof reader calls it /// once per starting clause, in file order. The caller keeps `literals`. The call returns /// `error.OutOfMemory` when the copy or the list growth fails, and then the artifact is as it /// was. pub fn appendClause(self: *ProofArtifact, literals: []const Literal) !void { const owned = try self.allocator.dupe(Literal, literals); errdefer self.allocator.free(owned); try self.clauses.append(self.allocator, .{ .literals = owned }); } /// Appends `literals` to the assumption list. A proof reader calls it for the assumption /// record, and `Solver.lastProofArtifact` calls it once with the solve's assumptions. Calls /// accumulate: each one appends after what earlier calls added. The call returns /// `error.OutOfMemory` when the list growth fails. pub fn appendAssumptions(self: *ProofArtifact, literals: []const Literal) !void { try self.assumptions.appendSlice(self.allocator, literals); } /// Copies `literals` and adds the copy as the last proof step. A proof reader calls it once per /// step, in file order, and `Solver.lastProofArtifact` calls it once per step of the trace. The /// caller keeps `literals`. The call returns `error.OutOfMemory` when the copy or the list /// growth fails, and then the artifact is as it was. pub fn appendStep(self: *ProofArtifact, literals: []const Literal) !void { const owned = try self.allocator.dupe(Literal, literals); errdefer self.allocator.free(owned); try self.steps.append(self.allocator, .{ .literals = owned }); } /// Returns true when every step follows by unit propagation from the starting clauses, the /// assumptions and the steps before it, and the last step is the empty clause. A caller runs it /// to confirm an unsatisfiable answer independently of the solver that gave it. To check one /// step, the call assumes the assumptions true and the step's literals false, then propagates /// unit clauses over the starting clauses and the earlier steps until a clause becomes false /// (Reverse Unit Propagation). The step passes when a clause becomes false, and also when the /// assumptions clash with the negated step. The call returns false when the step list is empty, /// or when any literal names a variable at or above `variable_count`. A step may use only the /// steps before it, so a step that only a later step supports fails. Each step repeats the /// propagation over every starting clause and earlier step until a pass leaves every value as /// it was. The call allocates one truth value per variable with the artifact's allocator for /// its own duration, and `error.OutOfMemory` is its only error. pub fn valid(self: *const ProofArtifact) !bool { if (self.steps.items.len == 0) return false; if (!proofClausesUseKnownVariables( ProofClause, self.variable_count, self.clauses.items, )) return false; if (!proofLiteralsUseKnownVariables( self.variable_count, self.assumptions.items, )) return false; for (self.steps.items) |step| { if (!proofLiteralsUseKnownVariables(self.variable_count, step.literals)) return false; } const assignment = try self.allocator.alloc(BoolValue, self.variable_count); defer self.allocator.free(assignment); for (self.steps.items, 0..) |step, index| { if (!rupCheckKnownVariablesWithClauses( assignment, ProofClause, self.clauses.items, self.assumptions.items, self.steps.items, step.literals, index, )) return false; } return self.steps.items[self.steps.items.len - 1].literals.len == 0; }};Source: lib/smt/src/root.zig:112
zig
pub const ProofArtifact = sat.ProofArtifact;Also reachable as
sat.ProofArtifact, sat.solver.ProofArtifact.
Complete caller list for ProofArtifact.appendStep
7 direct callers.
lib.smt.src.properties.model.test_semantic_proof_oracle_rejects_a_circular_self-visible_trace[function] — test source atlib/smt/src/properties/model.zig:369in nearest public ownerlib.smt.src.properties.modellib.smt.src.properties.sat.ArtifactSoundnessProperty.property[function] — private source atlib/smt/src/properties/sat.zig:208in nearest public ownerlib.smt.src.properties.satlib.smt.src.sat.proof.test_proof_artifact_assumptions_are_part_of_its_exact_scope[function] — test source atlib/smt/src/sat/proof.zig:425in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_a_first_step_visible_only_to_itself[function] — test source atlib/smt/src/sat/proof.zig:408in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_literals_outside_its_variable_scope[function] — test source atlib/smt/src/sat/proof.zig:417in nearest public ownerlib.smt.src.sat.prooftiny.smt.Solver.lastProofArtifact[method] atlib/smt/src/sat/solver.zig:449lib.smt.src.sat.test.test_sat_proof_artifact_rejects_unproven_empty_step[function] — test source atlib/smt/src/sat/test.zig:234in nearest public ownerlib.smt.src.sat.test
Complete caller list for ProofArtifact.deinit
7 direct callers.
lib.smt.src.properties.model.test_semantic_proof_oracle_rejects_a_circular_self-visible_trace[function] — test source atlib/smt/src/properties/model.zig:369in nearest public ownerlib.smt.src.properties.modellib.smt.src.properties.sat.ArtifactSoundnessProperty.property[function] — private source atlib/smt/src/properties/sat.zig:208in nearest public ownerlib.smt.src.properties.satlib.smt.src.sat.proof.test_proof_artifact_assumptions_are_part_of_its_exact_scope[function] — test source atlib/smt/src/sat/proof.zig:425in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_a_first_step_visible_only_to_itself[function] — test source atlib/smt/src/sat/proof.zig:408in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_literals_outside_its_variable_scope[function] — test source atlib/smt/src/sat/proof.zig:417in nearest public ownerlib.smt.src.sat.prooftiny.smt.Solver.lastProofArtifact[method] atlib/smt/src/sat/solver.zig:449lib.smt.src.sat.test.test_sat_proof_artifact_rejects_unproven_empty_step[function] — test source atlib/smt/src/sat/test.zig:234in nearest public ownerlib.smt.src.sat.test
Complete caller list for ProofArtifact.init
7 direct callers.
lib.smt.src.properties.model.test_semantic_proof_oracle_rejects_a_circular_self-visible_trace[function] — test source atlib/smt/src/properties/model.zig:369in nearest public ownerlib.smt.src.properties.modellib.smt.src.properties.sat.ArtifactSoundnessProperty.property[function] — private source atlib/smt/src/properties/sat.zig:208in nearest public ownerlib.smt.src.properties.satlib.smt.src.sat.proof.test_proof_artifact_assumptions_are_part_of_its_exact_scope[function] — test source atlib/smt/src/sat/proof.zig:425in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_a_first_step_visible_only_to_itself[function] — test source atlib/smt/src/sat/proof.zig:408in nearest public ownerlib.smt.src.sat.prooflib.smt.src.sat.proof.test_proof_artifact_rejects_literals_outside_its_variable_scope[function] — test source atlib/smt/src/sat/proof.zig:417in nearest public ownerlib.smt.src.sat.prooftiny.smt.Solver.lastProofArtifact[method] atlib/smt/src/sat/solver.zig:449lib.smt.src.sat.test.test_sat_proof_artifact_rejects_unproven_empty_step[function] — test source atlib/smt/src/sat/test.zig:234in nearest public ownerlib.smt.src.sat.test
Audit
| Definitions | 7 |
|---|---|
| Public names | 21 |
| Members | 5 |
| Version | 26.7.0 |
| Revision | daab053ee433 |