474 lines
13 KiB
C++
474 lines
13 KiB
C++
#include "circuit.h"
|
|
|
|
#include <queue>
|
|
#include <unordered_set>
|
|
#include <unordered_map>
|
|
#include <algorithm>
|
|
#include "assert.h"
|
|
#include <chrono>
|
|
|
|
bool Circuit::local_search() {
|
|
|
|
ls_reset_data();
|
|
|
|
ls_init_stems();
|
|
|
|
ls_init_weight();
|
|
|
|
ls_random_circuit();
|
|
|
|
for(int i=0; i<MAX_STEPS; i++) {
|
|
|
|
auto start = std::chrono::system_clock::now();
|
|
|
|
printf("[FLIP] stem: %lld, fault:%lld, stem_cnt: %lld, fault_cnt:%lld, fpl_score: %lld\n", stem_total_cost, fault_total_weight, stem_total_cnt, fault_total_cnt, fault_propagate_score);
|
|
|
|
Gate* stem = ls_pick();
|
|
|
|
if(stem == nullptr) {
|
|
printf("[UP] stem: %lld, fault:%lld, stem_cnt: %lld, fault_cnt:%lld, fpl_score: %lld\n", stem_total_cost, fault_total_weight, stem_total_cnt, fault_total_cnt, fault_propagate_score);
|
|
ls_update_weight();
|
|
stem = ls_pick_falsified();
|
|
}
|
|
|
|
if(stem_total_cnt == stems.size()) {
|
|
//printf("FIND SOLUTION!\n");
|
|
//printf("[SOL] flip: %lld, stem: %lld, fault:%lld. flip_cnt: %d, stem_cnt: %d, fault_cnt:%d\n", flip_total_weight, stem_total_weight, fault_total_weight, flip_total_cnt, stem_total_cnt, fault_total_cnt);
|
|
break;
|
|
}
|
|
|
|
assert(is_valid_circuit());
|
|
|
|
auto end = std::chrono::system_clock::now();
|
|
std::chrono::duration<double> elapsed_seconds = end - start;
|
|
update_cnt++;
|
|
update_time += elapsed_seconds.count();
|
|
|
|
//printf("[UP] flip: %lld, stem: %lld, fault:%lld. flip_cnt: %lld, stem_cnt: %lld, fault_cnt:%lld\n", flip_total_weight, stem_total_weight, fault_total_weight, flip_total_cnt, stem_total_cnt, fault_total_cnt);
|
|
}
|
|
|
|
ls_statistics();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Circuit::ls_statistics() {
|
|
|
|
int last_undetect = global_fault_undetected_count;
|
|
|
|
for(Gate* g : gates) {
|
|
if(g->fault_detected[0] && !g->global_fault_detected[0]) {
|
|
global_fault_undetected_count--;
|
|
g->global_fault_detected[0] = 1;
|
|
}
|
|
if(g->fault_detected[1] && !g->global_fault_detected[1]) {
|
|
global_fault_undetected_count--;
|
|
g->global_fault_detected[1] = 1;
|
|
}
|
|
}
|
|
|
|
printf("coverage: %.2f%% undected_fault: %d delta: %d\n",
|
|
(gates.size() * 2.0 - global_fault_undetected_count) / (gates.size() * 2.0) * 100,
|
|
global_fault_undetected_count, global_fault_undetected_count - last_undetect);
|
|
}
|
|
|
|
void Circuit::ls_update_weight() {
|
|
|
|
if(rand() % 10000 <= SP * 10000) {
|
|
for(Gate* g : gates) {
|
|
if(g->stem && g->stem_satisfied && (g->stem_weight - STEM_INC >= 1)) {
|
|
g->stem_weight -= STEM_INC;
|
|
}
|
|
|
|
if(g->fault_detected[0] && g->fault_weight[0] - FAULT_INC >= 1) {
|
|
g->fault_weight[0] -= FAULT_INC;
|
|
fault_propagate_score -= FAULT_INC * (g->fault_propagate_length[0]);
|
|
}
|
|
|
|
if(g->fault_detected[1] && g->fault_weight[1] - FAULT_INC >= 1) {
|
|
g->fault_weight[1] -= FAULT_INC;
|
|
fault_propagate_score -= FAULT_INC * (g->fault_propagate_length[1]);
|
|
}
|
|
}
|
|
} else {
|
|
for(Gate* g : gates) {
|
|
if(g->stem && !g->stem_satisfied && (g->stem_weight + STEM_INC < STEM_WEIGHT_MAX)) {
|
|
g->stem_weight += STEM_INC;
|
|
stem_total_cost += STEM_INC;
|
|
}
|
|
|
|
if(!g->fault_detected[0] && g->fault_weight[0] > 0 && (g->fault_weight[0] + FAULT_INC < FAULT_WEIGHT_MAX)) {
|
|
g->fault_weight[0] += FAULT_INC;
|
|
fault_propagate_score += FAULT_INC * (g->fault_propagate_length[0]);
|
|
}
|
|
|
|
if(!g->fault_detected[1] && g->fault_weight[1] > 0 && (g->fault_weight[1] + FAULT_INC < FAULT_WEIGHT_MAX)) {
|
|
g->fault_weight[1] += FAULT_INC;
|
|
fault_propagate_score += FAULT_INC * (g->fault_propagate_length[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Gate* Circuit::ls_pick() {
|
|
Gate* stem = nullptr;
|
|
ll max_score = 0;
|
|
|
|
std::vector<Gate*> stems_random;
|
|
std::vector<Gate*> candidates;
|
|
|
|
for(int i=0; i<stems.size(); i++) {
|
|
if(stems[i]->CC) {
|
|
stems_random.push_back(stems[i]);
|
|
}
|
|
}
|
|
|
|
for(int i=0; i<stems_random.size(); i++) {
|
|
std::swap(stems_random[i], stems_random[rand()%stems_random.size()]);
|
|
}
|
|
|
|
const int max_index = std::min((int)stems_random.size(), SAMPLING_COUNT);
|
|
|
|
for(int i=0; i<max_index; i++) {
|
|
Gate* t_stem = stems_random[i];
|
|
ll t_score = ls_pick_score(t_stem);
|
|
if(t_score > max_score) {
|
|
max_score = t_score;
|
|
stem = t_stem;
|
|
}
|
|
}
|
|
|
|
return stem;
|
|
}
|
|
|
|
Gate* Circuit::ls_pick_falsified() {
|
|
std::vector<Gate*> candidates;
|
|
for(Gate *g : stems) {
|
|
if(g->stem_satisfied) continue;
|
|
|
|
for(Gate* pre : g->pre_stems)
|
|
candidates.push_back(pre);
|
|
|
|
for(Gate* suc : g->suc_stems)
|
|
candidates.push_back(suc);
|
|
|
|
candidates.push_back(g);
|
|
}
|
|
|
|
if(candidates.size() == 0) {
|
|
candidates.push_back(stems[rand()%stems.size()]);
|
|
}
|
|
|
|
return candidates[rand()%candidates.size()];
|
|
}
|
|
|
|
void Circuit::ls_init_stems() {
|
|
stems.clear();
|
|
|
|
for(Gate* g : gates) {
|
|
if(g->pi || g->po) {
|
|
g->stem = true;
|
|
}
|
|
|
|
if(!g->global_fault_detected[0] || !g->global_fault_detected[0]) {
|
|
g->stem = true;
|
|
}
|
|
|
|
if(g->fan_outs.size() >= 2) {
|
|
g->stem = true;
|
|
}
|
|
|
|
if(g->stem) {
|
|
stems.push_back(g);
|
|
}
|
|
}
|
|
|
|
for(Gate *g : gates) {
|
|
if(g->pi) continue;
|
|
std::queue<Gate*> q;
|
|
std::unordered_map<Gate*, bool> used;
|
|
q.push(g);
|
|
|
|
while(!q.empty()) {
|
|
Gate* now = q.front();
|
|
q.pop();
|
|
for(Gate* in : now->fan_ins) {
|
|
if(in->stem) {
|
|
g->pre_stems.push_back(in);
|
|
} else if(!used[in]) {
|
|
used[in] = true;
|
|
q.push(in);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(Gate *g : gates) {
|
|
if(g->po) continue;
|
|
std::queue<Gate*> q;
|
|
std::unordered_map<Gate*, bool> used;
|
|
q.push(g);
|
|
|
|
while(!q.empty()) {
|
|
Gate* now = q.front();
|
|
q.pop();
|
|
for(Gate* out : now->fan_outs) {
|
|
if(out->stem) {
|
|
g->suc_stems.push_back(out);
|
|
} else if(!used[out]) {
|
|
used[out] = true;
|
|
q.push(out);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ll Circuit::ls_pick_score(Gate* stem) {
|
|
|
|
ll old_score = ls_circuit_score();
|
|
|
|
ls_flip(stem);
|
|
|
|
ll new_score = ls_circuit_score();
|
|
|
|
return new_score - old_score;
|
|
}
|
|
|
|
ll Circuit::ls_circuit_score() {
|
|
ll score = - stem_total_cost + fault_propagate_score;
|
|
return score;
|
|
}
|
|
|
|
void Circuit::ls_init_weight() {
|
|
for(Gate* s : stems) {
|
|
s->stem_weight = 1;
|
|
stem_total_cost += s->stem_weight;
|
|
}
|
|
|
|
for(Gate* g : gates) {
|
|
g->fault_weight[0] = !g->global_fault_detected[0];
|
|
g->fault_weight[1] = !g->global_fault_detected[1];
|
|
}
|
|
}
|
|
|
|
void Circuit::ls_random_circuit() {
|
|
|
|
// init assignment
|
|
for(Gate* s : stems) {
|
|
s->value = rand() % 2;
|
|
}
|
|
|
|
// recal value by topo
|
|
for(Gate *g : gates) {
|
|
if(g->stem) {
|
|
g->stem_satisfied = (g->recal_value() == g->value);
|
|
if(g->stem_satisfied) {
|
|
stem_total_cost -= g->stem_weight;
|
|
stem_total_cnt++;
|
|
}
|
|
} else {
|
|
g->value = g->recal_value();
|
|
}
|
|
}
|
|
|
|
// recal fault by rtopo
|
|
for(Gate* g : rtopo_gates) {
|
|
g->recal_fault(g->fault_detected);
|
|
if(g->fault_detected[0]) {
|
|
fault_total_weight += g->fault_weight[0];
|
|
fault_total_cnt++;
|
|
}
|
|
if(g->fault_detected[1]) {
|
|
fault_total_weight += g->fault_weight[1];
|
|
fault_total_cnt++;
|
|
}
|
|
|
|
g->propagate = (g->fault_detected[0] || g->fault_detected[1]);
|
|
|
|
g->recal_propagate_len(g->fault_propagate_length);
|
|
|
|
fault_propagate_score += g->fault_weight[0] * g->fault_propagate_length[0];
|
|
fault_propagate_score += g->fault_weight[1] * g->fault_propagate_length[1];
|
|
|
|
}
|
|
|
|
assert(is_valid_circuit());
|
|
}
|
|
|
|
void Circuit::ls_reset_data() {
|
|
|
|
stems.clear();
|
|
|
|
fault_propagate_score = 0;
|
|
|
|
stem_total_cost = 0;
|
|
stem_total_cnt = 0;
|
|
|
|
fault_total_weight = 0;
|
|
fault_total_cnt = 0;
|
|
|
|
for(Gate *g : gates) {
|
|
g->CC = 1;
|
|
g->stem = 0;
|
|
g->propagate = 0;
|
|
g->stem_weight = 0;
|
|
g->stem_satisfied = 0;
|
|
|
|
g->fault_weight[0] = g->fault_weight[1] = 0;
|
|
g->fault_detected[0] = g->fault_detected[1] = 0;
|
|
|
|
g->fault_propagate_length[0] = 0;
|
|
g->fault_propagate_length[1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void Circuit::ls_flip(Gate* stem) {
|
|
|
|
// update CC
|
|
stem->CC = 0;
|
|
for(Gate* pre : stem->pre_stems) {
|
|
pre->CC = 1;
|
|
}
|
|
for(Gate* suc : stem->suc_stems) {
|
|
suc->CC = 1;
|
|
}
|
|
|
|
// update value
|
|
bool new_stem_satisfied = (stem->recal_value() == stem->value);
|
|
|
|
if(new_stem_satisfied && !stem->stem_satisfied){
|
|
stem->stem_satisfied = true;
|
|
stem_total_cost -= stem->stem_weight;
|
|
stem_total_cnt += 1;
|
|
}
|
|
|
|
if(!new_stem_satisfied && stem->stem_satisfied){
|
|
stem->stem_satisfied = false;
|
|
stem_total_cost += stem->stem_weight;
|
|
stem_total_cnt -= 1;
|
|
}
|
|
|
|
// update po fault
|
|
if(stem->po) {
|
|
stem->propagate = true;
|
|
if(!stem->fault_detected[!stem->value]) {
|
|
fault_total_weight += stem->fault_weight[!stem->value];
|
|
fault_total_cnt += 1;
|
|
stem->fault_detected[!stem->value] = true;
|
|
}
|
|
|
|
if(stem->fault_detected[stem->value]) {
|
|
fault_total_weight -= stem->fault_weight[stem->value];
|
|
fault_total_cnt -= 1;
|
|
stem->fault_detected[stem->value] = false;
|
|
}
|
|
}
|
|
|
|
static std::queue<Gate*> q1;
|
|
static std::unordered_map<Gate*, int> used1;
|
|
static std::queue<Gate*> q2;
|
|
static std::unordered_map<Gate*, int> used2;
|
|
used1.clear();
|
|
used2.clear();
|
|
|
|
q1.push(stem);
|
|
|
|
while(!q1.empty()) {
|
|
Gate* g = q1.front();
|
|
q1.pop();
|
|
used1[g] = false;
|
|
|
|
for(Gate* suc : g->suc_stems) {
|
|
if(!used2[suc]) {
|
|
used2[suc] = true;
|
|
q2.push(suc);
|
|
}
|
|
}
|
|
|
|
for(Gate* out : g->fan_outs) {
|
|
if(out->stem) {
|
|
Gate* stem = out;
|
|
bool new_stem_satisfied = (stem->recal_value() == stem->value);
|
|
if(new_stem_satisfied && !stem->stem_satisfied){
|
|
stem->stem_satisfied = true;
|
|
stem_total_cost -= stem->stem_weight;
|
|
stem_total_cnt += 1;
|
|
}
|
|
|
|
if(!new_stem_satisfied && stem->stem_satisfied){
|
|
stem->stem_satisfied = false;
|
|
stem_total_cost += stem->stem_weight;
|
|
stem_total_cnt -= 1;
|
|
}
|
|
continue;
|
|
}
|
|
int new_value = out->recal_value();
|
|
if(new_value == out->value) continue;
|
|
out->value = new_value;
|
|
if(!used1[out]) {
|
|
used1[out] = true;
|
|
q1.push(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
while(!q2.empty()) {
|
|
Gate *g = q2.front();
|
|
q2.pop();
|
|
|
|
used2[g] = false;
|
|
|
|
for(Gate* in : g->fan_ins) {
|
|
|
|
bool update = false;
|
|
|
|
bool fd[2];
|
|
in->recal_fault(fd);
|
|
|
|
if(fd[0] != in->fault_detected[0]) {
|
|
update = true;
|
|
if(in->fault_detected[0]) {
|
|
fault_total_weight += in->fault_weight[0];
|
|
fault_total_cnt += 1;
|
|
} else {
|
|
fault_total_weight -= in->fault_weight[9];
|
|
fault_total_cnt -= 1;
|
|
}
|
|
in->fault_detected[0] = fd[0];
|
|
}
|
|
|
|
if(fd[1] != in->fault_detected[1]) {
|
|
update = true;
|
|
if(in->fault_detected[1]) {
|
|
fault_total_weight += in->fault_weight[1];
|
|
fault_total_cnt += 1;
|
|
} else {
|
|
fault_total_weight -= in->fault_weight[1];
|
|
fault_total_cnt -= 1;
|
|
}
|
|
in->fault_detected[1] = fd[1];
|
|
}
|
|
|
|
in->propagate = (in->fault_detected[0] || in->fault_detected[1]);
|
|
|
|
int fpl[2];
|
|
in->recal_propagate_len(fpl);
|
|
|
|
if(fpl[0] != in->fault_propagate_length[0] || fpl[1] != in->fault_propagate_length[1]) {
|
|
update = true;
|
|
fault_propagate_score += in->fault_weight[0] * (fpl[0] - in->fault_propagate_length[0]);
|
|
fault_propagate_score += in->fault_weight[1] * (fpl[1] - in->fault_propagate_length[1]);
|
|
|
|
in->fault_propagate_length[0] = fpl[0];
|
|
in->fault_propagate_length[1] = fpl[1];
|
|
}
|
|
|
|
if(!used2[in]) {
|
|
used2[in] = true;
|
|
q2.push(in);
|
|
}
|
|
}
|
|
}
|
|
} |