najaeda 0.3.3__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. najaeda/__init__.py +20 -0
  2. najaeda/_version.py +16 -0
  3. najaeda/docs/.readthedocs.yaml +26 -0
  4. najaeda/docs/requirements.txt +7 -0
  5. najaeda/docs/source/api.rst +7 -0
  6. najaeda/docs/source/common_classes.rst +11 -0
  7. najaeda/docs/source/conf.py +57 -0
  8. najaeda/docs/source/equipotential.rst +15 -0
  9. najaeda/docs/source/examples.rst.in +66 -0
  10. najaeda/docs/source/index.rst +17 -0
  11. najaeda/docs/source/instance.rst +34 -0
  12. najaeda/docs/source/introduction.rst +68 -0
  13. najaeda/docs/source/net.rst +20 -0
  14. najaeda/docs/source/netlist_classes.rst +11 -0
  15. najaeda/docs/source/preprocessor.py +73 -0
  16. najaeda/docs/source/term.rst +20 -0
  17. najaeda/docs/source/visitors.rst +13 -0
  18. najaeda/instance_visitor.py +43 -0
  19. najaeda/naja.pyd +0 -0
  20. najaeda/naja_bne.dll +0 -0
  21. najaeda/naja_dnl.dll +0 -0
  22. najaeda/naja_metrics.dll +0 -0
  23. najaeda/naja_nl.dll +0 -0
  24. najaeda/naja_opt.dll +0 -0
  25. najaeda/naja_python.dll +0 -0
  26. najaeda/native/__init__.py +0 -0
  27. najaeda/native/stats.py +341 -0
  28. najaeda/net_visitor.py +53 -0
  29. najaeda/netlist.py +1990 -0
  30. najaeda/pandas_stats.py +32 -0
  31. najaeda/primitives/__init__.py +0 -0
  32. najaeda/primitives/utils.py +19 -0
  33. najaeda/primitives/xilinx.py +541 -0
  34. najaeda/primitives/yosys.py +288 -0
  35. najaeda/stats.py +410 -0
  36. najaeda-0.3.3.dist-info/DELVEWHEEL +2 -0
  37. najaeda-0.3.3.dist-info/METADATA +108 -0
  38. najaeda-0.3.3.dist-info/RECORD +44 -0
  39. najaeda-0.3.3.dist-info/WHEEL +5 -0
  40. najaeda-0.3.3.dist-info/licenses/AUTHORS +7 -0
  41. najaeda-0.3.3.dist-info/licenses/LICENSE +201 -0
  42. najaeda.libs/msvcp140.dll +0 -0
  43. najaeda.libs/tbb12.dll +0 -0
  44. najaeda.libs/tbbmalloc.dll +0 -0
@@ -0,0 +1,341 @@
1
+ # SPDX-FileCopyrightText: 2024 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ import os
7
+ from najaeda import naja
8
+
9
+
10
+ class DesignsStats:
11
+ def __init__(self):
12
+ self.blackboxes = dict()
13
+ self.hier_designs = dict()
14
+
15
+
16
+ class DesignStats:
17
+ def __init__(self):
18
+ self.name = ""
19
+ self.assigns = 0
20
+ self.flat_assigns = 0
21
+ self.basic_primitives = dict()
22
+ self.primitives = dict()
23
+ self.flat_basic_primitives = dict()
24
+ self.flat_primitives = dict()
25
+ self.blackboxes = dict()
26
+ self.flat_blackboxes = dict()
27
+ self.ins = dict()
28
+ self.flat_ins = dict()
29
+ self.terms = dict()
30
+ self.bit_terms = dict()
31
+ self.net_stats = dict()
32
+
33
+ def add_ins_stats(self, ins_stats):
34
+ self.flat_assigns += ins_stats.flat_assigns
35
+ for ins, nb in ins_stats.flat_ins.items():
36
+ self.flat_ins[ins] = self.flat_ins.get(ins, 0) + nb
37
+ for ins, nb in ins_stats.flat_blackboxes.items():
38
+ self.flat_blackboxes[ins] = self.flat_blackboxes.get(ins, 0) + nb
39
+ for primitive, nb in ins_stats.flat_primitives.items():
40
+ self.flat_primitives[primitive] = (
41
+ self.flat_primitives.get(primitive, 0) + nb
42
+ )
43
+ for primitive, nb in ins_stats.flat_basic_primitives.items():
44
+ self.flat_basic_primitives[primitive] = (
45
+ self.flat_basic_primitives.get(primitive, 0) + nb
46
+ )
47
+
48
+
49
+ def isBasicPrimitive(design):
50
+ return design.isConst0() or design.isConst1() or design.isBuf() or design.isInv()
51
+
52
+
53
+ def compute_design_stats(design, designs_stats):
54
+ if design in designs_stats.hier_designs:
55
+ return designs_stats.hier_designs.get(design)
56
+ design_stats = DesignStats()
57
+ design_stats.name = design.getName()
58
+ for ins in design.getInstances():
59
+ model = ins.getModel()
60
+ if model.isAssign():
61
+ design_stats.assigns += 1
62
+ design_stats.flat_assigns += 1
63
+ elif model.isPrimitive():
64
+ if isBasicPrimitive(model):
65
+ design_stats.basic_primitives[model] = (
66
+ design_stats.basic_primitives.get(model, 0) + 1
67
+ )
68
+ design_stats.flat_basic_primitives[model] = (
69
+ design_stats.flat_basic_primitives.get(model, 0) + 1
70
+ )
71
+ else:
72
+ design_stats.primitives[model] = (
73
+ design_stats.primitives.get(model, 0) + 1
74
+ )
75
+ design_stats.flat_primitives[model] = (
76
+ design_stats.flat_primitives.get(model, 0) + 1
77
+ )
78
+ elif model.isBlackBox():
79
+ design_stats.blackboxes[model] = design_stats.blackboxes.get(model, 0) + 1
80
+ design_stats.flat_blackboxes[model] = (
81
+ design_stats.flat_blackboxes.get(model, 0) + 1
82
+ )
83
+ if model not in designs_stats.blackboxes:
84
+ designs_stats.blackboxes[model] = dict()
85
+ compute_design_terms(model, designs_stats.blackboxes[model])
86
+ else:
87
+ if model in designs_stats.hier_designs:
88
+ model_stats = designs_stats.hier_designs[model]
89
+ else:
90
+ model_stats = compute_design_stats(model, designs_stats)
91
+ design_stats.ins[model] = design_stats.ins.get(model, 0) + 1
92
+ design_stats.flat_ins[model] = design_stats.flat_ins.get(model, 0) + 1
93
+ design_stats.add_ins_stats(model_stats)
94
+ compute_design_terms(design, design_stats)
95
+ compute_design_net_stats(design, design_stats)
96
+ designs_stats.hier_designs[design] = design_stats
97
+ return design_stats
98
+
99
+
100
+ def compute_design_terms(design, design_stats):
101
+ for term in design.getTerms():
102
+ if term.getDirection() == naja.SNLTerm.Direction.Input:
103
+ design_stats.terms["inputs"] = design_stats.terms.get("inputs", 0) + 1
104
+ bit_terms = sum(1 for _ in term.getBits())
105
+ design_stats.bit_terms["inputs"] = (
106
+ design_stats.bit_terms.get("inputs", 0) + bit_terms
107
+ )
108
+ elif term.getDirection() == naja.SNLTerm.Direction.Output:
109
+ design_stats.terms["outputs"] = design_stats.terms.get("outputs", 0) + 1
110
+ bit_terms = sum(1 for _ in term.getBits())
111
+ design_stats.bit_terms["outputs"] = (
112
+ design_stats.bit_terms.get("outputs", 0) + bit_terms
113
+ )
114
+ elif term.getDirection() == naja.SNLTerm.Direction.InOut:
115
+ design_stats.terms["inouts"] = design_stats.terms.get("inouts", 0) + 1
116
+ bit_terms = sum(1 for _ in term.getBits())
117
+ design_stats.bit_terms["inouts"] = (
118
+ design_stats.bit_terms.get("inouts", 0) + bit_terms
119
+ )
120
+ else:
121
+ design_stats.terms["unknowns"] = design_stats.terms.get("unknowns", 0) + 1
122
+ bit_terms = sum(1 for _ in term.getBits())
123
+ design_stats.bit_terms["unknowns"] = (
124
+ design_stats.bit_terms.get("unknowns", 0) + bit_terms
125
+ )
126
+
127
+
128
+ def compute_design_net_stats(design, design_stats):
129
+ for net in design.getBitNets():
130
+ if net.isConstant():
131
+ pass
132
+ nb_components = sum(1 for c in net.getComponents())
133
+ design_stats.net_stats[nb_components] = (
134
+ design_stats.net_stats.get(nb_components, 0) + 1
135
+ )
136
+ design_stats.net_stats = dict(sorted(design_stats.net_stats.items()))
137
+
138
+
139
+ def dump_instances(stats_file, title, instances):
140
+ if len(instances) == 0:
141
+ return
142
+ sorted_instances = sorted(instances.items(), key=lambda item: item[0].getName())
143
+ stats_file.write(title + " " + str(sum(j for i, j in sorted_instances)) + "\n")
144
+ line_char = 0
145
+ for instance in sorted_instances:
146
+ if line_char != 0:
147
+ stats_file.write(",")
148
+ line_char += 1
149
+ if line_char > 80:
150
+ stats_file.write("\n")
151
+ line_char = 0
152
+ elif line_char != 0:
153
+ stats_file.write(" ")
154
+ line_char += 1
155
+ instance_char = instance[0].getName() + ":" + str(instance[1])
156
+ line_char += len(instance_char)
157
+ stats_file.write(instance_char)
158
+ stats_file.write("\n\n")
159
+
160
+
161
+ def dump_blackboxes_stats(stats_file, design_stats):
162
+ if len(design_stats.blackboxes) > 0:
163
+ stats_file.write("*** BlackBoxes ***\n")
164
+ for bbox in design_stats.blackboxes.items():
165
+ design = bbox[0]
166
+ design_terms = bbox[1]
167
+ stats_file.write("*** " + design.getName() + " ***\n")
168
+ if len(design_terms) > 0:
169
+ stats_file.write("Terms: ")
170
+ first = True
171
+ for terms in design_terms.items():
172
+ if not first:
173
+ stats_file.write(", ")
174
+ else:
175
+ first = False
176
+ stats_file.write(terms[0] + ":" + str(terms[1]))
177
+ stats_file.write("\n")
178
+ stats_file.write("\n")
179
+
180
+
181
+ def dump_stats(design, stats_file, designs_stats, dumped_models):
182
+ if design.isPrimitive() or design.isBlackBox():
183
+ return
184
+ if design in dumped_models:
185
+ return
186
+ dumped_models.add(design)
187
+ stats_file.write("*** " + design.getName() + " ***\n")
188
+ design_stats = designs_stats.hier_designs.get(design)
189
+ if design_stats is None:
190
+ print("Cannot find " + str(design) + " in design_stats")
191
+ raise
192
+ if len(design_stats.terms) > 0:
193
+ stats_file.write("Terms: ")
194
+ first = True
195
+ for terms in design_stats.terms.items():
196
+ if not first:
197
+ stats_file.write(", ")
198
+ else:
199
+ first = False
200
+ stats_file.write(terms[0] + ":" + str(terms[1]))
201
+ stats_file.write("\n")
202
+
203
+ dump_instances(stats_file, "Instances:", design_stats.ins)
204
+ nb_primitives = sum(design_stats.basic_primitives.values()) + sum(
205
+ design_stats.primitives.values()
206
+ )
207
+ if nb_primitives > 1:
208
+ stats_file.write("Primitives: " + str(nb_primitives) + "\n")
209
+ dump_instances(stats_file, "Simple Primitives:", design_stats.basic_primitives)
210
+ dump_instances(stats_file, "Other Primitives:", design_stats.primitives)
211
+ dump_instances(stats_file, "Blackboxes:", design_stats.blackboxes)
212
+ if design_stats.assigns > 0:
213
+ stats_file.write("Assigns: " + str(design_stats.assigns) + "\n")
214
+ dump_instances(stats_file, "Flat Instances:", design_stats.flat_ins)
215
+ dump_instances(stats_file, "Flat Blackboxes:", design_stats.flat_blackboxes)
216
+ nb_primitives = sum(design_stats.flat_basic_primitives.values()) + sum(
217
+ design_stats.flat_primitives.values()
218
+ )
219
+ if nb_primitives > 1:
220
+ stats_file.write("Flat Primitives: " + str(nb_primitives) + "\n")
221
+ dump_instances(
222
+ stats_file, "Flat Simple Primitives:", design_stats.flat_basic_primitives
223
+ )
224
+ dump_instances(stats_file, "Flat Other Primitives:", design_stats.flat_primitives)
225
+ if design_stats.flat_assigns > 0:
226
+ stats_file.write("Flat Assigns: " + str(design_stats.flat_assigns) + "\n")
227
+ stats_file.write("\n")
228
+ for ins in design.getInstances():
229
+ model = ins.getModel()
230
+ dump_stats(model, stats_file, designs_stats, dumped_models)
231
+
232
+
233
+ def dump_pandas(designs_stats):
234
+ import pandas
235
+ import matplotlib.pyplot as plt
236
+
237
+ # create a figures directory erase the previous one
238
+ if os.path.exists("figures"):
239
+ import shutil
240
+
241
+ shutil.rmtree("figures")
242
+ os.makedirs("figures")
243
+
244
+ data = []
245
+ for design, design_stats in designs_stats.hier_designs.items():
246
+ data.append(
247
+ [
248
+ design.getName(),
249
+ sum(design_stats.terms.values()),
250
+ sum(design_stats.bit_terms.values()),
251
+ sum(design_stats.basic_primitives.values()),
252
+ sum(design_stats.primitives.values()),
253
+ sum(design_stats.blackboxes.values()),
254
+ sum(design_stats.ins.values()),
255
+ sum(design_stats.flat_ins.values()),
256
+ sum(design_stats.flat_blackboxes.values()),
257
+ sum(design_stats.flat_basic_primitives.values()),
258
+ sum(design_stats.flat_primitives.values()),
259
+ ]
260
+ )
261
+ df = pandas.DataFrame(
262
+ data,
263
+ columns=[
264
+ "Design",
265
+ "Terms",
266
+ "Bit Terms",
267
+ "Basic Primitives",
268
+ "Primitives",
269
+ "Blackboxes",
270
+ "Instances",
271
+ "Flat Instances",
272
+ "Flat Blackboxes",
273
+ "Flat Basic Primitives",
274
+ "Flat Primitives",
275
+ ],
276
+ )
277
+ df.to_csv("figures/designs_stats.csv", index=False)
278
+
279
+ net_series = pandas.Series(design_stats.net_stats)
280
+ nets_plot = net_series.plot(
281
+ kind="bar",
282
+ title="Number of nets with a given number of components for\n"
283
+ + design.getName(),
284
+ xlabel="number of components",
285
+ ylabel="number of nets",
286
+ )
287
+ nets_plot.set_yscale("log")
288
+ nets_plot.xaxis.set_major_locator(plt.MaxNLocator(100))
289
+ nets_figure = nets_plot.get_figure()
290
+ nets_figure.tight_layout()
291
+ nets_figure.savefig("figures/nets_" + design.getName() + ".png")
292
+
293
+ flat_primitives_series = pandas.Series(design_stats.flat_primitives)
294
+ primitives_plot = flat_primitives_series.plot(
295
+ kind="bar",
296
+ title="Number of primitives for\n" + design.getName(),
297
+ xlabel="primitive",
298
+ ylabel="number of flat instances",
299
+ )
300
+ primitives_plot.set_yscale("log")
301
+ primitives_figure = primitives_plot.get_figure()
302
+ primitives_figure.tight_layout()
303
+ primitives_figure.savefig("figures/flat_primitives_" + design.getName() + ".png")
304
+
305
+
306
+ def compute_and_dump_design_stats(design, stats_file, with_pandas=False):
307
+ designs_stats = DesignsStats()
308
+ compute_design_stats(design, designs_stats)
309
+ dumped_models = set()
310
+ dump_stats(design, stats_file, designs_stats, dumped_models)
311
+ dump_blackboxes_stats(stats_file, designs_stats)
312
+ if with_pandas:
313
+ dump_pandas(designs_stats)
314
+
315
+
316
+ def dump_constants(design, analyzed_models):
317
+ if design.isPrimitive():
318
+ return
319
+ if design in analyzed_models:
320
+ return
321
+ analyzed_models.add(design)
322
+ for bitnet in design.getBitNets():
323
+ if bitnet.isConstant():
324
+ logging.info(
325
+ "In design "
326
+ + design.getName()
327
+ + ", constant net "
328
+ + bitnet.getName()
329
+ + " of type "
330
+ + bitnet.getTypeAsString()
331
+ )
332
+ if all(False for _ in bitnet.getComponents()):
333
+ logging.info(" with zero connections\n")
334
+ else:
335
+ logging.info(" connected to:\n")
336
+ for component in bitnet.getComponents():
337
+ logging.info(str(component) + "\n")
338
+
339
+ for ins in design.getInstances():
340
+ model = ins.getModel()
341
+ dump_constants(model, analyzed_models)
najaeda/net_visitor.py ADDED
@@ -0,0 +1,53 @@
1
+ # SPDX-FileCopyrightText: 2024 The Naja authors
2
+ # <https://github.com/najaeda/naja/blob/main/AUTHORS>
3
+ #
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ # from typing import Callable
7
+ # from najaeda import netlist
8
+ #
9
+ #
10
+ # class VisitorConfig:
11
+ # def __init__(
12
+ # self,
13
+ # enter_condition: Callable[[netlist.Instance], bool] = lambda node: True,
14
+ # callback: Callable[..., None] = lambda node, *args, **kwargs: None,
15
+ # args: tuple = (),
16
+ # kwargs: dict = None,
17
+ # ):
18
+ # """
19
+ # :param enter_condition: A callable that takes a node (dict)
20
+ # and returns True if the visitor should enter.
21
+ # :param callback: A callable that takes a node (dict) and performs an operation on it.
22
+ # :param args: Positional arguments to pass to the callback.
23
+ # :param kwargs: Keyword arguments to pass to the callback.
24
+ # """
25
+ # self.enter_condition = enter_condition
26
+ # self.callback = callback
27
+ # self.args = args
28
+ # self.kwargs = kwargs or {}
29
+ #
30
+ #
31
+ # def visit(equipotential: netlist.Equipotential, config: VisitorConfig):
32
+ # """Recursively visits nodes in the netlist hierarchy.
33
+ #
34
+ # :param instance: The current node in the netlist instance hierarchy.
35
+ # :param config: VisitorConfig object defining conditions and callbacks.
36
+ # """
37
+ # # Execute the callback
38
+ # config.callback(equipotential, *config.args, **config.kwargs)
39
+ #
40
+ # # Check if we should proceed to children
41
+ # if config.enter_condition(equipotential):
42
+ # for component in equipotential.get .get_child_instances():
43
+ # visit(child, config)
44
+ #
45
+ # def visit(term: netlist.Term, config: VisitorConfig):
46
+ # config.callback(term, *config.args, **config.kwargs)
47
+ #
48
+ # #get the corresponding iterms
49
+ # instance = term.get_instance()
50
+ # if instance is not None:
51
+ # for iterm in instance.get_iterms():
52
+ # visit(iterm, config)
53
+ #