diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/varisat-internal-proof | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/varisat-internal-proof')
-rw-r--r-- | vendor/varisat-internal-proof/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/Cargo.toml | 29 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/LICENSE-MIT | 25 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/README.md | 27 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/src/binary_format.rs | 332 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/src/lib.rs | 152 | ||||
-rw-r--r-- | vendor/varisat-internal-proof/src/vli_enc.rs | 136 |
8 files changed, 903 insertions, 0 deletions
diff --git a/vendor/varisat-internal-proof/.cargo-checksum.json b/vendor/varisat-internal-proof/.cargo-checksum.json new file mode 100644 index 000000000..4de3cd320 --- /dev/null +++ b/vendor/varisat-internal-proof/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"3fc37c3493bb992e9d0362475a0fa2cb8bad821edc0f5274b18cc97597a8ccff","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"2259cbb177661977dd5510c05a8670da3cb28aa7f4ff74c193798db496fe92d8","README.md":"bfc5897a6a04d192e8bc3c56f64ae735271511a394ccc08c8ea1fe58f0168dfa","src/binary_format.rs":"76ff2dced33a22925107c91730bd19df8a58621519b9a5348fd85061c299677b","src/lib.rs":"80ce44fdae8f2e8125a950f51a2e03d352eb79beb3df7c5359fde3870656c0a8","src/vli_enc.rs":"23b3d52aa89623a3f4ede0a2bda39d6cf2b8ced5e73c3355b67ec33ff4842750"},"package":"6163bb7bc9018af077b76d64f976803d141c36a27d640f1437dddc4fd527d207"}
\ No newline at end of file diff --git a/vendor/varisat-internal-proof/Cargo.toml b/vendor/varisat-internal-proof/Cargo.toml new file mode 100644 index 000000000..27b1b87ff --- /dev/null +++ b/vendor/varisat-internal-proof/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "varisat-internal-proof" +version = "0.2.2" +authors = ["Jannis Harder <me@jix.one>"] +description = "Internal proof format for the Varisat SAT solver" +homepage = "https://jix.one/project/varisat/" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/jix/varisat" +[dependencies.anyhow] +version = "1.0.32" + +[dependencies.varisat-formula] +version = "=0.2.2" +[dev-dependencies.proptest] +version = "0.10.1" diff --git a/vendor/varisat-internal-proof/LICENSE-APACHE b/vendor/varisat-internal-proof/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/varisat-internal-proof/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/varisat-internal-proof/LICENSE-MIT b/vendor/varisat-internal-proof/LICENSE-MIT new file mode 100644 index 000000000..4fd1cb2ff --- /dev/null +++ b/vendor/varisat-internal-proof/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017-2019 Jannis Harder + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/varisat-internal-proof/README.md b/vendor/varisat-internal-proof/README.md new file mode 100644 index 000000000..29552e8c6 --- /dev/null +++ b/vendor/varisat-internal-proof/README.md @@ -0,0 +1,27 @@ +# Varisat + +This crate defines the proof format used internally by the [`varisat` +crate][crate-varisat]. + +__This is an internal dependency of the Varisat SAT solver, and should not be +used directly.__ + +## License + +The Varisat source code is licensed under either of + + * Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license + ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Varisat by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[crate-varisat]: https://crates.io/crates/varisat diff --git a/vendor/varisat-internal-proof/src/binary_format.rs b/vendor/varisat-internal-proof/src/binary_format.rs new file mode 100644 index 000000000..e296468d1 --- /dev/null +++ b/vendor/varisat-internal-proof/src/binary_format.rs @@ -0,0 +1,332 @@ +//! Binary format for varisat proofs. +use std::io::{self, BufRead, Write}; + +use anyhow::Error; + +use varisat_formula::{Lit, Var}; + +use crate::vli_enc::{read_u64, write_u64}; + +use super::{ClauseHash, DeleteClauseProof, ProofStep}; + +macro_rules! step_codes { + ($counter:expr, $name:ident, ) => { + const $name: u64 = $counter; + }; + ($counter:expr, $name:ident, $($names:ident),* ,) => { + const $name: u64 = $counter; + step_codes!($counter + 1, $($names),* ,); + }; +} + +step_codes!( + 0, + CODE_SOLVER_VAR_NAME_UPDATE, + CODE_SOLVER_VAR_NAME_REMOVE, + CODE_USER_VAR_NAME_UPDATE, + CODE_USER_VAR_NAME_REMOVE, + CODE_DELETE_VAR, + CODE_CHANGE_SAMPLING_MODE_SAMPLE, + CODE_CHANGE_SAMPLING_MODE_WITNESS, + CODE_AT_CLAUSE_RED, + CODE_AT_CLAUSE_IRRED, + CODE_UNIT_CLAUSES, + CODE_DELETE_CLAUSE_REDUNDANT, + CODE_DELETE_CLAUSE_SIMPLIFIED, + CODE_DELETE_CLAUSE_SATISFIED, + CODE_CHANGE_HASH_BITS, + CODE_MODEL, + CODE_ADD_CLAUSE, + CODE_ASSUMPTIONS, + CODE_FAILED_ASSUMPTIONS, +); + +// Using a random value here makes it unlikely that a corrupted proof will be silently truncated and +// accepted +const CODE_END: u64 = 0x9ac3391f4294c211; + +/// Writes a proof step in the varisat format +pub fn write_step<'s>(target: &mut impl Write, step: &'s ProofStep<'s>) -> io::Result<()> { + match *step { + ProofStep::SolverVarName { global, solver } => { + if let Some(solver) = solver { + write_u64(&mut *target, CODE_SOLVER_VAR_NAME_UPDATE)?; + write_u64(&mut *target, global.index() as u64)?; + write_u64(&mut *target, solver.index() as u64)?; + } else { + write_u64(&mut *target, CODE_SOLVER_VAR_NAME_REMOVE)?; + write_u64(&mut *target, global.index() as u64)?; + } + } + + ProofStep::UserVarName { global, user } => { + if let Some(user) = user { + write_u64(&mut *target, CODE_USER_VAR_NAME_UPDATE)?; + write_u64(&mut *target, global.index() as u64)?; + write_u64(&mut *target, user.index() as u64)?; + } else { + write_u64(&mut *target, CODE_USER_VAR_NAME_REMOVE)?; + write_u64(&mut *target, global.index() as u64)?; + } + } + + ProofStep::DeleteVar { var } => { + write_u64(&mut *target, CODE_DELETE_VAR)?; + write_u64(&mut *target, var.index() as u64)?; + } + + ProofStep::ChangeSamplingMode { var, sample } => { + if sample { + write_u64(&mut *target, CODE_CHANGE_SAMPLING_MODE_SAMPLE)?; + } else { + write_u64(&mut *target, CODE_CHANGE_SAMPLING_MODE_WITNESS)?; + } + write_u64(&mut *target, var.index() as u64)?; + } + + ProofStep::AddClause { clause } => { + write_u64(&mut *target, CODE_ADD_CLAUSE)?; + write_literals(&mut *target, clause)?; + } + + ProofStep::AtClause { + redundant, + clause, + propagation_hashes, + } => { + if redundant { + write_u64(&mut *target, CODE_AT_CLAUSE_RED)?; + } else { + write_u64(&mut *target, CODE_AT_CLAUSE_IRRED)?; + } + write_literals(&mut *target, clause)?; + write_hashes(&mut *target, propagation_hashes)?; + } + + ProofStep::UnitClauses { units } => { + write_u64(&mut *target, CODE_UNIT_CLAUSES)?; + write_unit_clauses(&mut *target, units)?; + } + + ProofStep::DeleteClause { clause, proof } => { + match proof { + DeleteClauseProof::Redundant => { + write_u64(&mut *target, CODE_DELETE_CLAUSE_REDUNDANT)?; + } + DeleteClauseProof::Simplified => { + write_u64(&mut *target, CODE_DELETE_CLAUSE_SIMPLIFIED)?; + } + DeleteClauseProof::Satisfied => { + write_u64(&mut *target, CODE_DELETE_CLAUSE_SATISFIED)?; + } + } + + write_literals(&mut *target, clause)?; + } + + ProofStep::ChangeHashBits { bits } => { + write_u64(&mut *target, CODE_CHANGE_HASH_BITS)?; + write_u64(&mut *target, bits as u64)?; + } + + ProofStep::Model { assignment } => { + write_u64(&mut *target, CODE_MODEL)?; + write_literals(&mut *target, assignment)?; + } + + ProofStep::Assumptions { assumptions } => { + write_u64(&mut *target, CODE_ASSUMPTIONS)?; + write_literals(&mut *target, assumptions)?; + } + + ProofStep::FailedAssumptions { + failed_core, + propagation_hashes, + } => { + write_u64(&mut *target, CODE_FAILED_ASSUMPTIONS)?; + write_literals(&mut *target, failed_core)?; + write_hashes(&mut *target, propagation_hashes)?; + } + + ProofStep::End => { + write_u64(&mut *target, CODE_END)?; + } + } + + Ok(()) +} + +#[derive(Default)] +pub struct Parser { + lit_buf: Vec<Lit>, + hash_buf: Vec<ClauseHash>, + unit_buf: Vec<(Lit, ClauseHash)>, +} + +impl Parser { + pub fn parse_step<'a>(&'a mut self, source: &mut impl BufRead) -> Result<ProofStep<'a>, Error> { + let code = read_u64(&mut *source)?; + match code { + CODE_SOLVER_VAR_NAME_UPDATE => { + let global = Var::from_index(read_u64(&mut *source)? as usize); + let solver = Some(Var::from_index(read_u64(&mut *source)? as usize)); + Ok(ProofStep::SolverVarName { global, solver }) + } + CODE_SOLVER_VAR_NAME_REMOVE => { + let global = Var::from_index(read_u64(&mut *source)? as usize); + Ok(ProofStep::SolverVarName { + global, + solver: None, + }) + } + CODE_USER_VAR_NAME_UPDATE => { + let global = Var::from_index(read_u64(&mut *source)? as usize); + let user = Some(Var::from_index(read_u64(&mut *source)? as usize)); + Ok(ProofStep::UserVarName { global, user }) + } + CODE_USER_VAR_NAME_REMOVE => { + let global = Var::from_index(read_u64(&mut *source)? as usize); + Ok(ProofStep::UserVarName { global, user: None }) + } + CODE_DELETE_VAR => { + let var = Var::from_index(read_u64(&mut *source)? as usize); + Ok(ProofStep::DeleteVar { var }) + } + CODE_CHANGE_SAMPLING_MODE_SAMPLE | CODE_CHANGE_SAMPLING_MODE_WITNESS => { + let var = Var::from_index(read_u64(&mut *source)? as usize); + Ok(ProofStep::ChangeSamplingMode { + var, + sample: code == CODE_CHANGE_SAMPLING_MODE_SAMPLE, + }) + } + CODE_ADD_CLAUSE => { + read_literals(&mut *source, &mut self.lit_buf)?; + Ok(ProofStep::AddClause { + clause: &self.lit_buf, + }) + } + CODE_AT_CLAUSE_IRRED | CODE_AT_CLAUSE_RED => { + read_literals(&mut *source, &mut self.lit_buf)?; + read_hashes(&mut *source, &mut self.hash_buf)?; + Ok(ProofStep::AtClause { + redundant: code == CODE_AT_CLAUSE_RED, + clause: &self.lit_buf, + propagation_hashes: &self.hash_buf, + }) + } + CODE_UNIT_CLAUSES => { + read_unit_clauses(&mut *source, &mut self.unit_buf)?; + Ok(ProofStep::UnitClauses { + units: &self.unit_buf, + }) + } + CODE_DELETE_CLAUSE_REDUNDANT + | CODE_DELETE_CLAUSE_SIMPLIFIED + | CODE_DELETE_CLAUSE_SATISFIED => { + let proof = match code { + CODE_DELETE_CLAUSE_REDUNDANT => DeleteClauseProof::Redundant, + CODE_DELETE_CLAUSE_SIMPLIFIED => DeleteClauseProof::Simplified, + CODE_DELETE_CLAUSE_SATISFIED => DeleteClauseProof::Satisfied, + _ => unreachable!(), + }; + read_literals(&mut *source, &mut self.lit_buf)?; + Ok(ProofStep::DeleteClause { + clause: &self.lit_buf, + proof, + }) + } + CODE_CHANGE_HASH_BITS => { + let bits = read_u64(&mut *source)? as u32; + Ok(ProofStep::ChangeHashBits { bits }) + } + CODE_MODEL => { + read_literals(&mut *source, &mut self.lit_buf)?; + Ok(ProofStep::Model { + assignment: &self.lit_buf, + }) + } + CODE_ASSUMPTIONS => { + read_literals(&mut *source, &mut self.lit_buf)?; + Ok(ProofStep::Assumptions { + assumptions: &self.lit_buf, + }) + } + CODE_FAILED_ASSUMPTIONS => { + read_literals(&mut *source, &mut self.lit_buf)?; + read_hashes(&mut *source, &mut self.hash_buf)?; + Ok(ProofStep::FailedAssumptions { + failed_core: &self.lit_buf, + propagation_hashes: &self.hash_buf, + }) + } + CODE_END => Ok(ProofStep::End), + _ => anyhow::bail!("parse error"), + } + } +} + +/// Writes a slice of literals for a varisat proof +fn write_literals(target: &mut impl Write, literals: &[Lit]) -> io::Result<()> { + write_u64(&mut *target, literals.len() as u64)?; + for &lit in literals { + write_u64(&mut *target, lit.code() as u64)?; + } + Ok(()) +} + +/// Read a slice of literals from a varisat proof +fn read_literals(source: &mut impl BufRead, literals: &mut Vec<Lit>) -> Result<(), io::Error> { + literals.clear(); + let len = read_u64(&mut *source)? as usize; + literals.reserve(len); + for _ in 0..len { + literals.push(Lit::from_code(read_u64(&mut *source)? as usize)); + } + Ok(()) +} + +/// Writes a slice of clause hashes for a varisat proof +fn write_hashes(target: &mut impl Write, hashes: &[ClauseHash]) -> io::Result<()> { + write_u64(&mut *target, hashes.len() as u64)?; + for &hash in hashes { + write_u64(&mut *target, hash as u64)?; + } + Ok(()) +} + +/// Read a slice of clause hashes from a varisat proof +fn read_hashes(source: &mut impl BufRead, hashes: &mut Vec<ClauseHash>) -> Result<(), io::Error> { + hashes.clear(); + let len = read_u64(&mut *source)? as usize; + hashes.reserve(len); + for _ in 0..len { + hashes.push(read_u64(&mut *source)? as ClauseHash); + } + Ok(()) +} + +/// Writes a slice of unit clauses for a varisat proof +fn write_unit_clauses(target: &mut impl Write, units: &[(Lit, ClauseHash)]) -> io::Result<()> { + write_u64(&mut *target, units.len() as u64)?; + for &(lit, hash) in units { + write_u64(&mut *target, lit.code() as u64)?; + write_u64(&mut *target, hash as u64)?; + } + Ok(()) +} + +/// Read a slice of unit clauses from a varisat proof +fn read_unit_clauses( + source: &mut impl BufRead, + units: &mut Vec<(Lit, ClauseHash)>, +) -> Result<(), io::Error> { + units.clear(); + let len = read_u64(&mut *source)? as usize; + units.reserve(len); + for _ in 0..len { + let lit = Lit::from_code(read_u64(&mut *source)? as usize); + let hash = read_u64(&mut *source)? as ClauseHash; + units.push((lit, hash)); + } + Ok(()) +} diff --git a/vendor/varisat-internal-proof/src/lib.rs b/vendor/varisat-internal-proof/src/lib.rs new file mode 100644 index 000000000..83d38dc5d --- /dev/null +++ b/vendor/varisat-internal-proof/src/lib.rs @@ -0,0 +1,152 @@ +//! Internal proof format for the Varisat SAT solver. +use varisat_formula::{Lit, Var}; + +pub mod binary_format; + +mod vli_enc; + +// Integer type used to store a hash of a clause. +pub type ClauseHash = u64; + +/// Hash a single literal. +/// +/// Multiple literals can be combined with xor, as done in [`clause_hash`]. +pub fn lit_hash(lit: Lit) -> ClauseHash { + lit_code_hash(lit.code()) +} + +/// Hash a single literal from a code. +/// +/// This doesn't require the code to correspond a valid literal. +pub fn lit_code_hash(lit_code: usize) -> ClauseHash { + // Constant based on the golden ratio provides good mixing for the resulting upper bits + (!(lit_code as u64)).wrapping_mul(0x61c8864680b583ebu64) +} + +/// A fast hash function for clauses (or other *sets* of literals). +/// +/// This hash function interprets the given slice as a set and will not change when the input is +/// permuted. It does not handle duplicated items. +pub fn clause_hash(lits: &[Lit]) -> ClauseHash { + let mut hash = 0; + for &lit in lits { + hash ^= lit_hash(lit); + } + hash +} + +/// Justifications for a simple clause deletion. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum DeleteClauseProof { + /// The clause is known to be redundant. + Redundant, + /// The clause is irred and subsumed by the clause added in the previous step. + Simplified, + /// The clause contains a true literal. + /// + /// Also used to justify deletion of tautological clauses. + Satisfied, +} + +/// A single proof step. +/// +/// Represents a mutation of the current formula and a justification for the mutation's validity. +#[derive(Copy, Clone, Debug)] +pub enum ProofStep<'a> { + /// Update the global to solver var mapping. + /// + /// For proof checking, the solver variable names are only used for hash computations. + SolverVarName { global: Var, solver: Option<Var> }, + /// Update the global to user var mapping. + /// + /// A variable without user mapping is considered hidden by the checker. When a variable without + /// user mapping gets a user mapping, the sampling mode is initialized to witness. + /// + /// It's not allowed to change a variable from one user name to another when the variable is in + /// use. + /// + /// Clause additions and assumptions are only allowed to use variables with user mappings (and a + /// non-witness sampling mode). + UserVarName { global: Var, user: Option<Var> }, + /// Delete a variable. + /// + /// This is only allowed for variables that are isolated and hidden. + DeleteVar { var: Var }, + /// Changes the sampling mode of a variable. + /// + /// This is only used to change between Sample and Witness. Hidden is managed by adding or + /// removing a user var name. + ChangeSamplingMode { var: Var, sample: bool }, + /// Add a new input clause. + /// + /// This is only emitted for clauses added incrementally after an initial solve call. + AddClause { clause: &'a [Lit] }, + /// Add a clause that is an asymmetric tautoligy (AT). + /// + /// Assuming the negation of the clause's literals leads to a unit propagation conflict. + /// + /// The second slice contains the hashes of all clauses involved in the resulting conflict. The + /// order of hashes is the order in which the clauses propagate when all literals of the clause + /// are set false. + /// + /// When generating DRAT proofs the second slice is ignored and may be empty. + AtClause { + redundant: bool, + clause: &'a [Lit], + propagation_hashes: &'a [ClauseHash], + }, + /// Unit clauses found by top-level unit-propagation. + /// + /// Pairs of unit clauses and the original clause that became unit. Clauses are in chronological + /// order. This is equivalent to multiple `AtClause` steps where the clause is unit and the + /// propagation_hashes field contains just one hash, with the difference that this is not output + /// for DRAT proofs. + /// + /// Ignored when generating DRAT proofs. + UnitClauses { units: &'a [(Lit, ClauseHash)] }, + /// Delete a clause consisting of the given literals. + DeleteClause { + clause: &'a [Lit], + proof: DeleteClauseProof, + }, + /// Change the number of clause hash bits used + ChangeHashBits { bits: u32 }, + /// A (partial) assignment that satisfies all clauses and assumptions. + Model { assignment: &'a [Lit] }, + /// Change the active set of assumptions. + /// + /// This is checked against future model or failed assumptions steps. + Assumptions { assumptions: &'a [Lit] }, + /// A subset of the assumptions that make the formula unsat. + FailedAssumptions { + failed_core: &'a [Lit], + propagation_hashes: &'a [ClauseHash], + }, + /// Signals the end of a proof. + /// + /// A varisat proof must end with this command or else the checker will complain about an + /// incomplete proof. + End, +} + +impl<'a> ProofStep<'a> { + /// Does this proof step use clause hashes? + pub fn contains_hashes(&self) -> bool { + match self { + ProofStep::AtClause { .. } + | ProofStep::UnitClauses { .. } + | ProofStep::FailedAssumptions { .. } => true, + + ProofStep::SolverVarName { .. } + | ProofStep::UserVarName { .. } + | ProofStep::DeleteVar { .. } + | ProofStep::ChangeSamplingMode { .. } + | ProofStep::AddClause { .. } + | ProofStep::DeleteClause { .. } + | ProofStep::ChangeHashBits { .. } + | ProofStep::Model { .. } + | ProofStep::Assumptions { .. } + | ProofStep::End => false, + } + } +} diff --git a/vendor/varisat-internal-proof/src/vli_enc.rs b/vendor/varisat-internal-proof/src/vli_enc.rs new file mode 100644 index 000000000..058058e6e --- /dev/null +++ b/vendor/varisat-internal-proof/src/vli_enc.rs @@ -0,0 +1,136 @@ +//! Variable length integer encoding. +//! +//! This uses a different encoding from the leb128 encoding used for binary DRAT and CLRAT. It uses +//! the same amount of bytes for each input, but is faster to encode and decode. +//! +//! Numbers are encoded like this: +//! ```text +//! 1xxxxxxx for up to 7 bits +//! 01xxxxxx xxxxxxxx for up to 14 bits +//! 001xxxxx xxxxxxxx xxxxxxxx for up to 21 bits +//! ... +//! ``` +//! +//! The x-bits store the number from LSB to MSB. This scheme allows faster encoding and decoding, as +//! the bits are kept consecutive and the length can be determined from the first or first two +//! bytes. +//! +//! The current implementations are not optimal but fast enough to not be the bottleneck when +//! checking proofs. +use std::{ + convert::{TryFrom, TryInto}, + io::{self, BufRead, Write}, +}; + +/// Write an encoded 64 bit number. +pub fn write_u64(target: &mut impl Write, mut value: u64) -> Result<(), io::Error> { + let bits = (64 - value.leading_zeros()) as u32; + let blocks = (bits * (64 / 7)) / 64; + if value < (1 << (8 * 7)) { + value = ((value << 1) | 1) << blocks; + let bytes = unsafe { std::mem::transmute::<u64, [u8; 8]>(value.to_le()) }; + target.write_all(&bytes[..(blocks + 1) as usize]) + } else { + let lo_data = ((value << 1) | 1) << blocks; + let lo_bytes = unsafe { std::mem::transmute::<u64, [u8; 8]>(lo_data.to_le()) }; + let hi_data = value >> (64 - (blocks + 1)); + let hi_bytes = unsafe { std::mem::transmute::<u64, [u8; 8]>(hi_data.to_le()) }; + + target.write_all(&lo_bytes)?; + target.write_all(&hi_bytes[..(blocks as usize) + 1 - 8]) + } +} + +/// Read an encoded 64 bit number, if at least 16 bytes lookahead are available. +fn read_u64_fast(bytes: &[u8; 16]) -> (u64, usize) { + let lo_data = u64::from_le(unsafe { + std::mem::transmute::<[u8; 8], u64>(*<&[u8; 8]>::try_from(&bytes[..8]).unwrap()) + }); + + let len = (lo_data | (1 << 9)).trailing_zeros() + 1; + + if len <= 8 { + let result = lo_data & (!0u64 >> (64 - 8 * len)); + + let result = result >> len; + + (result, len as usize) + } else { + let hi_data = u64::from_le(unsafe { + std::mem::transmute::<[u8; 8], u64>(*<&[u8; 8]>::try_from(&bytes[8..]).unwrap()) + }); + + let hi_data = hi_data & (!0u64 >> (64 - 8 * (len - 8))); + + let result = (lo_data >> len) | (hi_data << (64 - len)); + + (result as u64, len as usize) + } +} + +/// Read an encoded 64 bit number from a buffered reader. +/// +/// This uses [`read_u64_fast`] if the remaining buffer is larger than 16 bytes and falls back to a +/// slower implementation otherwise. +pub fn read_u64(source: &mut impl BufRead) -> Result<u64, io::Error> { + let buf = source.fill_buf()?; + if buf.len() >= 16 { + let next_bytes: &[u8; 16] = (&buf[..16]).try_into().unwrap(); + let (value, advance) = read_u64_fast(next_bytes); + source.consume(advance); + Ok(value) + } else { + let mut scan = 1 << 9; + let mut byte: [u8; 1] = [0]; + let mut begin = 1; + source.read_exact(&mut byte[..])?; + let mut result = byte[0] as u64; + scan |= byte[0] as u64; + if byte[0] == 0 { + begin += 1; + source.read_exact(&mut byte[..])?; + result |= (byte[0] as u64) << 8; + scan |= (byte[0] as u64) << 8; + } + let len = scan.trailing_zeros() + 1; + + result >>= len; + + for i in begin..len { + source.read_exact(&mut byte[..])?; + result |= (byte[0] as u64) << (8 * i - len); + } + + Ok(result as u64) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use proptest::prelude::*; + + proptest! { + #[test] + fn roundtrip ( + numbers in prop::collection::vec(prop::num::u64::ANY, 0..10_000) + ) { + let mut buf = vec![]; + + for &num in numbers.iter() { + write_u64(&mut buf, num)?; + } + + let mut read = std::io::BufReader::with_capacity(128, &buf[..]); + + let mut out = vec![]; + + while let Ok(num) = read_u64(&mut read) { + out.push(num) + } + + prop_assert_eq!(numbers, out); + } + } +} |