1 /*
2  *  ezSAT -- A simple and easy to use CNF generator for SAT solvers
3  *
4  *  Copyright (C) 2013  Claire Xenia Wolf <claire@yosyshq.com>
5  *
6  *  Permission to use, copy, modify, and/or distribute this software for any
7  *  purpose with or without fee is hereby granted, provided that the above
8  *  copyright notice and this permission notice appear in all copies.
9  *
10  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  */
19 
20 #include "ezsat.h"
21 
22 #include <cmath>
23 #include <algorithm>
24 #include <cassert>
25 #include <string>
26 
27 #include <stdlib.h>
28 
29 const int ezSAT::CONST_TRUE = 1;
30 const int ezSAT::CONST_FALSE = 2;
31 
my_int_to_string(int i)32 static std::string my_int_to_string(int i)
33 {
34 #ifdef __MINGW32__
35 	char buffer[64];
36 	snprintf(buffer, 64, "%d", i);
37 	return buffer;
38 #else
39 	return std::to_string(i);
40 #endif
41 }
42 
ezSAT()43 ezSAT::ezSAT()
44 {
45 	statehash = 5381;
46 
47 	flag_keep_cnf = false;
48 	flag_non_incremental = false;
49 
50 	non_incremental_solve_used_up = false;
51 
52 	cnfConsumed = false;
53 	cnfVariableCount = 0;
54 	cnfClausesCount = 0;
55 
56 	solverTimeout = 0;
57 	solverTimoutStatus = false;
58 
59 	literal("CONST_TRUE");
60 	literal("CONST_FALSE");
61 
62 	assert(literal("CONST_TRUE") == CONST_TRUE);
63 	assert(literal("CONST_FALSE") == CONST_FALSE);
64 }
65 
~ezSAT()66 ezSAT::~ezSAT()
67 {
68 }
69 
addhash(unsigned int h)70 void ezSAT::addhash(unsigned int h)
71 {
72 	statehash = ((statehash << 5) + statehash) ^ h;
73 }
74 
value(bool val)75 int ezSAT::value(bool val)
76 {
77 	return val ? CONST_TRUE : CONST_FALSE;
78 }
79 
literal()80 int ezSAT::literal()
81 {
82 	literals.push_back(std::string());
83 	return literals.size();
84 }
85 
literal(const std::string & name)86 int ezSAT::literal(const std::string &name)
87 {
88 	if (literalsCache.count(name) == 0) {
89 		literals.push_back(name);
90 		literalsCache[name] = literals.size();
91 	}
92 	return literalsCache.at(name);
93 }
94 
frozen_literal()95 int ezSAT::frozen_literal()
96 {
97 	int id = literal();
98 	freeze(id);
99 	return id;
100 }
101 
frozen_literal(const std::string & name)102 int ezSAT::frozen_literal(const std::string &name)
103 {
104 	int id = literal(name);
105 	freeze(id);
106 	return id;
107 }
108 
expression(OpId op,int a,int b,int c,int d,int e,int f)109 int ezSAT::expression(OpId op, int a, int b, int c, int d, int e, int f)
110 {
111 	std::vector<int> args(6);
112 	args[0] = a, args[1] = b, args[2] = c;
113 	args[3] = d, args[4] = e, args[5] = f;
114 	return expression(op, args);
115 }
116 
expression(OpId op,const std::vector<int> & args)117 int ezSAT::expression(OpId op, const std::vector<int> &args)
118 {
119 	std::vector<int> myArgs;
120 	myArgs.reserve(args.size());
121 	bool xorRemovedOddTrues = false;
122 
123 	addhash(__LINE__);
124 	addhash(op);
125 
126 	for (auto arg : args)
127 	{
128 		addhash(__LINE__);
129 		addhash(arg);
130 
131 		if (arg == 0)
132 			continue;
133 		if (op == OpAnd && arg == CONST_TRUE)
134 			continue;
135 		if ((op == OpOr || op == OpXor) && arg == CONST_FALSE)
136 			continue;
137 		if (op == OpXor && arg == CONST_TRUE) {
138 			xorRemovedOddTrues = !xorRemovedOddTrues;
139 			continue;
140 		}
141 		myArgs.push_back(arg);
142 	}
143 
144 	if (myArgs.size() > 0 && (op == OpAnd || op == OpOr || op == OpXor || op == OpIFF)) {
145 		std::sort(myArgs.begin(), myArgs.end());
146 		int j = 0;
147 		for (int i = 1; i < int(myArgs.size()); i++)
148 			if (j < 0 || myArgs[j] != myArgs[i])
149 				myArgs[++j] = myArgs[i];
150 			else if (op == OpXor)
151 				j--;
152 		myArgs.resize(j+1);
153 	}
154 
155 	switch (op)
156 	{
157 	case OpNot:
158 		assert(myArgs.size() == 1);
159 		if (myArgs[0] == CONST_TRUE)
160 			return CONST_FALSE;
161 		if (myArgs[0] == CONST_FALSE)
162 			return CONST_TRUE;
163 		break;
164 
165 	case OpAnd:
166 		if (myArgs.size() == 0)
167 			return CONST_TRUE;
168 		if (myArgs.size() == 1)
169 			return myArgs[0];
170 		break;
171 
172 	case OpOr:
173 		if (myArgs.size() == 0)
174 			return CONST_FALSE;
175 		if (myArgs.size() == 1)
176 			return myArgs[0];
177 		break;
178 
179 	case OpXor:
180 		if (myArgs.size() == 0)
181 			return xorRemovedOddTrues ? CONST_TRUE : CONST_FALSE;
182 		if (myArgs.size() == 1)
183 			return xorRemovedOddTrues ? NOT(myArgs[0]) : myArgs[0];
184 		break;
185 
186 	case OpIFF:
187 		assert(myArgs.size() >= 1);
188 		if (myArgs.size() == 1)
189 			return CONST_TRUE;
190 		// FIXME: Add proper const folding
191 		break;
192 
193 	case OpITE:
194 		assert(myArgs.size() == 3);
195 		if (myArgs[0] == CONST_TRUE)
196 			return myArgs[1];
197 		if (myArgs[0] == CONST_FALSE)
198 			return myArgs[2];
199 		break;
200 
201 	default:
202 		abort();
203 	}
204 
205 	std::pair<OpId, std::vector<int>> myExpr(op, myArgs);
206 	int id = 0;
207 
208 	if (expressionsCache.count(myExpr) > 0) {
209 		id = expressionsCache.at(myExpr);
210 	} else {
211 		id = -(int(expressions.size()) + 1);
212 		expressionsCache[myExpr] = id;
213 		expressions.push_back(myExpr);
214 	}
215 
216 	if (xorRemovedOddTrues)
217 		id = NOT(id);
218 
219 	addhash(__LINE__);
220 	addhash(id);
221 
222 	return id;
223 }
224 
lookup_literal(int id,std::string & name) const225 void ezSAT::lookup_literal(int id, std::string &name) const
226 {
227 	assert(0 < id && id <= int(literals.size()));
228 	name = literals[id - 1];
229 }
230 
lookup_literal(int id) const231 const std::string &ezSAT::lookup_literal(int id) const
232 {
233 	assert(0 < id && id <= int(literals.size()));
234 	return literals[id - 1];
235 }
236 
lookup_expression(int id,OpId & op,std::vector<int> & args) const237 void ezSAT::lookup_expression(int id, OpId &op, std::vector<int> &args) const
238 {
239 	assert(0 < -id && -id <= int(expressions.size()));
240 	op = expressions[-id - 1].first;
241 	args = expressions[-id - 1].second;
242 }
243 
lookup_expression(int id,OpId & op) const244 const std::vector<int> &ezSAT::lookup_expression(int id, OpId &op) const
245 {
246 	assert(0 < -id && -id <= int(expressions.size()));
247 	op = expressions[-id - 1].first;
248 	return expressions[-id - 1].second;
249 }
250 
parse_string(const std::string &)251 int ezSAT::parse_string(const std::string &)
252 {
253 	abort();
254 }
255 
to_string(int id) const256 std::string ezSAT::to_string(int id) const
257 {
258 	std::string text;
259 
260 	if (id > 0)
261 	{
262 		lookup_literal(id, text);
263 	}
264 	else
265 	{
266 		OpId op;
267 		std::vector<int> args;
268 		lookup_expression(id, op, args);
269 
270 		switch (op)
271 		{
272 		case OpNot:
273 			text = "not(";
274 			break;
275 
276 		case OpAnd:
277 			text = "and(";
278 			break;
279 
280 		case OpOr:
281 			text = "or(";
282 			break;
283 
284 		case OpXor:
285 			text = "xor(";
286 			break;
287 
288 		case OpIFF:
289 			text = "iff(";
290 			break;
291 
292 		case OpITE:
293 			text = "ite(";
294 			break;
295 
296 		default:
297 			abort();
298 		}
299 
300 		for (int i = 0; i < int(args.size()); i++) {
301 			if (i > 0)
302 				text += ", ";
303 			text += to_string(args[i]);
304 		}
305 
306 		text += ")";
307 	}
308 
309 	return text;
310 }
311 
eval(int id,const std::vector<int> & values) const312 int ezSAT::eval(int id, const std::vector<int> &values) const
313 {
314 	if (id > 0) {
315 		if (id <= int(values.size()) && (values[id-1] == CONST_TRUE || values[id-1] == CONST_FALSE || values[id-1] == 0))
316 			return values[id-1];
317 		return 0;
318 	}
319 
320 	OpId op;
321 	const std::vector<int> &args = lookup_expression(id, op);
322 	int a, b;
323 
324 	switch (op)
325 	{
326 	case OpNot:
327 		assert(args.size() == 1);
328 		a = eval(args[0], values);
329 		if (a == CONST_TRUE)
330 			return CONST_FALSE;
331 		if (a == CONST_FALSE)
332 			return CONST_TRUE;
333 		return 0;
334 	case OpAnd:
335 		a = CONST_TRUE;
336 		for (auto arg : args) {
337 			b = eval(arg, values);
338 			if (b != CONST_TRUE && b != CONST_FALSE)
339 				a = 0;
340 			if (b == CONST_FALSE)
341 				return CONST_FALSE;
342 		}
343 		return a;
344 	case OpOr:
345 		a = CONST_FALSE;
346 		for (auto arg : args) {
347 			b = eval(arg, values);
348 			if (b != CONST_TRUE && b != CONST_FALSE)
349 				a = 0;
350 			if (b == CONST_TRUE)
351 				return CONST_TRUE;
352 		}
353 		return a;
354 	case OpXor:
355 		a = CONST_FALSE;
356 		for (auto arg : args) {
357 			b = eval(arg, values);
358 			if (b != CONST_TRUE && b != CONST_FALSE)
359 				return 0;
360 			if (b == CONST_TRUE)
361 				a = a == CONST_TRUE ? CONST_FALSE : CONST_TRUE;
362 		}
363 		return a;
364 	case OpIFF:
365 		assert(args.size() > 0);
366 		a = eval(args[0], values);
367 		for (auto arg : args) {
368 			b = eval(arg, values);
369 			if (b != CONST_TRUE && b != CONST_FALSE)
370 				return 0;
371 			if (b != a)
372 				return CONST_FALSE;
373 		}
374 		return CONST_TRUE;
375 	case OpITE:
376 		assert(args.size() == 3);
377 		a = eval(args[0], values);
378 		if (a == CONST_TRUE)
379 			return eval(args[1], values);
380 		if (a == CONST_FALSE)
381 			return eval(args[2], values);
382 		return 0;
383 	default:
384 		abort();
385 	}
386 }
387 
clear()388 void ezSAT::clear()
389 {
390 	cnfConsumed = false;
391 	cnfVariableCount = 0;
392 	cnfClausesCount = 0;
393 	cnfLiteralVariables.clear();
394 	cnfExpressionVariables.clear();
395 	cnfClauses.clear();
396 }
397 
freeze(int)398 void ezSAT::freeze(int)
399 {
400 }
401 
eliminated(int)402 bool ezSAT::eliminated(int)
403 {
404 	return false;
405 }
406 
assume(int id)407 void ezSAT::assume(int id)
408 {
409 	addhash(__LINE__);
410 	addhash(id);
411 
412 	if (id < 0)
413 	{
414 		assert(0 < -id && -id <= int(expressions.size()));
415 		cnfExpressionVariables.resize(expressions.size());
416 
417 		if (cnfExpressionVariables[-id-1] == 0)
418 		{
419 			OpId op;
420 			std::vector<int> args;
421 			lookup_expression(id, op, args);
422 
423 			if (op == OpNot) {
424 				int idx = bind(args[0]);
425 				cnfClauses.push_back(std::vector<int>(1, -idx));
426 				cnfClausesCount++;
427 				return;
428 			}
429 			if (op == OpOr) {
430 				std::vector<int> clause;
431 				for (int arg : args)
432 					clause.push_back(bind(arg));
433 				cnfClauses.push_back(clause);
434 				cnfClausesCount++;
435 				return;
436 			}
437 			if (op == OpAnd) {
438 				for (int arg : args) {
439 					cnfClauses.push_back(std::vector<int>(1, bind(arg)));
440 					cnfClausesCount++;
441 				}
442 				return;
443 			}
444 		}
445 	}
446 
447 	int idx = bind(id);
448 	cnfClauses.push_back(std::vector<int>(1, idx));
449 	cnfClausesCount++;
450 }
451 
add_clause(const std::vector<int> & args)452 void ezSAT::add_clause(const std::vector<int> &args)
453 {
454 	addhash(__LINE__);
455 	for (auto arg : args)
456 		addhash(arg);
457 
458 	cnfClauses.push_back(args);
459 	cnfClausesCount++;
460 }
461 
add_clause(const std::vector<int> & args,bool argsPolarity,int a,int b,int c)462 void ezSAT::add_clause(const std::vector<int> &args, bool argsPolarity, int a, int b, int c)
463 {
464 	std::vector<int> clause;
465 	for (auto arg : args)
466 		clause.push_back(argsPolarity ? +arg : -arg);
467 	if (a != 0)
468 		clause.push_back(a);
469 	if (b != 0)
470 		clause.push_back(b);
471 	if (c != 0)
472 		clause.push_back(c);
473 	add_clause(clause);
474 }
475 
add_clause(int a,int b,int c)476 void ezSAT::add_clause(int a, int b, int c)
477 {
478 	std::vector<int> clause;
479 	if (a != 0)
480 		clause.push_back(a);
481 	if (b != 0)
482 		clause.push_back(b);
483 	if (c != 0)
484 		clause.push_back(c);
485 	add_clause(clause);
486 }
487 
bind_cnf_not(const std::vector<int> & args)488 int ezSAT::bind_cnf_not(const std::vector<int> &args)
489 {
490 	assert(args.size() == 1);
491 	return -args[0];
492 }
493 
bind_cnf_and(const std::vector<int> & args)494 int ezSAT::bind_cnf_and(const std::vector<int> &args)
495 {
496 	assert(args.size() >= 2);
497 
498 	int idx = ++cnfVariableCount;
499 	add_clause(args, false, idx);
500 
501 	for (auto arg : args)
502 		add_clause(-idx, arg);
503 
504 	return idx;
505 }
506 
bind_cnf_or(const std::vector<int> & args)507 int ezSAT::bind_cnf_or(const std::vector<int> &args)
508 {
509 	assert(args.size() >= 2);
510 
511 	int idx = ++cnfVariableCount;
512 	add_clause(args, true, -idx);
513 
514 	for (auto arg : args)
515 		add_clause(idx, -arg);
516 
517 	return idx;
518 }
519 
bound(int id) const520 int ezSAT::bound(int id) const
521 {
522 	if (id > 0 && id <= int(cnfLiteralVariables.size()))
523 		return cnfLiteralVariables[id-1];
524 	if (-id > 0 && -id <= int(cnfExpressionVariables.size()))
525 		return cnfExpressionVariables[-id-1];
526 	return 0;
527 }
528 
cnfLiteralInfo(int idx) const529 std::string ezSAT::cnfLiteralInfo(int idx) const
530 {
531 	for (int i = 0; i < int(cnfLiteralVariables.size()); i++) {
532 		if (cnfLiteralVariables[i] == idx)
533 			return to_string(i+1);
534 		if (cnfLiteralVariables[i] == -idx)
535 			return "NOT " + to_string(i+1);
536 	}
537 	for (int i = 0; i < int(cnfExpressionVariables.size()); i++) {
538 		if (cnfExpressionVariables[i] == idx)
539 			return to_string(-i-1);
540 		if (cnfExpressionVariables[i] == -idx)
541 			return "NOT " + to_string(-i-1);
542 	}
543 	return "<unnamed>";
544 }
545 
bind(int id,bool auto_freeze)546 int ezSAT::bind(int id, bool auto_freeze)
547 {
548 	addhash(__LINE__);
549 	addhash(id);
550 	addhash(auto_freeze);
551 
552 	if (id >= 0) {
553 		assert(0 < id && id <= int(literals.size()));
554 		cnfLiteralVariables.resize(literals.size());
555 		if (eliminated(cnfLiteralVariables[id-1])) {
556 			fprintf(stderr, "ezSAT: Missing freeze on literal `%s'.\n", to_string(id).c_str());
557 			abort();
558 		}
559 		if (cnfLiteralVariables[id-1] == 0) {
560 			cnfLiteralVariables[id-1] = ++cnfVariableCount;
561 			if (id == CONST_TRUE)
562 				add_clause(+cnfLiteralVariables[id-1]);
563 			if (id == CONST_FALSE)
564 				add_clause(-cnfLiteralVariables[id-1]);
565 		}
566 		return cnfLiteralVariables[id-1];
567 	}
568 
569 	assert(0 < -id && -id <= int(expressions.size()));
570 	cnfExpressionVariables.resize(expressions.size());
571 
572 	if (eliminated(cnfExpressionVariables[-id-1]))
573 	{
574 		cnfExpressionVariables[-id-1] = 0;
575 
576 		// this will recursively call bind(id). within the recursion
577 		// the cnf is pre-set to 0. an idx is allocated there, then it
578 		// is frozen, then it returns here with the new idx already set.
579 		if (auto_freeze)
580 			freeze(id);
581 	}
582 
583 	if (cnfExpressionVariables[-id-1] == 0)
584 	{
585 		OpId op;
586 		std::vector<int> args;
587 		lookup_expression(id, op, args);
588 		int idx = 0;
589 
590 		if (op == OpXor) {
591 			while (args.size() > 1) {
592 				std::vector<int> newArgs;
593 				for (int i = 0; i < int(args.size()); i += 2)
594 					if (i+1 == int(args.size())) {
595 						newArgs.push_back(args[i]);
596 					} else {
597 						int sub1 = AND(args[i], NOT(args[i+1]));
598 						int sub2 = AND(NOT(args[i]), args[i+1]);
599 						newArgs.push_back(OR(sub1, sub2));
600 					}
601 				args.swap(newArgs);
602 			}
603 			idx = bind(args.at(0), false);
604 			goto assign_idx;
605 		}
606 
607 		if (op == OpIFF) {
608 			std::vector<int> invArgs;
609 			for (auto arg : args)
610 				invArgs.push_back(NOT(arg));
611 			int sub1 = expression(OpAnd, args);
612 			int sub2 = expression(OpAnd, invArgs);
613 			idx = bind(OR(sub1, sub2), false);
614 			goto assign_idx;
615 		}
616 
617 		if (op == OpITE) {
618 			int sub1 = AND(args[0], args[1]);
619 			int sub2 = AND(NOT(args[0]), args[2]);
620 			idx = bind(OR(sub1, sub2), false);
621 			goto assign_idx;
622 		}
623 
624 		for (int i = 0; i < int(args.size()); i++)
625 			args[i] = bind(args[i], false);
626 
627 		switch (op)
628 		{
629 			case OpNot: idx = bind_cnf_not(args); break;
630 			case OpAnd: idx = bind_cnf_and(args); break;
631 			case OpOr:  idx = bind_cnf_or(args);  break;
632 			default: abort();
633 		}
634 
635 	assign_idx:
636 		assert(idx != 0);
637 		cnfExpressionVariables[-id-1] = idx;
638 	}
639 
640 	return cnfExpressionVariables[-id-1];
641 }
642 
consumeCnf()643 void ezSAT::consumeCnf()
644 {
645 	if (mode_keep_cnf())
646 		cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
647 	else
648 		cnfConsumed = true;
649 	cnfClauses.clear();
650 }
651 
consumeCnf(std::vector<std::vector<int>> & cnf)652 void ezSAT::consumeCnf(std::vector<std::vector<int>> &cnf)
653 {
654 	if (mode_keep_cnf())
655 		cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
656 	else
657 		cnfConsumed = true;
658 	cnf.swap(cnfClauses);
659 	cnfClauses.clear();
660 }
661 
getFullCnf(std::vector<std::vector<int>> & full_cnf) const662 void ezSAT::getFullCnf(std::vector<std::vector<int>> &full_cnf) const
663 {
664 	assert(full_cnf.empty());
665 	full_cnf.insert(full_cnf.end(), cnfClausesBackup.begin(), cnfClausesBackup.end());
666 	full_cnf.insert(full_cnf.end(), cnfClauses.begin(), cnfClauses.end());
667 }
668 
preSolverCallback()669 void ezSAT::preSolverCallback()
670 {
671 	assert(!non_incremental_solve_used_up);
672 	if (mode_non_incremental())
673 		non_incremental_solve_used_up = true;
674 }
675 
solver(const std::vector<int> &,std::vector<bool> &,const std::vector<int> &)676 bool ezSAT::solver(const std::vector<int>&, std::vector<bool>&, const std::vector<int>&)
677 {
678 	preSolverCallback();
679 	fprintf(stderr, "************************************************************************\n");
680 	fprintf(stderr, "ERROR: You are trying to use the solve() method of the ezSAT base class!\n");
681 	fprintf(stderr, "Use a dervied class like ezMiniSAT instead.\n");
682 	fprintf(stderr, "************************************************************************\n");
683 	abort();
684 }
685 
vec_const(const std::vector<bool> & bits)686 std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
687 {
688 	std::vector<int> vec;
689 	for (auto bit : bits)
690 		vec.push_back(bit ? CONST_TRUE : CONST_FALSE);
691 	return vec;
692 }
693 
vec_const_signed(int64_t value,int numBits)694 std::vector<int> ezSAT::vec_const_signed(int64_t value, int numBits)
695 {
696 	std::vector<int> vec;
697 	for (int i = 0; i < numBits; i++)
698 		vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
699 	return vec;
700 }
701 
vec_const_unsigned(uint64_t value,int numBits)702 std::vector<int> ezSAT::vec_const_unsigned(uint64_t value, int numBits)
703 {
704 	std::vector<int> vec;
705 	for (int i = 0; i < numBits; i++)
706 		vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
707 	return vec;
708 }
709 
vec_var(int numBits)710 std::vector<int> ezSAT::vec_var(int numBits)
711 {
712 	std::vector<int> vec;
713 	for (int i = 0; i < numBits; i++)
714 		vec.push_back(literal());
715 	return vec;
716 }
717 
vec_var(std::string name,int numBits)718 std::vector<int> ezSAT::vec_var(std::string name, int numBits)
719 {
720 	std::vector<int> vec;
721 	for (int i = 0; i < numBits; i++) {
722 		vec.push_back(VAR(name + my_int_to_string(i)));
723 	}
724 	return vec;
725 }
726 
vec_cast(const std::vector<int> & vec1,int toBits,bool signExtend)727 std::vector<int> ezSAT::vec_cast(const std::vector<int> &vec1, int toBits, bool signExtend)
728 {
729 	std::vector<int> vec;
730 	for (int i = 0; i < toBits; i++)
731 		if (i >= int(vec1.size()))
732 			vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
733 		else
734 			vec.push_back(vec1[i]);
735 	return vec;
736 }
737 
vec_not(const std::vector<int> & vec1)738 std::vector<int> ezSAT::vec_not(const std::vector<int> &vec1)
739 {
740 	std::vector<int> vec;
741 	for (auto bit : vec1)
742 		vec.push_back(NOT(bit));
743 	return vec;
744 }
745 
vec_and(const std::vector<int> & vec1,const std::vector<int> & vec2)746 std::vector<int> ezSAT::vec_and(const std::vector<int> &vec1, const std::vector<int> &vec2)
747 {
748 	assert(vec1.size() == vec2.size());
749 	std::vector<int> vec(vec1.size());
750 	for (int i = 0; i < int(vec1.size()); i++)
751 		vec[i] = AND(vec1[i], vec2[i]);
752 	return vec;
753 }
754 
vec_or(const std::vector<int> & vec1,const std::vector<int> & vec2)755 std::vector<int> ezSAT::vec_or(const std::vector<int> &vec1, const std::vector<int> &vec2)
756 {
757 	assert(vec1.size() == vec2.size());
758 	std::vector<int> vec(vec1.size());
759 	for (int i = 0; i < int(vec1.size()); i++)
760 		vec[i] = OR(vec1[i], vec2[i]);
761 	return vec;
762 }
763 
vec_xor(const std::vector<int> & vec1,const std::vector<int> & vec2)764 std::vector<int> ezSAT::vec_xor(const std::vector<int> &vec1, const std::vector<int> &vec2)
765 {
766 	assert(vec1.size() == vec2.size());
767 	std::vector<int> vec(vec1.size());
768 	for (int i = 0; i < int(vec1.size()); i++)
769 		vec[i] = XOR(vec1[i], vec2[i]);
770 	return vec;
771 }
772 
vec_iff(const std::vector<int> & vec1,const std::vector<int> & vec2)773 std::vector<int> ezSAT::vec_iff(const std::vector<int> &vec1, const std::vector<int> &vec2)
774 {
775 	assert(vec1.size() == vec2.size());
776 	std::vector<int> vec(vec1.size());
777 	for (int i = 0; i < int(vec1.size()); i++)
778 		vec[i] = IFF(vec1[i], vec2[i]);
779 	return vec;
780 }
781 
vec_ite(const std::vector<int> & vec1,const std::vector<int> & vec2,const std::vector<int> & vec3)782 std::vector<int> ezSAT::vec_ite(const std::vector<int> &vec1, const std::vector<int> &vec2, const std::vector<int> &vec3)
783 {
784 	assert(vec1.size() == vec2.size() && vec2.size() == vec3.size());
785 	std::vector<int> vec(vec1.size());
786 	for (int i = 0; i < int(vec1.size()); i++)
787 		vec[i] = ITE(vec1[i], vec2[i], vec3[i]);
788 	return vec;
789 }
790 
791 
vec_ite(int sel,const std::vector<int> & vec1,const std::vector<int> & vec2)792 std::vector<int> ezSAT::vec_ite(int sel, const std::vector<int> &vec1, const std::vector<int> &vec2)
793 {
794 	assert(vec1.size() == vec2.size());
795 	std::vector<int> vec(vec1.size());
796 	for (int i = 0; i < int(vec1.size()); i++)
797 		vec[i] = ITE(sel, vec1[i], vec2[i]);
798 	return vec;
799 }
800 
801 // 'y' is the MSB (carry) and x the LSB (sum) output
fulladder(ezSAT * that,int a,int b,int c,int & y,int & x)802 static void fulladder(ezSAT *that, int a, int b, int c, int &y, int &x)
803 {
804 	int tmp = that->XOR(a, b);
805 	int new_x = that->XOR(tmp, c);
806 	int new_y = that->OR(that->AND(a, b), that->AND(c, tmp));
807 #if 0
808 	printf("FULLADD> a=%s, b=%s, c=%s, carry=%s, sum=%s\n", that->to_string(a).c_str(), that->to_string(b).c_str(),
809 			that->to_string(c).c_str(), that->to_string(new_y).c_str(), that->to_string(new_x).c_str());
810 #endif
811 	x = new_x, y = new_y;
812 }
813 
814 // 'y' is the MSB (carry) and x the LSB (sum) output
halfadder(ezSAT * that,int a,int b,int & y,int & x)815 static void halfadder(ezSAT *that, int a, int b, int &y, int &x)
816 {
817 	int new_x = that->XOR(a, b);
818 	int new_y = that->AND(a, b);
819 #if 0
820 	printf("HALFADD> a=%s, b=%s, carry=%s, sum=%s\n", that->to_string(a).c_str(), that->to_string(b).c_str(),
821 			that->to_string(new_y).c_str(), that->to_string(new_x).c_str());
822 #endif
823 	x = new_x, y = new_y;
824 }
825 
vec_count(const std::vector<int> & vec,int numBits,bool clip)826 std::vector<int> ezSAT::vec_count(const std::vector<int> &vec, int numBits, bool clip)
827 {
828 	std::vector<int> sum = vec_const_unsigned(0, numBits);
829 	std::vector<int> carry_vector;
830 
831 	for (auto bit : vec) {
832 		int carry = bit;
833 		for (int i = 0; i < numBits; i++)
834 			halfadder(this, carry, sum[i], carry, sum[i]);
835 		carry_vector.push_back(carry);
836 	}
837 
838 	if (clip) {
839 		int overflow = vec_reduce_or(carry_vector);
840 		sum = vec_ite(overflow, vec_const_unsigned(~0, numBits), sum);
841 	}
842 
843 #if 0
844 	printf("COUNT> vec=[");
845 	for (int i = int(vec.size())-1; i >= 0; i--)
846 		printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : "");
847 	printf("], result=[");
848 	for (int i = int(sum.size())-1; i >= 0; i--)
849 		printf("%s%s", to_string(sum[i]).c_str(), i ? ", " : "");
850 	printf("]\n");
851 #endif
852 
853 	return sum;
854 }
855 
vec_add(const std::vector<int> & vec1,const std::vector<int> & vec2)856 std::vector<int> ezSAT::vec_add(const std::vector<int> &vec1, const std::vector<int> &vec2)
857 {
858 	assert(vec1.size() == vec2.size());
859 	std::vector<int> vec(vec1.size());
860 	int carry = CONST_FALSE;
861 	for (int i = 0; i < int(vec1.size()); i++)
862 		fulladder(this, vec1[i], vec2[i], carry, carry, vec[i]);
863 
864 #if 0
865 	printf("ADD> vec1=[");
866 	for (int i = int(vec1.size())-1; i >= 0; i--)
867 		printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : "");
868 	printf("], vec2=[");
869 	for (int i = int(vec2.size())-1; i >= 0; i--)
870 		printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : "");
871 	printf("], result=[");
872 	for (int i = int(vec.size())-1; i >= 0; i--)
873 		printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : "");
874 	printf("]\n");
875 #endif
876 
877 	return vec;
878 }
879 
vec_sub(const std::vector<int> & vec1,const std::vector<int> & vec2)880 std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<int> &vec2)
881 {
882 	assert(vec1.size() == vec2.size());
883 	std::vector<int> vec(vec1.size());
884 	int carry = CONST_TRUE;
885 	for (int i = 0; i < int(vec1.size()); i++)
886 		fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, vec[i]);
887 
888 #if 0
889 	printf("SUB> vec1=[");
890 	for (int i = int(vec1.size())-1; i >= 0; i--)
891 		printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : "");
892 	printf("], vec2=[");
893 	for (int i = int(vec2.size())-1; i >= 0; i--)
894 		printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : "");
895 	printf("], result=[");
896 	for (int i = int(vec.size())-1; i >= 0; i--)
897 		printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : "");
898 	printf("]\n");
899 #endif
900 
901 	return vec;
902 }
903 
vec_neg(const std::vector<int> & vec)904 std::vector<int> ezSAT::vec_neg(const std::vector<int> &vec)
905 {
906 	std::vector<int> zero(vec.size(), CONST_FALSE);
907 	return vec_sub(zero, vec);
908 }
909 
vec_cmp(const std::vector<int> & vec1,const std::vector<int> & vec2,int & carry,int & overflow,int & sign,int & zero)910 void ezSAT::vec_cmp(const std::vector<int> &vec1, const std::vector<int> &vec2, int &carry, int &overflow, int &sign, int &zero)
911 {
912 	assert(vec1.size() == vec2.size());
913 	carry = CONST_TRUE;
914 	zero = CONST_FALSE;
915 	for (int i = 0; i < int(vec1.size()); i++) {
916 		overflow = carry;
917 		fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, sign);
918 		zero = OR(zero, sign);
919 	}
920 	overflow = XOR(overflow, carry);
921 	carry = NOT(carry);
922 	zero = NOT(zero);
923 
924 #if 0
925 	printf("CMP> vec1=[");
926 	for (int i = int(vec1.size())-1; i >= 0; i--)
927 		printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : "");
928 	printf("], vec2=[");
929 	for (int i = int(vec2.size())-1; i >= 0; i--)
930 		printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : "");
931 	printf("], carry=%s, overflow=%s, sign=%s, zero=%s\n", to_string(carry).c_str(), to_string(overflow).c_str(), to_string(sign).c_str(), to_string(zero).c_str());
932 #endif
933 }
934 
vec_lt_signed(const std::vector<int> & vec1,const std::vector<int> & vec2)935 int ezSAT::vec_lt_signed(const std::vector<int> &vec1, const std::vector<int> &vec2)
936 {
937 	int carry, overflow, sign, zero;
938 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
939 	return OR(AND(NOT(overflow), sign), AND(overflow, NOT(sign)));
940 }
941 
vec_le_signed(const std::vector<int> & vec1,const std::vector<int> & vec2)942 int ezSAT::vec_le_signed(const std::vector<int> &vec1, const std::vector<int> &vec2)
943 {
944 	int carry, overflow, sign, zero;
945 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
946 	return OR(AND(NOT(overflow), sign), AND(overflow, NOT(sign)), zero);
947 }
948 
vec_ge_signed(const std::vector<int> & vec1,const std::vector<int> & vec2)949 int ezSAT::vec_ge_signed(const std::vector<int> &vec1, const std::vector<int> &vec2)
950 {
951 	int carry, overflow, sign, zero;
952 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
953 	return OR(AND(NOT(overflow), NOT(sign)), AND(overflow, sign));
954 }
955 
vec_gt_signed(const std::vector<int> & vec1,const std::vector<int> & vec2)956 int ezSAT::vec_gt_signed(const std::vector<int> &vec1, const std::vector<int> &vec2)
957 {
958 	int carry, overflow, sign, zero;
959 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
960 	return AND(OR(AND(NOT(overflow), NOT(sign)), AND(overflow, sign)), NOT(zero));
961 }
962 
vec_lt_unsigned(const std::vector<int> & vec1,const std::vector<int> & vec2)963 int ezSAT::vec_lt_unsigned(const std::vector<int> &vec1, const std::vector<int> &vec2)
964 {
965 	int carry, overflow, sign, zero;
966 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
967 	return carry;
968 }
969 
vec_le_unsigned(const std::vector<int> & vec1,const std::vector<int> & vec2)970 int ezSAT::vec_le_unsigned(const std::vector<int> &vec1, const std::vector<int> &vec2)
971 {
972 	int carry, overflow, sign, zero;
973 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
974 	return OR(carry, zero);
975 }
976 
vec_ge_unsigned(const std::vector<int> & vec1,const std::vector<int> & vec2)977 int ezSAT::vec_ge_unsigned(const std::vector<int> &vec1, const std::vector<int> &vec2)
978 {
979 	int carry, overflow, sign, zero;
980 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
981 	return NOT(carry);
982 }
983 
vec_gt_unsigned(const std::vector<int> & vec1,const std::vector<int> & vec2)984 int ezSAT::vec_gt_unsigned(const std::vector<int> &vec1, const std::vector<int> &vec2)
985 {
986 	int carry, overflow, sign, zero;
987 	vec_cmp(vec1, vec2, carry, overflow, sign, zero);
988 	return AND(NOT(carry), NOT(zero));
989 }
990 
vec_eq(const std::vector<int> & vec1,const std::vector<int> & vec2)991 int ezSAT::vec_eq(const std::vector<int> &vec1, const std::vector<int> &vec2)
992 {
993 	return vec_reduce_and(vec_iff(vec1, vec2));
994 }
995 
vec_ne(const std::vector<int> & vec1,const std::vector<int> & vec2)996 int ezSAT::vec_ne(const std::vector<int> &vec1, const std::vector<int> &vec2)
997 {
998 	return NOT(vec_reduce_and(vec_iff(vec1, vec2)));
999 }
1000 
vec_shl(const std::vector<int> & vec1,int shift,bool signExtend)1001 std::vector<int> ezSAT::vec_shl(const std::vector<int> &vec1, int shift, bool signExtend)
1002 {
1003 	std::vector<int> vec;
1004 	for (int i = 0; i < int(vec1.size()); i++) {
1005 		int j = i-shift;
1006 		if (int(vec1.size()) <= j)
1007 			vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
1008 		else if (0 <= j)
1009 			vec.push_back(vec1[j]);
1010 		else
1011 			vec.push_back(CONST_FALSE);
1012 	}
1013 	return vec;
1014 }
1015 
vec_srl(const std::vector<int> & vec1,int shift)1016 std::vector<int> ezSAT::vec_srl(const std::vector<int> &vec1, int shift)
1017 {
1018 	std::vector<int> vec;
1019 	for (int i = 0; i < int(vec1.size()); i++) {
1020 		int j = i-shift;
1021 		while (j < 0)
1022 			j += vec1.size();
1023 		while (j >= int(vec1.size()))
1024 			j -= vec1.size();
1025 		vec.push_back(vec1[j]);
1026 	}
1027 	return vec;
1028 }
1029 
vec_shift(const std::vector<int> & vec1,int shift,int extend_left,int extend_right)1030 std::vector<int> ezSAT::vec_shift(const std::vector<int> &vec1, int shift, int extend_left, int extend_right)
1031 {
1032 	std::vector<int> vec;
1033 	for (int i = 0; i < int(vec1.size()); i++) {
1034 		int j = i+shift;
1035 		if (j < 0)
1036 			vec.push_back(extend_right);
1037 		else if (j >= int(vec1.size()))
1038 			vec.push_back(extend_left);
1039 		else
1040 			vec.push_back(vec1[j]);
1041 	}
1042 	return vec;
1043 }
1044 
my_clog2(int x)1045 static int my_clog2(int x)
1046 {
1047 	int result = 0;
1048 	for (x--; x > 0; result++)
1049 		x >>= 1;
1050 	return result;
1051 }
1052 
vec_shift_right(const std::vector<int> & vec1,const std::vector<int> & vec2,bool vec2_signed,int extend_left,int extend_right)1053 std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
1054 {
1055 	int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size()));
1056 
1057 	std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
1058 	int overflow_left = CONST_FALSE, overflow_right = CONST_FALSE;
1059 
1060 	if (vec2_signed) {
1061 		int overflow = CONST_FALSE;
1062 		for (auto bit : overflow_bits)
1063 			overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
1064 		overflow_left = AND(overflow, NOT(vec2.back()));
1065 		overflow_right = AND(overflow, vec2.back());
1066 	} else
1067 		overflow_left = vec_reduce_or(overflow_bits);
1068 
1069 	std::vector<int> buffer = vec1;
1070 
1071 	if (vec2_signed)
1072 		while (buffer.size() < vec1.size() + (1 << vec2_bits))
1073 			buffer.push_back(extend_left);
1074 
1075 	std::vector<int> overflow_pattern_left(buffer.size(), extend_left);
1076 	std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
1077 
1078 	buffer = vec_ite(overflow_left, overflow_pattern_left, buffer);
1079 
1080 	if (vec2_signed)
1081 		buffer = vec_ite(overflow_right, overflow_pattern_left, buffer);
1082 
1083 	for (int i = vec2_bits-1; i >= 0; i--) {
1084 		std::vector<int> shifted_buffer;
1085 		if (vec2_signed && i == vec2_bits-1)
1086 			shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
1087 		else
1088 			shifted_buffer = vec_shift(buffer, 1 << i, extend_left, extend_right);
1089 		buffer = vec_ite(vec2[i], shifted_buffer, buffer);
1090 	}
1091 
1092 	buffer.resize(vec1.size());
1093 	return buffer;
1094 }
1095 
vec_shift_left(const std::vector<int> & vec1,const std::vector<int> & vec2,bool vec2_signed,int extend_left,int extend_right)1096 std::vector<int> ezSAT::vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
1097 {
1098 	// vec2_signed is not implemented in vec_shift_left() yet
1099 	if (vec2_signed) assert(vec2_signed == false);
1100 
1101 	int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
1102 
1103 	std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
1104 	int overflow = vec_reduce_or(overflow_bits);
1105 
1106 	std::vector<int> buffer = vec1;
1107 	std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
1108 	buffer = vec_ite(overflow, overflow_pattern_right, buffer);
1109 
1110 	for (int i = 0; i < vec2_bits; i++) {
1111 		std::vector<int> shifted_buffer;
1112 		shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
1113 		buffer = vec_ite(vec2[i], shifted_buffer, buffer);
1114 	}
1115 
1116 	buffer.resize(vec1.size());
1117 	return buffer;
1118 }
1119 
vec_append(std::vector<int> & vec,const std::vector<int> & vec1) const1120 void ezSAT::vec_append(std::vector<int> &vec, const std::vector<int> &vec1) const
1121 {
1122 	for (auto bit : vec1)
1123 		vec.push_back(bit);
1124 }
1125 
vec_append_signed(std::vector<int> & vec,const std::vector<int> & vec1,int64_t value)1126 void ezSAT::vec_append_signed(std::vector<int> &vec, const std::vector<int> &vec1, int64_t value)
1127 {
1128 	assert(int(vec1.size()) <= 64);
1129 	for (int i = 0; i < int(vec1.size()); i++) {
1130 		if (((value >> i) & 1) != 0)
1131 			vec.push_back(vec1[i]);
1132 		else
1133 			vec.push_back(NOT(vec1[i]));
1134 	}
1135 }
1136 
vec_append_unsigned(std::vector<int> & vec,const std::vector<int> & vec1,uint64_t value)1137 void ezSAT::vec_append_unsigned(std::vector<int> &vec, const std::vector<int> &vec1, uint64_t value)
1138 {
1139 	assert(int(vec1.size()) <= 64);
1140 	for (int i = 0; i < int(vec1.size()); i++) {
1141 		if (((value >> i) & 1) != 0)
1142 			vec.push_back(vec1[i]);
1143 		else
1144 			vec.push_back(NOT(vec1[i]));
1145 	}
1146 }
1147 
vec_model_get_signed(const std::vector<int> & modelExpressions,const std::vector<bool> & modelValues,const std::vector<int> & vec1) const1148 int64_t ezSAT::vec_model_get_signed(const std::vector<int> &modelExpressions, const std::vector<bool> &modelValues, const std::vector<int> &vec1) const
1149 {
1150 	int64_t value = 0;
1151 	std::map<int, bool> modelMap;
1152 	assert(modelExpressions.size() == modelValues.size());
1153 	for (int i = 0; i < int(modelExpressions.size()); i++)
1154 		modelMap[modelExpressions[i]] = modelValues[i];
1155 	for (int i = 0; i < 64; i++) {
1156 		int j = i < int(vec1.size()) ? i : vec1.size()-1;
1157 		if (modelMap.at(vec1[j]))
1158 			value |= int64_t(1) << i;
1159 	}
1160 	return value;
1161 }
1162 
vec_model_get_unsigned(const std::vector<int> & modelExpressions,const std::vector<bool> & modelValues,const std::vector<int> & vec1) const1163 uint64_t ezSAT::vec_model_get_unsigned(const std::vector<int> &modelExpressions, const std::vector<bool> &modelValues, const std::vector<int> &vec1) const
1164 {
1165 	uint64_t value = 0;
1166 	std::map<int, bool> modelMap;
1167 	assert(modelExpressions.size() == modelValues.size());
1168 	for (int i = 0; i < int(modelExpressions.size()); i++)
1169 		modelMap[modelExpressions[i]] = modelValues[i];
1170 	for (int i = 0; i < int(vec1.size()); i++)
1171 		if (modelMap.at(vec1[i]))
1172 			value |= uint64_t(1) << i;
1173 	return value;
1174 }
1175 
vec_reduce_and(const std::vector<int> & vec1)1176 int ezSAT::vec_reduce_and(const std::vector<int> &vec1)
1177 {
1178 	return expression(OpAnd, vec1);
1179 }
1180 
vec_reduce_or(const std::vector<int> & vec1)1181 int ezSAT::vec_reduce_or(const std::vector<int> &vec1)
1182 {
1183 	return expression(OpOr, vec1);
1184 }
1185 
vec_set(const std::vector<int> & vec1,const std::vector<int> & vec2)1186 void ezSAT::vec_set(const std::vector<int> &vec1, const std::vector<int> &vec2)
1187 {
1188 	assert(vec1.size() == vec2.size());
1189 	for (int i = 0; i < int(vec1.size()); i++)
1190 		SET(vec1[i], vec2[i]);
1191 }
1192 
vec_set_signed(const std::vector<int> & vec1,int64_t value)1193 void ezSAT::vec_set_signed(const std::vector<int> &vec1, int64_t value)
1194 {
1195 	assert(int(vec1.size()) <= 64);
1196 	for (int i = 0; i < int(vec1.size()); i++) {
1197 		if (((value >> i) & 1) != 0)
1198 			assume(vec1[i]);
1199 		else
1200 			assume(NOT(vec1[i]));
1201 	}
1202 }
1203 
vec_set_unsigned(const std::vector<int> & vec1,uint64_t value)1204 void ezSAT::vec_set_unsigned(const std::vector<int> &vec1, uint64_t value)
1205 {
1206 	assert(int(vec1.size()) <= 64);
1207 	for (int i = 0; i < int(vec1.size()); i++) {
1208 		if (((value >> i) & 1) != 0)
1209 			assume(vec1[i]);
1210 		else
1211 			assume(NOT(vec1[i]));
1212 	}
1213 }
1214 
bit(_V a)1215 ezSATbit ezSAT::bit(_V a)
1216 {
1217 	return ezSATbit(*this, a);
1218 }
1219 
vec(const std::vector<int> & vec)1220 ezSATvec ezSAT::vec(const std::vector<int> &vec)
1221 {
1222 	return ezSATvec(*this, vec);
1223 }
1224 
printDIMACS(FILE * f,bool verbose) const1225 void ezSAT::printDIMACS(FILE *f, bool verbose) const
1226 {
1227 	if (cnfConsumed) {
1228 		fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!");
1229 		abort();
1230 	}
1231 
1232 	int digits = ceil(log10f(cnfVariableCount)) + 2;
1233 
1234 	fprintf(f, "c generated by ezSAT\n");
1235 
1236 	if (verbose)
1237 	{
1238 		fprintf(f, "c\n");
1239 		fprintf(f, "c mapping of variables to literals:\n");
1240 		for (int i = 0; i < int(cnfLiteralVariables.size()); i++)
1241 			if (cnfLiteralVariables[i] != 0)
1242 				fprintf(f, "c %*d: %s\n", digits, cnfLiteralVariables[i], literals[i].c_str());
1243 
1244 		fprintf(f, "c\n");
1245 		fprintf(f, "c mapping of variables to expressions:\n");
1246 		for (int i = 0; i < int(cnfExpressionVariables.size()); i++)
1247 			if (cnfExpressionVariables[i] != 0)
1248 				fprintf(f, "c %*d: %d\n", digits, cnfExpressionVariables[i], -i-1);
1249 
1250 		if (mode_keep_cnf()) {
1251 			fprintf(f, "c\n");
1252 			fprintf(f, "c %d clauses from backup, %d from current buffer\n",
1253 					int(cnfClausesBackup.size()), int(cnfClauses.size()));
1254 		}
1255 
1256 		fprintf(f, "c\n");
1257 	}
1258 
1259 	std::vector<std::vector<int>> all_clauses;
1260 	getFullCnf(all_clauses);
1261 	assert(cnfClausesCount == int(all_clauses.size()));
1262 
1263 	fprintf(f, "p cnf %d %d\n", cnfVariableCount, cnfClausesCount);
1264 	int maxClauseLen = 0;
1265 	for (auto &clause : all_clauses)
1266 		maxClauseLen = std::max(int(clause.size()), maxClauseLen);
1267 	if (!verbose)
1268 		maxClauseLen = std::min(maxClauseLen, 3);
1269 	for (auto &clause : all_clauses) {
1270 		for (auto idx : clause)
1271 			fprintf(f, " %*d", digits, idx);
1272 		if (maxClauseLen >= int(clause.size()))
1273 			fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0);
1274 		else
1275 			fprintf(f, " %*d\n", digits, 0);
1276 	}
1277 }
1278 
expression2str(const std::pair<ezSAT::OpId,std::vector<int>> & data)1279 static std::string expression2str(const std::pair<ezSAT::OpId, std::vector<int>> &data)
1280 {
1281 	std::string text;
1282 	switch (data.first) {
1283 #define X(op) case ezSAT::op: text += #op; break;
1284 		X(OpNot)
1285 		X(OpAnd)
1286 		X(OpOr)
1287 		X(OpXor)
1288 		X(OpIFF)
1289 		X(OpITE)
1290 	default:
1291 		abort();
1292 #undef X
1293 	}
1294 	text += ":";
1295 	for (auto it : data.second)
1296 		text += " " + my_int_to_string(it);
1297 	return text;
1298 }
1299 
printInternalState(FILE * f) const1300 void ezSAT::printInternalState(FILE *f) const
1301 {
1302 	fprintf(f, "--8<-- snip --8<--\n");
1303 
1304 	fprintf(f, "literalsCache:\n");
1305 	for (auto &it : literalsCache)
1306 		fprintf(f, "    `%s' -> %d\n", it.first.c_str(), it.second);
1307 
1308 	fprintf(f, "literals:\n");
1309 	for (int i = 0; i < int(literals.size()); i++)
1310 		fprintf(f, "    %d: `%s'\n", i+1, literals[i].c_str());
1311 
1312 	fprintf(f, "expressionsCache:\n");
1313 	for (auto &it : expressionsCache)
1314 		fprintf(f, "    `%s' -> %d\n", expression2str(it.first).c_str(), it.second);
1315 
1316 	fprintf(f, "expressions:\n");
1317 	for (int i = 0; i < int(expressions.size()); i++)
1318 		fprintf(f, "    %d: `%s'\n", -i-1, expression2str(expressions[i]).c_str());
1319 
1320 	fprintf(f, "cnfVariables (count=%d):\n", cnfVariableCount);
1321 	for (int i = 0; i < int(cnfLiteralVariables.size()); i++)
1322 		if (cnfLiteralVariables[i] != 0)
1323 			fprintf(f, "    literal %d -> %d (%s)\n", i+1, cnfLiteralVariables[i], to_string(i+1).c_str());
1324 	for (int i = 0; i < int(cnfExpressionVariables.size()); i++)
1325 		if (cnfExpressionVariables[i] != 0)
1326 			fprintf(f, "    expression %d -> %d (%s)\n", -i-1, cnfExpressionVariables[i], to_string(-i-1).c_str());
1327 
1328 	fprintf(f, "cnfClauses:\n");
1329 	for (auto &i1 : cnfClauses) {
1330 		for (auto &i2 : i1)
1331 			fprintf(f, " %4d", i2);
1332 		fprintf(f, "\n");
1333 	}
1334 	if (cnfConsumed)
1335 		fprintf(f, " *** more clauses consumed via cnfConsume() ***\n");
1336 
1337 	fprintf(f, "--8<-- snap --8<--\n");
1338 }
1339 
clog2(int x)1340 static int clog2(int x)
1341 {
1342 	int y = (x & (x - 1));
1343 	y = (y | -y) >> 31;
1344 
1345 	x |= (x >> 1);
1346 	x |= (x >> 2);
1347 	x |= (x >> 4);
1348 	x |= (x >> 8);
1349 	x |= (x >> 16);
1350 
1351 	x >>= 1;
1352 	x -= ((x >> 1) & 0x55555555);
1353 	x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
1354 	x = (((x >> 4) + x) & 0x0f0f0f0f);
1355 	x += (x >> 8);
1356 	x += (x >> 16);
1357 	x = x & 0x0000003f;
1358 
1359 	return x - y;
1360 }
1361 
onehot(const std::vector<int> & vec,bool max_only)1362 int ezSAT::onehot(const std::vector<int> &vec, bool max_only)
1363 {
1364 	// Mixed one-hot/binary encoding as described by Claessen in Sec. 4.2 of
1365 	// "Successful SAT Encoding Techniques. Magnus Bjiirk. 25th July 2009".
1366 	// http://jsat.ewi.tudelft.nl/addendum/Bjork_encoding.pdf
1367 
1368 	std::vector<int> formula;
1369 
1370 	// add at-leat-one constraint
1371 	if (max_only == false)
1372 		formula.push_back(expression(OpOr, vec));
1373 
1374 	if (vec.size() < 8)
1375 	{
1376 		// fall-back to simple O(n^2) solution for small cases
1377 		for (size_t i = 0; i < vec.size(); i++)
1378 			for (size_t j = i+1; j < vec.size(); j++) {
1379 				std::vector<int> clause;
1380 				clause.push_back(NOT(vec[i]));
1381 				clause.push_back(NOT(vec[j]));
1382 				formula.push_back(expression(OpOr, clause));
1383 			}
1384 	}
1385 	else
1386 	{
1387 		// create binary vector
1388 		int num_bits = clog2(vec.size());
1389 		std::vector<int> bits;
1390 		for (int k = 0; k < num_bits; k++)
1391 			bits.push_back(literal());
1392 
1393 		// add at-most-one clauses using binary encoding
1394 		for (size_t i = 0; i < vec.size(); i++)
1395 			for (int k = 0; k < num_bits; k++) {
1396 				std::vector<int> clause;
1397 				clause.push_back(NOT(vec[i]));
1398 				clause.push_back((i & (1 << k)) != 0 ? bits[k] : NOT(bits[k]));
1399 				formula.push_back(expression(OpOr, clause));
1400 			}
1401 	}
1402 
1403 	return expression(OpAnd, formula);
1404 }
1405 
1406 #if 0
1407 int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
1408 {
1409 	// many-hot encoding using a simple sorting network
1410 
1411 	if (max_hot < 0)
1412 		max_hot = min_hot;
1413 
1414 	std::vector<int> formula;
1415 	int M = max_hot+1, N = vec.size();
1416 	std::map<std::pair<int,int>, int> x;
1417 
1418 	for (int i = -1; i < N; i++)
1419 	for (int j = -1; j < M; j++)
1420 		x[std::pair<int,int>(i,j)] = j < 0 ? CONST_TRUE : i < 0 ? CONST_FALSE : literal();
1421 
1422 	for (int i = 0; i < N; i++)
1423 	for (int j = 0; j < M; j++) {
1424 		formula.push_back(OR(NOT(vec[i]), x[std::pair<int,int>(i-1,j-1)], NOT(x[std::pair<int,int>(i,j)])));
1425 		formula.push_back(OR(NOT(vec[i]), NOT(x[std::pair<int,int>(i-1,j-1)]), x[std::pair<int,int>(i,j)]));
1426 		formula.push_back(OR(vec[i], x[std::pair<int,int>(i-1,j)], NOT(x[std::pair<int,int>(i,j)])));
1427 		formula.push_back(OR(vec[i], NOT(x[std::pair<int,int>(i-1,j)]), x[std::pair<int,int>(i,j)]));
1428 #if 0
1429 		// explicit resolution clauses -- in tests it was better to let the sat solver figure those out
1430 		formula.push_back(OR(NOT(x[std::pair<int,int>(i-1,j-1)]), NOT(x[std::pair<int,int>(i-1,j)]), x[std::pair<int,int>(i,j)]));
1431 		formula.push_back(OR(x[std::pair<int,int>(i-1,j-1)], x[std::pair<int,int>(i-1,j)], NOT(x[std::pair<int,int>(i,j)])));
1432 #endif
1433 	}
1434 
1435 	for (int j = 0; j < M; j++) {
1436 		if (j+1 <= min_hot)
1437 			formula.push_back(x[std::pair<int,int>(N-1,j)]);
1438 		else if (j+1 > max_hot)
1439 			formula.push_back(NOT(x[std::pair<int,int>(N-1,j)]));
1440 	}
1441 
1442 	return expression(OpAnd, formula);
1443 }
1444 #else
lfsr_sym(ezSAT * that,const std::vector<int> & vec,int poly)1445 static std::vector<int> lfsr_sym(ezSAT *that, const std::vector<int> &vec, int poly)
1446 {
1447 	std::vector<int> out;
1448 
1449 	for (int i = 0; i < int(vec.size()); i++)
1450 		if ((poly & (1 << (i+1))) != 0) {
1451 			if (out.empty())
1452 				out.push_back(vec.at(i));
1453 			else
1454 				out.at(0) = that->XOR(out.at(0), vec.at(i));
1455 		}
1456 
1457 	for (int i = 0; i+1 < int(vec.size()); i++)
1458 		out.push_back(vec.at(i));
1459 
1460 	return out;
1461 }
1462 
lfsr_num(int vec,int poly,int cnt=1)1463 static int lfsr_num(int vec, int poly, int cnt = 1)
1464 {
1465 	int mask = poly >> 1;
1466 	mask |= mask >> 1;
1467 	mask |= mask >> 2;
1468 	mask |= mask >> 4;
1469 	mask |= mask >> 8;
1470 	mask |= mask >> 16;
1471 
1472 	while (cnt-- > 0) {
1473 		int bits = vec & (poly >> 1);
1474 		bits = ((bits & 0xAAAAAAAA) >>  1) ^ (bits & 0x55555555);
1475 		bits = ((bits & 0x44444444) >>  2) ^ (bits & 0x11111111);
1476 		bits = ((bits & 0x10101010) >>  4) ^ (bits & 0x01010101);
1477 		bits = ((bits & 0x01000100) >>  8) ^ (bits & 0x00010001);
1478 		bits = ((bits & 0x00010000) >> 16) ^ (bits & 0x00000001);
1479 		vec = ((vec << 1) | bits) & mask;
1480 	}
1481 
1482 	return vec;
1483 }
1484 
manyhot(const std::vector<int> & vec,int min_hot,int max_hot)1485 int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
1486 {
1487 	// many-hot encoding using LFSR as counter
1488 
1489 	int poly = 0;
1490 	int nbits = 0;
1491 
1492 	if (vec.size() < 3) {
1493 		poly = (1 << 2) | (1 << 1) | 1;
1494 		nbits = 2;
1495 	} else
1496 	if (vec.size() < 7) {
1497 		poly = (1 << 3) | (1 << 2) | 1;
1498 		nbits = 3;
1499 	} else
1500 	if (vec.size() < 15) {
1501 		poly = (1 << 4) | (1 << 3) | 1;
1502 		nbits = 4;
1503 	} else
1504 	if (vec.size() < 31) {
1505 		poly = (1 << 5) | (1 << 3) | 1;
1506 		nbits = 5;
1507 	} else
1508 	if (vec.size() < 63) {
1509 		poly = (1 << 6) | (1 << 5) | 1;
1510 		nbits = 6;
1511 	} else
1512 	if (vec.size() < 127) {
1513 		poly = (1 << 7) | (1 << 6) | 1;
1514 		nbits = 7;
1515 	} else
1516 	// if (vec.size() < 255) {
1517 	//	poly = (1 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | 1;
1518 	//	nbits = 8;
1519 	// } else
1520 	if (vec.size() < 511) {
1521 		poly = (1 << 9) | (1 << 5) | 1;
1522 		nbits = 9;
1523 	} else {
1524 		assert(0);
1525 	}
1526 
1527 	std::vector<int> min_val;
1528 	std::vector<int> max_val;
1529 
1530 	if (min_hot > 1)
1531 		min_val = vec_const_unsigned(lfsr_num(1, poly, min_hot), nbits);
1532 
1533 	if (max_hot >= 0)
1534 		max_val = vec_const_unsigned(lfsr_num(1, poly, max_hot+1), nbits);
1535 
1536 	std::vector<int> state = vec_const_unsigned(1, nbits);
1537 
1538 	std::vector<int> match_min;
1539 	std::vector<int> match_max;
1540 
1541 	if (min_hot == 1)
1542 		match_min = vec;
1543 
1544 	for (int i = 0; i < int(vec.size()); i++)
1545 	{
1546 		state = vec_ite(vec[i], lfsr_sym(this, state, poly), state);
1547 
1548 		if (!min_val.empty() && i+1 >= min_hot)
1549 			match_min.push_back(vec_eq(min_val, state));
1550 
1551 		if (!max_val.empty() && i >= max_hot)
1552 			match_max.push_back(vec_eq(max_val, state));
1553 	}
1554 
1555 	int min_matched = min_hot ? vec_reduce_or(match_min) : CONST_TRUE;
1556 	int max_matched = vec_reduce_or(match_max);
1557 
1558 	return AND(min_matched, NOT(max_matched));
1559 }
1560 #endif
1561 
ordered(const std::vector<int> & vec1,const std::vector<int> & vec2,bool allow_equal)1562 int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, bool allow_equal)
1563 {
1564 	std::vector<int> formula;
1565 	int last_x = CONST_FALSE;
1566 
1567 	assert(vec1.size() == vec2.size());
1568 	for (size_t i = 0; i < vec1.size(); i++)
1569 	{
1570 		int a = vec1[i], b = vec2[i];
1571 		formula.push_back(OR(NOT(a), b, last_x));
1572 
1573 		int next_x = i+1 < vec1.size() ? literal() : allow_equal ? CONST_FALSE : CONST_TRUE;
1574 		formula.push_back(OR(a, b, last_x, NOT(next_x)));
1575 		formula.push_back(OR(NOT(a), NOT(b), last_x, NOT(next_x)));
1576 		last_x = next_x;
1577 	}
1578 
1579 	return expression(OpAnd, formula);
1580 }
1581 
1582