atpg-ls/ls.cpp
2023-03-13 05:44:49 +00:00

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);
}
}
}
}