summaryrefslogtreecommitdiff
path: root/src/proof/drat/drat_proof.cpp
blob: 5a01ffdfdd45bd962558e4b52e0a177605a2aeca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*********************                                                        */
/*! \file drat_proof.cpp
 ** \verbatim
 ** Top contributors (to current version):
 **   Alex Ozdemir
 ** This file is part of the CVC4 project.
 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
 ** in the top-level source directory) and their institutional affiliations.
 ** All rights reserved.  See the file COPYING in the top-level source
 ** directory for licensing information.\endverbatim
 **
 ** \brief DRAT Proof Format
 **
 ** Defines deserialization for DRAT proofs.
 **/

#include "proof/drat/drat_proof.h"

#include <algorithm>
#include <bitset>
#include <iostream>

#include "proof/proof_manager.h"

namespace CVC4 {
namespace proof {
namespace drat {

// helper functions for parsing the binary DRAT format.

/**
 * Parses a binary literal which starts at `start` and must not go beyond `end`
 *
 * Leaves the iterator one past the last byte that is a part of the clause.
 *
 * If the literal overruns `end`, then raises a `InvalidDratProofException`.
 */
SatLiteral parse_binary_literal(std::string::const_iterator& start,
                                const std::string::const_iterator& proof_end)
{
  // lit is encoded as uint represented by a variable-length byte sequence
  uint64_t literal_represented_as_uint = 0;
  for (uint8_t shift = 0; start != proof_end; ++start, shift += 7)
  {
    // Check whether shift is so large that we're going to lose some
    // information
    if (shift + 7 >= 64)
    {
      throw InvalidDratProofException(
          "While parsing a DRAT proof, encountered a literal that was too "
          "long");
    }
    unsigned char byte = *start;
    // The MSB of the byte is an indicator of whether the sequence continues
    bool continued = (byte >> 7) & 1;
    uint64_t numeric_part = byte & 0x7f;
    literal_represented_as_uint |= numeric_part << shift;
    if (!continued)
    {
      // LSB of `literal_represented_as_uint` indicates negation.
      bool negated = literal_represented_as_uint & 1;
      // Rest is the literal number
      SatVariable var_number = literal_represented_as_uint >> 1;
      ++start;
      // Internal clauses start at 0, external ones start at 1.
      return SatLiteral(var_number - 1, negated);
    }
  }
  throw InvalidDratProofException(
      "Literal in DRAT proof was not done when "
      "EOF was encountered");
}

/**
 * Parses a binary clause which starts at `start` and must not go beyond `end`
 *
 * Leaves the iterator one past the last byte that is a part of the clause.
 * That is, one past the null byte.
 *
 * If the clause overruns `end`, then raises a `InvalidDratProofException`.
 */
SatClause parse_binary_clause(std::string::const_iterator& start,
                              const std::string::const_iterator& proof_end)
{
  SatClause clause;
  // A clause is a 0-terminated sequence of literals
  while (start != proof_end)
  {
    // Is the clause done?
    if (*start == 0)
    {
      ++start;
      return clause;
    }
    else
    {
      // If not, parse another literal
      clause.emplace_back(parse_binary_literal(start, proof_end));
    }
  }
  // We've overrun the end of the byte stream.
  throw InvalidDratProofException(
      "Clause in DRAT proof was not done when "
      "EOF was encountered");
}

/**
 * Writes this SAT literal in the textual DIMACS format. i.e. as a non-zero
 * integer.
 *
 * Since internally +0 and -0 are valid literals, we add one to each
 * literal's number (SAT variable) when outputtting it.
 *
 * @param os the stream to write to
 * @param l the literal to write
 */
void outputLiteralAsDimacs(std::ostream& os, SatLiteral l)
{
  if (l.isNegated())
  {
    os << '-';
  }
  // add 1 to  convert between internal literals and their DIMACS
  // representaations.
  os << l.getSatVariable() + 1;
}

// DratInstruction implementation

DratInstruction::DratInstruction(DratInstructionKind kind, SatClause clause)
    : d_kind(kind), d_clause(clause)
{
  // All intialized
}

void DratInstruction::outputAsText(std::ostream& os) const
{
  switch (d_kind)
  {
    case DratInstructionKind::ADDITION:
    {
      for (const SatLiteral& l : d_clause)
      {
        outputLiteralAsDimacs(os, l);
        os << ' ';
      }
      os << '0' << std::endl;
      break;
    }
    case DratInstructionKind::DELETION:
    {
      os << "d ";
      for (const SatLiteral& l : d_clause)
      {
        outputLiteralAsDimacs(os, l);
        os << ' ';
      }
      os << '0' << std::endl;
      break;
    }
    default: { Unreachable("Unknown DRAT instruction kind");
    }
  }
}

// DratProof implementation

DratProof::DratProof() : d_instructions() {}

// See the "binary format" section of
// https://www.cs.utexas.edu/~marijn/drat-trim/
DratProof DratProof::fromBinary(const std::string& s)
{
  DratProof proof;
  if (Debug.isOn("pf::drat"))
  {
    Debug("pf::drat") << "Parsing binary DRAT proof" << std::endl;
    Debug("pf::drat") << "proof length: " << s.length() << " bytes"
                      << std::endl;
    Debug("pf::drat") << "proof as bytes: ";
    for (char i : s)
    {
      if (i == 'a' || i == 'd')
      {
        Debug("pf::drat") << std::endl << "  " << std::bitset<8>(i);
      }
      else
      {
        Debug("pf::drat") << " " << std::bitset<8>(i);
      }
    }
    Debug("pf::drat") << std::endl << "parsing proof..." << std::endl;
  }

  // For each instruction
  for (auto i = s.cbegin(), end = s.cend(); i != end;)
  {
    switch (*i)
    {
      case 'a':
      {
        ++i;
        proof.d_instructions.emplace_back(ADDITION,
                                          parse_binary_clause(i, end));
        break;
      }
      case 'd':
      {
        ++i;
        proof.d_instructions.emplace_back(DELETION,
                                          parse_binary_clause(i, end));
        break;
      }
      default:
      {
        std::ostringstream s;
        s << "Invalid instruction in Drat proof. Instruction bits: "
          << std::bitset<8>(*i)
          << ". Expected 'a' (01100001) or 'd' "
             "(01100100).";
        throw InvalidDratProofException(s.str());
      }
    }
  }

  if (Debug.isOn("pf::drat"))
  {
    Debug("pf::drat") << "Printing out DRAT in textual format:" << std::endl;
    proof.outputAsText(Debug("pf::drat"));
  }

  return proof;
};

const std::vector<DratInstruction>& DratProof::getInstructions() const
{
  return d_instructions;
};

void DratProof::outputAsText(std::ostream& os) const
{
  for (const DratInstruction& instruction : d_instructions)
  {
    instruction.outputAsText(os);
    os << "\n";
  }
};

void DratProof::outputAsLfsc(std::ostream& os, uint8_t indentation) const
{
  for (const DratInstruction& i : d_instructions)
  {
    if (indentation > 0)
    {
      std::fill_n(std::ostream_iterator<char>(os), indentation, ' ');
    }
    os << "(";
    switch (i.d_kind)
    {
      case ADDITION:
      {
        os << "DRATProofa ";
        break;
      }
      case DELETION:
      {
        os << "DRATProofd ";
        break;
      }
      default: { Unreachable("Unrecognized DRAT instruction kind");
      }
    }
    for (const SatLiteral& l : i.d_clause)
    {
      os << "(clc (" << (l.isNegated() ? "neg " : "pos ")
         << ProofManager::getVarName(l.getSatVariable(), "bb") << ") ";
    }
    os << "cln";
    std::fill_n(std::ostream_iterator<char>(os), i.d_clause.size(), ')');
    os << "\n";
  }
  os << "DRATProofn";
  std::fill_n(std::ostream_iterator<char>(os), d_instructions.size(), ')');
}
}  // namespace drat
}  // namespace proof
}  // namespace CVC4
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback