From 268b2b2c802c567147ea805a45c9a4f4ce6cb3c3 Mon Sep 17 00:00:00 2001 From: YuhangQ Date: Wed, 10 May 2023 21:42:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=95=B4=E6=B5=81=E7=A8=8B=E8=B7=91?= =?UTF-8?q?=E9=80=9A=EF=BC=8C=E4=BD=86=E6=95=88=E6=9E=9C=E5=BE=88=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- atpg | Bin 83489 -> 102241 bytes src/checker.cpp | 37 +++++++--- src/circuit.cpp | 36 ++++++++++ src/circuit.h | 24 ++++++- src/gate.cpp | 25 +++++++ src/ls.cpp | 188 +++++++++++++++++++++++++++--------------------- src/main.cpp | 7 +- src/options.h | 5 ++ src/parser.cpp | 4 +- src/score.cpp | 22 +++++- 10 files changed, 244 insertions(+), 104 deletions(-) diff --git a/atpg b/atpg index 41737baaa15bea94af07430af5b358fc1e197e69..77fcaa4ccdc06573d04ba22363ee0780516c7aec 100755 GIT binary patch delta 24763 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 diff --git a/src/checker.cpp b/src/checker.cpp index 4e4fdd9..670d6e4 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -12,25 +12,40 @@ int Circuit::check_circuit() { for(Gate* g : gates) { - // assert(g->fault_detected[0] == g->cal_fault_detected(0)); - // assert(g->fault_detected[1] == g->cal_fault_detected(1)); - // assert(g->fault_propagated_len[0] == g->fault_propagated_len[0]); - // assert(g->fault_propagated_len[1] == g->fault_propagated_len[1]); - assert(g->value_satisfied == ( g->cal_value() == g->value )); assert(g->fault_detected_satisfied[0] == ( g->cal_fault_detected(0) == g->fault_detected[0] )); assert(g->fault_detected_satisfied[1] == ( g->cal_fault_detected(1) == g->fault_detected[1] )); assert(g->fault_propagated_satisfied[0] == ( g->cal_propagate_len(0) == g->fault_propagated_len[0])); - - - // if(g->fault_propagated_satisfied[1] != ( g->cal_propagate_len(1) == g->fault_propagated_len[1])) { - // printf("pl: %s\n", g->name.c_str()); - // print_gates(); - // } assert(g->fault_propagated_satisfied[1] == ( g->cal_propagate_len(1) == g->fault_propagated_len[1])); + + if(g->value_satisfied) { + assert(value_satisfied_vars.count(g)); + assert(!value_unsatisfied_vars.count(g)); + } else { + assert(value_unsatisfied_vars.count(g)); + assert(!value_satisfied_vars.count(g)); + } + + if(g->fault_detected_satisfied[0] && g->fault_detected_satisfied[1]) { + assert(detected_satisfied_vars.count(g)); + assert(!detected_unsatisfied_vars.count(g)); + } else { + assert(detected_unsatisfied_vars.count(g)); + assert(!detected_satisfied_vars.count(g)); + } + + if(g->fault_propagated_satisfied[0] && g->fault_propagated_satisfied[1]) { + assert(propagated_satisfied_vars.count(g)); + assert(!propagated_unsatisfied_vars.count(g)); + } else { + assert(propagated_unsatisfied_vars.count(g)); + assert(!propagated_satisfied_vars.count(g)); + } + + if(!g->value_satisfied) sum_value_unsatisfied_cost += g->value_unsatisfied_cost; if(g->fault_detected[0]) sum_fault_detected_weight += g->fault_detected_weight[0]; diff --git a/src/circuit.cpp b/src/circuit.cpp index ac466fe..e90a47f 100644 --- a/src/circuit.cpp +++ b/src/circuit.cpp @@ -109,6 +109,42 @@ void Circuit::init_reigons() { std::sort(g->reigon.begin(), g->reigon.end()); g->reigon.erase(unique(g->reigon.begin(), g->reigon.end()), g->reigon.end()); } + + std::unordered_set r_set; + + // score reigon + for(Gate* gate : gates) { + r_set.clear(); + + for(Gate* out : gate->fanouts) { + r_set.insert(out); + for(Gate* in : out->fanins) { + r_set.insert(in); + for(Gate *out : in->fanouts) { + r_set.insert(out); + for(Gate *in : out->fanins) { + r_set.insert(in); + } + } + } + } + + for(Gate* in : gate->fanins) { + r_set.insert(in); + for(Gate* out : in->fanouts) { + r_set.insert(out); + for(Gate* in : out->fanins) { + r_set.insert(in); + } + } + } + + r_set.erase(gate); + + for(Gate* g : r_set) { + gate->score_reigon.push_back(g); + } + } } // bool Circuit::is_valid_circuit() { diff --git a/src/circuit.h b/src/circuit.h index 72b618c..a5e702f 100644 --- a/src/circuit.h +++ b/src/circuit.h @@ -8,9 +8,14 @@ using ll = long long; + +class Circuit; + class Gate { public: + Gate(Circuit* C):C(C) {} + // gate basic info int id; @@ -24,6 +29,7 @@ public: std::vector fanouts; std::vector fanins; std::vector reigon; + std::vector score_reigon; // circuit-ls info int value_satisfied; @@ -40,6 +46,9 @@ public: int fault_detected_satisfied[2]; int fault_detected_unsatisfied_cost[2]; + + int good_var_index; + int unsatisfied_var_index; int CC; @@ -77,7 +86,7 @@ public: // score calculation function - int cal_score(int debug=0); + void cal_score(int debug=0); int cal_value_unsatisfied_cost(); @@ -88,6 +97,10 @@ public: int cal_score_fault_detected_weight(int sa); int cal_score_fault_detected_unsatisfied_cost(int sa); + + +private: + Circuit* C; }; class Fault { @@ -118,6 +131,15 @@ void parse_from_file(const char *filename); void print_gates(); // local search + +std::vector good_vars; +std::unordered_set value_unsatisfied_vars; +std::unordered_set value_satisfied_vars; +std::unordered_set propagated_unsatisfied_vars; +std::unordered_set propagated_satisfied_vars; +std::unordered_set detected_unsatisfied_vars; +std::unordered_set detected_satisfied_vars; + bool local_search(std::unordered_set &faults); void ls_init_circuit(std::unordered_set &faults); diff --git a/src/gate.cpp b/src/gate.cpp index b1a0326..655fe46 100644 --- a/src/gate.cpp +++ b/src/gate.cpp @@ -12,10 +12,35 @@ void Gate::update_gate_property() { void Gate::update_gate_statistics() { value_satisfied = ( cal_value() == value ); + if(value_satisfied) { + C->value_satisfied_vars.insert(this); + C->value_unsatisfied_vars.erase(this); + } else { + C->value_satisfied_vars.erase(this); + C->value_unsatisfied_vars.insert(this); + } + fault_detected_satisfied[0] = ( cal_fault_detected(0) == fault_detected[0] ); fault_detected_satisfied[1] = ( cal_fault_detected(1) == fault_detected[1] ); + + if(fault_detected_satisfied[0] && fault_detected_satisfied[1]) { + C->detected_satisfied_vars.insert(this); + C->detected_unsatisfied_vars.erase(this); + } else { + C->detected_unsatisfied_vars.insert(this); + C->detected_satisfied_vars.erase(this); + } + fault_propagated_satisfied[0] = ( cal_propagate_len(0) == fault_propagated_len[0] ); fault_propagated_satisfied[1] = ( cal_propagate_len(1) == fault_propagated_len[1] ); + + if(fault_propagated_satisfied[0] && fault_propagated_satisfied[1]) { + C->propagated_satisfied_vars.insert(this); + C->propagated_unsatisfied_vars.erase(this); + } else { + C->propagated_unsatisfied_vars.insert(this); + C->propagated_satisfied_vars.erase(this); + } } int Gate::cal_propagate_len(bool x) { diff --git a/src/ls.cpp b/src/ls.cpp index 76706ae..6c86f5c 100644 --- a/src/ls.cpp +++ b/src/ls.cpp @@ -16,22 +16,24 @@ bool Circuit::local_search(std::unordered_set &faults) { // print_gates(); printf("generate random circuit done!\n"); - - srand(19260817); - int T = 10000000; + + int iter = 0; while(T--) { - printf("%d\n", T); + iter++; + if(iter % 1000 == 0) { + printf("iter: %d\n", iter); + check_circuit(); + } - // print_gates(); + if(value_unsatisfied_vars.empty()) { + printf("Get Solution!\n"); + break; + } - // int score_1 = check_circuit(); - - int i = rand()%gates.size(); - Gate* flip_gate = gates[i]; - - int dert = flip_gate->score; + Gate* gate = ls_pick(); + ls_flip(gate); // printf("svuc: %d, sfpw: %d, sfpuc: %d, sfdw: %d, sfduc: %d <<<\n", // flip_gate->score_value_unsatisfied_cost, @@ -40,7 +42,7 @@ bool Circuit::local_search(std::unordered_set &faults) { // flip_gate->score_fault_detected_weight[0] + flip_gate->score_fault_detected_weight[1], // flip_gate->score_fault_detected_unsatisfied_cost[0] + flip_gate->score_fault_detected_unsatisfied_cost[1]); - ls_flip(flip_gate); + // int score_2 = check_circuit(); // printf("checking circuit: %d %d\n", score_2 - score_1, dert); @@ -49,15 +51,9 @@ bool Circuit::local_search(std::unordered_set &faults) { // printf("i: %s\n", flip_gate->name.c_str()); } - exit(0); - - //printf("local search!\n"); - - while(true) { - Gate* gate = ls_pick(); - if(gate == nullptr) { - break; - } + // execute simulation + for(Gate* g : rtopo_gates) { + g->update_gate_statistics(); } static int original_faults = -1; @@ -78,22 +74,85 @@ bool Circuit::local_search(std::unordered_set &faults) { printf("coverage: %.3f%%\tpattern: %d\tbefore: %d\tnow: %d\n", (double)(original_faults - faults.size()) / (original_faults) * 100, ++pattern, tmp.size(), faults.size()); + exit(0); + if(tmp.size() == faults.size()) return false; return true; } Gate* Circuit::ls_pick() { - return nullptr; + static int focus = 1; + + double SP = 0.1; + + if(rand() % 1000 <= 500 * SP) { + std::vector tmp; + for(Gate* g : value_unsatisfied_vars) { + tmp.push_back(g); + } + return tmp[rand()%tmp.size()]; + } + + if(good_vars.size()) { + return good_vars[rand()%good_vars.size()]; + } + + // printf("update weight\n"); + ls_update_weight(); + + std::vector tmp; + for(Gate* g : value_unsatisfied_vars) { + tmp.push_back(g); + } + + return tmp[rand()%tmp.size()]; +} + +void Circuit::ls_update_weight() { + + std::unordered_set gates_need_recal_score; + + for(Gate* g : value_unsatisfied_vars) { + g->value_unsatisfied_cost += 1; + for(Gate *in : g->fanins) { + gates_need_recal_score.insert(in); + } + for(Gate *out : g->fanouts) { + gates_need_recal_score.insert(out); + } + } + + for(Gate* g : detected_unsatisfied_vars) { + g->fault_detected_unsatisfied_cost[0] += g->level; + g->fault_detected_unsatisfied_cost[1] += g->level; + for(Gate* r : g->score_reigon) { + gates_need_recal_score.insert(r); + } + } + + for(Gate* g : propagated_unsatisfied_vars) { + g->fault_propagated_unsatisfied_cost[0] += g->level; + g->fault_propagated_unsatisfied_cost[1] += g->level; + for(Gate* r : g->score_reigon) { + gates_need_recal_score.insert(r); + } + } + + for(Gate *g : gates_need_recal_score) { + g->cal_score(); + } + + // check_circuit(); + } void Circuit::ls_flip(Gate* gate) { - printf("flip: %s\n", gate->name.c_str()); + // printf("flip: %s\n", gate->name.c_str()); gate->value ^= 1; gate->update_gate_property(); - gate->update_gate_statistics(); for(Gate* g : gate->fanouts) { @@ -107,76 +166,37 @@ void Circuit::ls_flip(Gate* gate) { // g->score = g->cal_score(); // } - gate->score = gate->cal_score(); + gate->cal_score(); - std::unordered_set t; - int cal_cnt = 0; - - for(Gate* g : gate->fanouts) { - // printf("cal2: %s\n", g->name.c_str()); - t.insert(g); - g->score = g->cal_score(); - cal_cnt++; - for(Gate* in : g->fanins) { - t.insert(in); - in->score = in->cal_score(); - cal_cnt++; - for(Gate *out : in->fanouts) { - t.insert(out); - out->score = out->cal_score(); - cal_cnt++; - for(Gate *in : out->fanins) { - t.insert(in); - in->score = in->cal_score(); - cal_cnt++; - } - } - } + for(Gate* g : gate->score_reigon) { + g->cal_score(); } - for(Gate* g : gate->fanins) { - t.insert(g); - g->score = g->cal_score(); - cal_cnt++; - for(Gate* out : g->fanouts) { - t.insert(out); - out->score = out->cal_score(); - cal_cnt++; - for(Gate* in : out->fanins) { - t.insert(in); - in->score = in->cal_score(); - cal_cnt++; - } - } - } + // printf("t: %d cal_cnt: %d r_set: %d\n", t.size(), cal_cnt, gate->score_reigon.size()); - printf("t: %d cal_cnt: %d\n", t.size(), cal_cnt); - - for(Gate* g : gates) { - if(g->score != g->cal_score(true) ){ - printf("bug3: %s\n", g->name.c_str()); - // print_gates(); - exit(0); - } - } + // for(Gate* g : gates) { + // if(g->score != g->cal_score(true) ){ + // printf("bug3: %s\n", g->name.c_str()); + // // print_gates(); + // exit(0); + // } + // } // exit(0); // printf("bug %s: cal_len:%d len:%d\n", gate->name.c_str(), gate->cal_propagate_len(1), gate->fault_propagated_len[1]); } -void Circuit::ls_update_weight() { - - -} - -void Circuit::ls_update(Gate* stem) { - - -} - void Circuit::ls_init_circuit(std::unordered_set &faults) { + good_vars.clear(); + value_unsatisfied_vars.clear(); + value_satisfied_vars.clear(); + propagated_unsatisfied_vars.clear(); + propagated_satisfied_vars.clear(); + detected_unsatisfied_vars.clear(); + detected_satisfied_vars.clear(); + // init value, weight and cost for(Gate* g : gates) { g->value = rand() % 2; @@ -185,6 +205,8 @@ void Circuit::ls_init_circuit(std::unordered_set &faults) { g->fault_propagated_unsatisfied_cost[0] = g->fault_propagated_unsatisfied_cost[1] = 1; g->fault_detected_weight[0] = g->fault_detected_weight[1] = 0; g->fault_detected_unsatisfied_cost[0] = g->fault_detected_unsatisfied_cost[1] = 1; + g->good_var_index = -1; + g->unsatisfied_var_index = -1; } for(Fault* f : faults) { @@ -202,7 +224,7 @@ void Circuit::ls_init_circuit(std::unordered_set &faults) { // cal score for(Gate* g : gates) { - g->score = g->cal_score(); + g->cal_score(); printf("%d ", g->score); } diff --git a/src/main.cpp b/src/main.cpp index 0186fb6..b09cc1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,12 +42,9 @@ int main(int args, char* argv[]) { bool is_valid = circuit->check_circuit(); printf("checking valid circuit ..."); printf(" result: %d.\n", is_valid); - if(!ls) break; - if(!is_valid) break; + // if(!ls) break; + // if(!is_valid) break; if(faults.size() == 0) break; - - //circuit->print_gates(); - //break; } //printf("[final] flip: %d, stem: %d, fault:%d\n", circuit->flip_total_weight, circuit->stem_total_weight, circuit->fault_total_weight); diff --git a/src/options.h b/src/options.h index 1996ed8..9a3748c 100644 --- a/src/options.h +++ b/src/options.h @@ -1,3 +1,8 @@ +#define DEBUG 1 + + + + const double SP = 0.01; const int STEM_INC = 0; diff --git a/src/parser.cpp b/src/parser.cpp index 6de1483..241d100 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -71,7 +71,7 @@ void Circuit::parse_from_file(const char *filename) { } } - Gate* gate = new Gate(); + Gate* gate = new Gate(this); gate->name = tokens[0]; gate->isPI = false; gate->isPO = false; @@ -108,7 +108,7 @@ void Circuit::parse_from_file(const char *filename) { } // input else if(tokens.size() == 4 && tokens[0] == "INPUT" && tokens[1] == "(" && tokens[3] == ")") { - Gate* gate = new Gate(); + Gate* gate = new Gate(this); gate->name = tokens[2]; gate->type = Gate::INPUT; gate->isPI = true; diff --git a/src/score.cpp b/src/score.cpp index c6389f3..28c1160 100644 --- a/src/score.cpp +++ b/src/score.cpp @@ -1,7 +1,7 @@ #include "circuit.h" -int Gate::cal_score(int debug) { +void Gate::cal_score(int debug) { value ^= 1; @@ -33,11 +33,29 @@ int Gate::cal_score(int debug) { value ^= 1; - return - score_value_unsatisfied_cost + score = - score_value_unsatisfied_cost + score_fault_propagated_weight[0] + score_fault_propagated_weight[1] - score_fault_propagated_unsatisfied_cost[0] - score_fault_propagated_unsatisfied_cost[1] + score_fault_detected_weight[0] + score_fault_detected_weight[1] - score_fault_detected_unsatisfied_cost[0] - score_fault_detected_unsatisfied_cost[1]; + + if(score > 0 && good_var_index == -1) { + good_var_index = C->good_vars.size(); + C->good_vars.push_back(this); + } + + if(score <= 0 && good_var_index != -1) { + C->good_vars[C->good_vars.size()-1]->good_var_index = good_var_index; + std::swap(C->good_vars[good_var_index], C->good_vars[C->good_vars.size()-1]); + C->good_vars.pop_back(); + good_var_index = -1; + } + + for(Gate* g : C->good_vars) { + assert(g->score > 0); + } + + return; } int Gate::cal_value_unsatisfied_cost() {