ACEC/fraig.cpp
2022-10-21 19:34:18 +08:00

291 lines
9.2 KiB
C++

#include "sweep.hpp"
#include "circuit.hpp"
#include "src/cadical.hpp"
extern "C" {
#include "aiger.h"
}
void Sweep::propagate(int* input, int* result) {
std::queue<int> q;
for(int i=0; i<aig->num_inputs; i++) {
result[aig->inputs[i].lit] = input[i];
result[aig->inputs[i].lit+1] = !input[i];
q.push(aiger_lit2var(aig->inputs[i].lit));
}
static int* topo_counter = new int[maxvar + 1];
memset(topo_counter, 0, (maxvar + 1) * sizeof(int));
while(!q.empty()) {
int cur = q.front();
q.pop();
for(auto& edge : graph.edge[cur]) {
int v = edge.to;
topo_counter[v]++;
if(topo_counter[v] == 2) {
q.push(v);
//cout << "redge: " << v << " " << graph.redge[v][0].to << " " << graph.redge[v][1].to << endl;
Graph::Edge rhs0_edge = graph.redge[v][0];
int rhs0 = aiger_var2lit(rhs0_edge.to);
Graph::Edge rhs1_edge = graph.redge[v][1];
int rhs1 = aiger_var2lit(rhs1_edge.to);
result[aiger_var2lit(v)] = result[rhs0 + rhs0_edge.neg] & result[rhs1 + rhs1_edge.neg];
result[aiger_var2lit(v)+1] = !result[aiger_var2lit(v)];
//cout << "var: " << aiger_var2lit(v) << " = " << rhs0 + rhs0_edge.neg << " " << rhs1 + rhs1_edge.neg << " : " << result[aiger_var2lit(v)] << endl;
}
}
}
}
void Sweep::circuit_propagate(int *input, int* result) {
std::queue<int> q;
for(int i=1; i<=aig->num_inputs; i++) {
result[i] = input[i - 1];
q.push(i);
// printf("%d %d\n", i, result[i]);
}
for (int i = 1; i <= maxvar; i++) seen[i] = 0;
while(!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < inv_C[x].size(); i++) {
int v = inv_C[x][i];
seen[v]++;
if (seen[v] == C[v].sz) {
q.push(v);
if (C[v].type == And) {
result[v] = 1;
for (int j = 0; j < C[v].sz; j++) {
int x = C[v][j];
result[v] &= x > 0 ? result[abs(x)] : !result[abs(x)];
}
}
else if (C[v].type == Xor) {
result[v] = 0;
for (int j = 0; j < C[v].sz; j++) {
int x = C[v][j];
result[v] ^= x > 0 ? result[abs(x)] : !result[abs(x)];
}
}
else if (C[v].type == Majority) {
int s[2] = {0, 0};
for (int j = 0; j < C[v].sz; j++) {
int x = C[v][j];
s[x > 0 ? result[abs(x)] : !result[abs(x)]]++;
}
result[v] = s[1] > s[0] ? 1 : 0;
}
else if (C[v].type == HA) {
assert(C[v].sz == 2);
int s = 0;
for (int j = 0; j < C[v].sz; j++) {
int x = C[v][j];
s += x > 0 ? result[abs(x)] : !result[abs(x)];
}
result[v] = s % 2;
result[abs(C[v].carrier)] = s >> 1;
if (C[v].carrier < 0) result[abs(C[v].carrier)] = !result[abs(C[v].carrier)];
q.push(abs(C[v].carrier));
}
else if (C[v].type == FA) {
assert(C[v].sz == 3);
int s = 0;
for (int j = 0; j < C[v].sz; j++) {
int x = C[v][j];
s += x > 0 ? result[abs(x)] : !result[abs(x)];
}
result[v] = s % 2;
result[abs(C[v].carrier)] = s >> 1;
if (C[v].carrier < 0) result[abs(C[v].carrier)] = !result[abs(C[v].carrier)];
q.push(abs(C[v].carrier));
}
if (C[v].neg) result[v] = !result[v];
// printf("%d %d\n", v, result[v]);
}
}
}
}
// int Sweep::seen_cut_points(aiger* aig, int x, int y) {
// std::queue<int> q;
// int *used =
// x = x & 1 ? -aiger_lit2var(x) : aiger_lit2var(x);
// y = y & 1 ? -aiger_lit2var(y) : aiger_lit2var(y);
// if (!used[abs(x)])
// q.push(abs(x)), used[abs(x)] = true;
// if(!used[abs(y)])
// q.push(abs(y)), used[abs(y)] = true;
// }
bool Sweep::check_var_equal(int x, int y, int assume) {
std::queue<int> q;
x = x & 1 ? -aiger_lit2var(x) : aiger_lit2var(x);
y = y & 1 ? -aiger_lit2var(y) : aiger_lit2var(y);
if (!used[abs(x)])
q.push(abs(x)), used[abs(x)] = true;
if(!used[abs(y)])
q.push(abs(y)), used[abs(y)] = true;
int can_del = 2;
while(!q.empty()) {
int u = q.front();
q.pop();
/*
(u => a & b) <=> ~u | (a & b) <=> (~u | a) & (~u | b)
(u <= a & b) <=> ~(a & b) | u <=> ~a | ~b | u
*/
if(graph.redge[u].size() == 0) continue;
int a = graph.redge[u][0].to;
int b = graph.redge[u][1].to;
//cout << "AND " << aiger_var2lit(u) << " " << (aiger_var2lit(a) + graph.redge[u][0].neg) << " " << (aiger_var2lit(b) + graph.redge[u][1].neg) << endl;
if(graph.redge[u][0].neg) a = -a;
if(graph.redge[u][1].neg) b = -b;
solver->add(-u), solver->add( a), solver->add(0);
solver->add(-u), solver->add( b), solver->add(0);
solver->add(-a), solver->add(-b), solver->add(u), solver->add(0);
a = abs(a), b = abs(b);
if(!used[a])
q.push(a), used[a] = true, can_del++;
if(!used[b])
q.push(b), used[b] = true, can_del++;
}
//Assume -NV
solver->add(-assume), solver->add(-x), solver->add(-y), solver->add(0);
solver->add(-assume), solver->add(x), solver->add(y), solver->add(0);
solver->assume (assume);
int result = solver->solve ();
// if (result == 20) printf("can delete %d vars\n", can_del);
return result == 20;
}
bool Sweep::check_constant(int x, int val) {
std::queue<int> q;
x = x & 1 ? -aiger_lit2var(x) : aiger_lit2var(x);
if (!used[abs(x)]) q.push(abs(x)), used[abs(x)] = true;
while(!q.empty()) {
int u = q.front();
q.pop();
if(graph.redge[u].size() == 0) continue;
int a = graph.redge[u][0].to;
int b = graph.redge[u][1].to;
if(graph.redge[u][0].neg) a = -a;
if(graph.redge[u][1].neg) b = -b;
solver->add(-u), solver->add( a), solver->add(0);
solver->add(-u), solver->add( b), solver->add(0);
solver->add(-a), solver->add(-b), solver->add(u), solver->add(0);
a = abs(a), b = abs(b);
if(!used[a]) q.push(a), used[a] = true;
if(!used[b]) q.push(b), used[b] = true;
}
solver->assume (x * (val ? -1 : 1));
int result = solver->solve();
return result == 20;
}
void Sweep::random_simulation() {
int* result = new int[2 * maxvar + 2];
int* circuit_res = new int[maxvar + 1];
int* input_vector = new int[aig->num_inputs];
for(int i=0; i<rounds; i++)
{
if (i % 10000 == 0) printf("================================= %d ===========================\n", i);
for(int i=0; i<aig->num_inputs; i++) {
input_vector[i] = rand() % 2;
}
for (int i=0; i<det_v_sz; i++) {
if (abs(det_v[i]) <= aig->num_inputs) input_vector[abs(det_v[i]) - 1] = det_v[i] > 0 ? 1 : 0;
}
memset(result, -1, (2 * maxvar + 2) * sizeof(int));
memset(circuit_res, -1, (maxvar + 1) * sizeof(int));
propagate(input_vector, result);
circuit_propagate(input_vector, circuit_res);
if (result[output] != !circuit_res[output >> 1]) {
printf("wrong %d %d %d\n", output, !result[output], circuit_res[output >> 1]);
for (int i = 1; i <= maxvar; i++) {
if (circuit_res[i] == -1) continue;
if (result[i * 2] != circuit_res[i]) printf("%d %d %d\n", i, result[i * 2], circuit_res[i]);
printf("%d %d\n", i, result[i << 1]);
}
return;
}
std::vector<std::vector<int>> tmp;
for(auto& clas : classes) {
std::vector<int> v0;
std::vector<int> v1;
for(auto &v : clas) {
if(result[v]) v1.push_back(v), sum_pos[v] += 1;
else v0.push_back(v), sum_neg[v] += 1;
}
if(v0.size() > 1) tmp.push_back(v0);
if(v1.size() > 1) tmp.push_back(v1);
}
classes = tmp;
}
printf("c Number of equivalent classes: %d\n", classes.size());
// printf("classes: \n");
// for(auto& clas : classes) {
// int lit = clas[0];
// printf("[ ");
// for(auto &v : clas) {
// printf("%d ", v);
// }
// printf("] %d %d\n", sum_pos[lit], sum_neg[lit]);
// }
}
void Sweep::simulation() {
//printf("c =================================== detect =================================\n");
seen = new int[maxvar + 1];
classes.push_back(std::vector<int>());
for(int i=2; i<=maxvar*2+1; i++) {
classes[0].push_back(i);
}
random_simulation();
}