Skip to content

Commit af446e6

Browse files
author
Simon Klix
committed
work in progress
1 parent a30b810 commit af446e6

File tree

10 files changed

+361
-17
lines changed

10 files changed

+361
-17
lines changed

plugins/machine_learning/include/machine_learning/features/gate_feature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace hal
2929
virtual Result<std::vector<FEATURE_TYPE>> calculate_feature(Context& ctx, const Gate* g) const = 0;
3030
virtual std::string to_string() const = 0;
3131

32-
Result<std::vector<std::vector<FEATURE_TYPE>>> calculate_feature(Context& ctx, const std::vector<Gate*>& gates) const override;
32+
virtual Result<std::vector<std::vector<FEATURE_TYPE>>> calculate_feature(Context& ctx, const std::vector<Gate*>& gates) const override;
3333
};
3434

3535
class GateFeatureBulk : public GateFeature

plugins/machine_learning/include/machine_learning/features/gate_pair_feature.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ namespace hal
2020
{
2121
public:
2222
virtual Result<std::vector<FEATURE_TYPE>> calculate_feature(Context& ctx, const Gate* g_a, const Gate* g_b) const = 0;
23-
virtual std::string to_string() const = 0;
23+
virtual Result<std::vector<std::vector<FEATURE_TYPE>>> calculate_features(Context& ctx, const std::vector<std::pair<Gate*, Gate*>>& gate_pairs) const;
24+
virtual std::string to_string() const = 0;
2425
};
2526

2627
class LogicalDistance : public GatePairFeature

plugins/machine_learning/scripts/hal_testing/test_gate_pair_feature_generation_speed.py

Lines changed: 159 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
import sys, os
3+
import pathlib
4+
5+
user_name = os.getlogin()
6+
7+
# some necessary configuration:
8+
if user_name == "simon":
9+
base_path = "/home/simon/projects/hal/"
10+
if user_name == "simon.klix":
11+
base_path = "/mnt/scratch/simon.klix/tools/hal/"
12+
else:
13+
print("add base paths for user {} before executing...".format(user_name))
14+
exit()
15+
16+
sys.path.append(base_path + "build/lib/") #this is where your hal python lib is located
17+
os.environ["HAL_BASE_PATH"] = base_path + "build" # hal base path
18+
19+
import hal_py
20+
import random
21+
import time
22+
23+
#initialize HAL
24+
hal_py.plugin_manager.load_all_plugins()
25+
26+
from hal_plugins import machine_learning
27+
28+
netlist_path = "/home/nfs0/simon.klix/projects/benchmarks/netlists_preprocessed/yosys/NangateOpenCellLibrary/synthetic/arithmetic/synth_0/netlist_1559bb70c68caf4c_7403e6d54ad10560/netlist_1559bb70c68caf4c_7403e6d54ad10560.hal"
29+
gate_lib_path = base_path + "/plugins/gate_libraries/definitions/NangateOpenCellLibrary.hgl"
30+
31+
netlist = hal_py.NetlistFactory.load_netlist(netlist_path, gate_lib_path)
32+
33+
34+
seq_gates = netlist.get_gates(lambda g : g.type.has_property(hal_py.ff))
35+
nl_seq_abstr = hal_py.NetlistAbstraction.create(netlist, seq_gates, False)
36+
37+
res = nl_seq_abstr.get_successors(seq_gates[0])
38+
if not res:
39+
quit()
40+
41+
nl_seq_abstr_dec = hal_py.NetlistAbstractionDecorator(nl_seq_abstr)
42+
43+
to_test = list()
44+
for i in range(10):
45+
ri = random.randint(0, len(seq_gates) - 1)
46+
g = seq_gates[ri]
47+
to_test.append(g)
48+
49+
50+
ep_filter = lambda _ep, d : d <= 2
51+
52+
# TEST cached
53+
start_cached = time.time()
54+
cached_results = nl_seq_abstr_dec.get_next_matching_gates(to_test, lambda g : True, hal_py.PinDirection.output, True, True, ep_filter, ep_filter)
55+
end_cached = time.time()
56+
57+
# TEST single
58+
original_results = list()
59+
start_original = time.time()
60+
for g in to_test:
61+
res = nl_seq_abstr_dec.get_next_matching_gates(g, lambda g : True, hal_py.PinDirection.output, True, True, ep_filter, ep_filter)
62+
original_results.append(res)
63+
end_original = time.time()
64+
65+
print(cached_results == original_results)
66+
print(end_cached - start_cached)
67+
print(end_original - start_original)
68+
69+
hal_py.plugin_manager.unload_all_plugins()

plugins/machine_learning/src/features/gate_feature_single.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ namespace hal
270270
{
271271
// Preallocate the feature vectors
272272
std::vector<std::vector<FEATURE_TYPE>> feature_vecs(gates.size());
273-
std::vector<Result<std::monostate>> thread_results(ctx.num_threads, ERR("uninitialized"));
273+
274+
const u32 used_threads = std::min(u32(gates.size()), ctx.num_threads);
275+
276+
std::vector<Result<std::monostate>> thread_results(used_threads, ERR("uninitialized"));
274277

275278
// Worker function for each thread
276279
auto thread_func = [&](u32 start, u32 end, u32 thread_index) {
@@ -292,8 +295,8 @@ namespace hal
292295

293296
// Launch threads to process gates in parallel
294297
std::vector<std::thread> threads;
295-
u32 chunk_size = (gates.size() + ctx.num_threads - 1) / ctx.num_threads;
296-
for (u32 t = 0; t < ctx.num_threads; ++t)
298+
u32 chunk_size = (gates.size() + used_threads - 1) / used_threads;
299+
for (u32 t = 0; t < used_threads; ++t)
297300
{
298301
u32 start = t * chunk_size;
299302
u32 end = std::min(start + chunk_size, u32(gates.size()));
@@ -309,8 +312,9 @@ namespace hal
309312
}
310313

311314
// Check whether a thread encountered an error
312-
for (const auto& res : thread_results)
315+
for (u32 idx = 0; idx < threads.size(); idx++)
313316
{
317+
const auto& res = thread_results.at(idx);
314318
if (res.is_error())
315319
{
316320
return ERR_APPEND(res.get_error(), "Encountered error when building feature vectors");

plugins/machine_learning/src/features/gate_pair_feature.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@ namespace hal
1515
{
1616
namespace gate_pair_feature
1717
{
18+
Result<std::vector<std::vector<FEATURE_TYPE>>> GatePairFeature::calculate_features(Context& ctx, const std::vector<std::pair<Gate*, Gate*>>& gate_pairs) const
19+
{
20+
std::vector<std::vector<FEATURE_TYPE>> results;
21+
for (const auto& [g_a, g_b] : gate_pairs)
22+
{
23+
auto res = calculate_feature(ctx, g_a, g_b);
24+
if (res.is_error())
25+
{
26+
return ERR_APPEND(res.get_error(), "cannot calculate features for all pairs");
27+
}
28+
29+
results.push_back(res.get());
30+
}
31+
32+
return OK(results);
33+
}
34+
1835
Result<std::vector<FEATURE_TYPE>> LogicalDistance::calculate_feature(Context& ctx, const Gate* g_a, const Gate* g_b) const
1936
{
2037
if (g_a == g_b)
@@ -550,7 +567,10 @@ namespace hal
550567
{
551568
// Preallocate the feature vectors
552569
std::vector<std::vector<FEATURE_TYPE>> feature_vecs(gate_pairs.size());
553-
std::vector<Result<std::monostate>> thread_results(ctx.num_threads, ERR("uninitialized"));
570+
571+
const u32 used_threads = std::min(u32(gate_pairs.size()), ctx.num_threads);
572+
573+
std::vector<Result<std::monostate>> thread_results(used_threads, ERR("uninitialized"));
554574

555575
#ifdef PROGRESS_BAR
556576
const auto msg = "Calculated gate pair features for " + std::to_string(gate_pairs.size()) + "/" + std::to_string(gate_pairs.size()) + " pairs";
@@ -591,8 +611,8 @@ namespace hal
591611

592612
// Launch threads to process gate_pairs in parallel
593613
std::vector<std::thread> threads;
594-
u32 chunk_size = (gate_pairs.size() + ctx.num_threads - 1) / ctx.num_threads;
595-
for (u32 t = 0; t < ctx.num_threads; ++t)
614+
u32 chunk_size = (gate_pairs.size() + used_threads - 1) / used_threads;
615+
for (u32 t = 0; t < used_threads; ++t)
596616
{
597617
u32 start = t * chunk_size;
598618
u32 end = std::min(start + chunk_size, static_cast<u32>(gate_pairs.size()));
@@ -608,8 +628,9 @@ namespace hal
608628
}
609629

610630
// Check whether a thread encountered an error
611-
for (const auto& res : thread_results)
631+
for (u32 idx = 0; idx < threads.size(); idx++)
612632
{
633+
const auto& res = thread_results.at(idx);
613634
if (res.is_error())
614635
{
615636
return ERR_APPEND(res.get_error(), "Encountered error when building feature vectors");

plugins/machine_learning/src/types.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace hal
2121
{
2222
if (!g->has_data("preprocessing_information", "multi_bit_indexed_identifiers"))
2323
{
24-
log_error("machine_learning", "unable to find indexed identifiers for gate with ID {}", g->get_id());
24+
log_error("machine_learning", "unable to find indexed identifiers for gate with {} ID {}", g->get_name(), g->get_id());
2525
continue;
2626
}
2727

src/netlist/decorators/netlist_abstraction_decorator.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ namespace hal
3939
// gather all successors
4040
for (Endpoint* ep_out : gate->get_fan_out_endpoints())
4141
{
42+
// TODO remove debug print
43+
// std::cout << ep_out->get_pin()->get_name() << std::endl;
44+
4245
new_abstraction->m_successors.insert({ep_out, {}});
4346
const auto successors = nl_trav_dec.get_next_matching_endpoints(
4447
ep_out,
@@ -120,6 +123,9 @@ namespace hal
120123
}
121124
}
122125

126+
// TODO remove debug print
127+
// std::cout << new_abstraction->m_successors.size() << std::endl;
128+
123129
return OK(std::move(new_abstraction));
124130
}
125131

@@ -207,7 +213,7 @@ namespace hal
207213
std::vector<Endpoint*> successors;
208214
for (auto* ep : gate->get_fan_out_endpoints())
209215
{
210-
const auto new_successors = get_predecessors(ep);
216+
const auto new_successors = get_successors(ep);
211217
if (new_successors.is_error())
212218
{
213219
return ERR_APPEND(new_successors.get_error(), "failed to get successors of gate " + gate->get_name() + " with ID " + std::to_string(gate->get_id()) + " in netlist abstraction");
@@ -247,10 +253,8 @@ namespace hal
247253
}
248254
}
249255

250-
// std::sort(successors.begin(), successors.end());
251-
// successors.erase(std::unique(successors.begin(), successors.end()), successors.end());
252-
253-
successors = utils::to_vector(utils::to_set(successors));
256+
std::sort(successors.begin(), successors.end());
257+
successors.erase(std::unique(successors.begin(), successors.end()), successors.end());
254258

255259
return OK(successors);
256260
}

src/python_bindings/bindings/netlist_abstraction_decorator.cpp

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace hal
2929
auto res = NetlistAbstraction::create(netlist, gates, include_all_netlist_gates, exit_endpoint_filter, entry_endpoint_filter);
3030
if (res.is_ok())
3131
{
32-
return res.get();
32+
return std::shared_ptr<NetlistAbstraction>(res.get());
3333
}
3434
else
3535
{
@@ -525,6 +525,90 @@ namespace hal
525525
:rtype: set[hal_py.Gate] or None
526526
)");
527527

528+
py_netlist_abstraction_decorator.def(
529+
"get_next_matching_gates",
530+
[](const NetlistAbstractionDecorator& self,
531+
const std::vector<Endpoint*>& endpoints,
532+
const std::function<bool(const Gate*)>& target_gate_filter,
533+
const PinDirection& direction,
534+
bool directed,
535+
bool continue_on_match,
536+
const std::function<bool(const Endpoint*, const u32)>& exit_endpoint_filter,
537+
const std::function<bool(const Endpoint*, const u32)>& entry_endpoint_filter) -> std::optional<std::vector<std::set<Gate*>>> {
538+
auto res = self.get_next_matching_gates(endpoints, target_gate_filter, direction, directed, continue_on_match, exit_endpoint_filter, entry_endpoint_filter);
539+
if (res.is_ok())
540+
{
541+
return res.get();
542+
}
543+
else
544+
{
545+
log_error("python_context", "error in get_next_matching_gates:{}", res.get_error().get());
546+
return std::nullopt;
547+
}
548+
},
549+
py::arg("endpoints"),
550+
py::arg("target_gate_filter"),
551+
py::arg("direction"),
552+
py::arg("directed") = true,
553+
py::arg("continue_on_match") = false,
554+
py::arg("exit_endpoint_filter") = nullptr,
555+
py::arg("entry_endpoint_filter") = nullptr,
556+
R"(
557+
Starting from the given endpoint, traverse the netlist abstraction and return the successor/predecessor gates that satisfy the `target_gate_filter`.
558+
559+
:param list[hal_py.Endpoint] endpoints: The starting endpoints.
560+
:param callable target_gate_filter: A filter function for the target gates.
561+
:param hal_py.PinDirection direction: The direction to search (`PinDirection.input` or `PinDirection.output`).
562+
:param bool directed: Whether to use a directed graph representation. Defaults to `True`.
563+
:param bool continue_on_match: Whether to continue traversal even after finding a match. Defaults to `False`.
564+
:param callable exit_endpoint_filter: A filter function to stop traversal on a fan-in/out endpoint. Defaults to `None`.
565+
:param callable entry_endpoint_filter: A filter function to stop traversal on successor/predecessor endpoints. Defaults to `None`.
566+
:returns: A list of sets of gates matching the filter, or `None` on error.
567+
:rtype: list[set[hal_py.Gate]] or None
568+
)");
569+
570+
py_netlist_abstraction_decorator.def(
571+
"get_next_matching_gates",
572+
[](const NetlistAbstractionDecorator& self,
573+
const std::vector<Gate*>& gates,
574+
const std::function<bool(const Gate*)>& target_gate_filter,
575+
const PinDirection& direction,
576+
bool directed,
577+
bool continue_on_match,
578+
const std::function<bool(const Endpoint*, const u32)>& exit_endpoint_filter,
579+
const std::function<bool(const Endpoint*, const u32)>& entry_endpoint_filter) -> std::optional<std::vector<std::set<Gate*>>> {
580+
auto res = self.get_next_matching_gates(gates, target_gate_filter, direction, directed, continue_on_match, exit_endpoint_filter, entry_endpoint_filter);
581+
if (res.is_ok())
582+
{
583+
return res.get();
584+
}
585+
else
586+
{
587+
log_error("python_context", "error in get_next_matching_gates:{}", res.get_error().get());
588+
return std::nullopt;
589+
}
590+
},
591+
py::arg("gates"),
592+
py::arg("target_gate_filter"),
593+
py::arg("direction"),
594+
py::arg("directed") = true,
595+
py::arg("continue_on_match") = false,
596+
py::arg("exit_endpoint_filter") = nullptr,
597+
py::arg("entry_endpoint_filter") = nullptr,
598+
R"(
599+
Starting from the given gate, traverse the netlist abstraction and return the successor/predecessor gates that satisfy the `target_gate_filter`.
600+
601+
:param list[hal_py.Gate] gates: The starting gates.
602+
:param callable target_gate_filter: A filter function for the target gates.
603+
:param hal_py.PinDirection direction: The direction to search (`PinDirection.input` or `PinDirection.output`).
604+
:param bool directed: Whether to use a directed graph representation. Defaults to `True`.
605+
:param bool continue_on_match: Whether to continue traversal even after finding a match. Defaults to `False`.
606+
:param callable exit_endpoint_filter: A filter function to stop traversal on a fan-in/out endpoint. Defaults to `None`.
607+
:param callable entry_endpoint_filter: A filter function to stop traversal on successor/predecessor endpoints. Defaults to `None`.
608+
:returns: A list of sets of gates matching the filter, or `None` on error.
609+
:rtype: list[set[hal_py.Gate]] or None
610+
)");
611+
528612
// Bind the first overloaded get_next_matching_gates_until method
529613
py_netlist_abstraction_decorator.def(
530614
"get_next_matching_gates_until",

src/python_bindings/python_bindings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ namespace hal
7777

7878
netlist_traversal_decorator_init(m);
7979

80+
netlist_abstraction_decorator_init(m);
81+
8082
log_init(m);
8183

8284
#ifndef PYBIND11_MODULE

0 commit comments

Comments
 (0)