hchevva commited on
Commit
09d07c6
·
verified ·
1 Parent(s): da5cb2e

Upload eda_view.py

Browse files
Files changed (1) hide show
  1. quread/eda_view.py +194 -0
quread/eda_view.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import Any, Dict, List, Tuple
5
+
6
+
7
+ _FLOAT_RE = r"[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?"
8
+
9
+ _SYN_RE = {
10
+ "risk": re.compile(rf"^set\s+quread_q(\d+)_risk\s+({_FLOAT_RE})\s*$"),
11
+ "tier": re.compile(r"^set\s+quread_q(\d+)_tier\s+([A-Za-z_]+)\s*$"),
12
+ "timing_derate": re.compile(rf"^set\s+quread_q(\d+)_timing_derate\s+({_FLOAT_RE})\s*$"),
13
+ "guardband_mv": re.compile(rf"^set\s+quread_q(\d+)_guardband_mv\s+({_FLOAT_RE})\s*$"),
14
+ "row": re.compile(r"^set\s+quread_q(\d+)_row\s+(-?\d+)\s*$"),
15
+ "col": re.compile(r"^set\s+quread_q(\d+)_col\s+(-?\d+)\s*$"),
16
+ "comment_route": re.compile(r"^#\s*q(\d+):.*\broute=([A-Za-z_]+)\b.*$"),
17
+ }
18
+
19
+ _CAD_ROW_RE = re.compile(
20
+ rf'^qureadRiskRows\s*=\s*cons\(list\("q(\d+)"\s+({_FLOAT_RE})\s+"([^"]+)"\s+({_FLOAT_RE})\s+({_FLOAT_RE})\s+(-?\d+)\s+(-?\d+)\s+"([^"]+)"\)\s+qureadRiskRows\)\s*$'
21
+ )
22
+
23
+
24
+ def _default_row(q: int) -> Dict[str, Any]:
25
+ return {
26
+ "qubit": int(q),
27
+ "tier": "UNKNOWN",
28
+ "composite_risk": 0.0,
29
+ "timing_derate": 1.0,
30
+ "guardband_mv": 0.0,
31
+ "route_priority": "UNKNOWN",
32
+ "layout_row": None,
33
+ "layout_col": None,
34
+ }
35
+
36
+
37
+ def _finalize_rows(rows_by_q: Dict[int, Dict[str, Any]]) -> List[Dict[str, Any]]:
38
+ rows: List[Dict[str, Any]] = []
39
+ for q in sorted(rows_by_q.keys()):
40
+ row = dict(rows_by_q[q])
41
+ rr = row.get("layout_row")
42
+ cc = row.get("layout_col")
43
+ if isinstance(rr, int) and rr < 0:
44
+ row["layout_row"] = None
45
+ if isinstance(cc, int) and cc < 0:
46
+ row["layout_col"] = None
47
+ rows.append(row)
48
+ rows.sort(key=lambda r: float(r.get("composite_risk", 0.0)), reverse=True)
49
+ return rows
50
+
51
+
52
+ def detect_eda_format(text: str) -> str:
53
+ raw = str(text or "")
54
+ syn_hits = raw.count("set quread_q")
55
+ cad_hits = raw.count('qureadRiskRows = cons(list("q')
56
+ if syn_hits == 0 and cad_hits == 0:
57
+ return "unknown"
58
+ if syn_hits >= cad_hits:
59
+ return "synopsys_tcl"
60
+ return "cadence_skill"
61
+
62
+
63
+ def parse_synopsys_tcl(text: str) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
64
+ rows_by_q: Dict[int, Dict[str, Any]] = {}
65
+ parsed = 0
66
+
67
+ for raw_line in str(text or "").splitlines():
68
+ line = raw_line.strip()
69
+ if not line:
70
+ continue
71
+
72
+ m = _SYN_RE["risk"].match(line)
73
+ if m:
74
+ q = int(m.group(1))
75
+ rows_by_q.setdefault(q, _default_row(q))["composite_risk"] = float(m.group(2))
76
+ parsed += 1
77
+ continue
78
+
79
+ m = _SYN_RE["tier"].match(line)
80
+ if m:
81
+ q = int(m.group(1))
82
+ rows_by_q.setdefault(q, _default_row(q))["tier"] = str(m.group(2)).upper()
83
+ parsed += 1
84
+ continue
85
+
86
+ m = _SYN_RE["timing_derate"].match(line)
87
+ if m:
88
+ q = int(m.group(1))
89
+ rows_by_q.setdefault(q, _default_row(q))["timing_derate"] = float(m.group(2))
90
+ parsed += 1
91
+ continue
92
+
93
+ m = _SYN_RE["guardband_mv"].match(line)
94
+ if m:
95
+ q = int(m.group(1))
96
+ rows_by_q.setdefault(q, _default_row(q))["guardband_mv"] = float(m.group(2))
97
+ parsed += 1
98
+ continue
99
+
100
+ m = _SYN_RE["row"].match(line)
101
+ if m:
102
+ q = int(m.group(1))
103
+ rows_by_q.setdefault(q, _default_row(q))["layout_row"] = int(m.group(2))
104
+ parsed += 1
105
+ continue
106
+
107
+ m = _SYN_RE["col"].match(line)
108
+ if m:
109
+ q = int(m.group(1))
110
+ rows_by_q.setdefault(q, _default_row(q))["layout_col"] = int(m.group(2))
111
+ parsed += 1
112
+ continue
113
+
114
+ m = _SYN_RE["comment_route"].match(line)
115
+ if m:
116
+ q = int(m.group(1))
117
+ rows_by_q.setdefault(q, _default_row(q))["route_priority"] = str(m.group(2)).upper()
118
+ parsed += 1
119
+ continue
120
+
121
+ rows = _finalize_rows(rows_by_q)
122
+ meta = {
123
+ "format": "synopsys_tcl",
124
+ "parsed_rows": len(rows),
125
+ "matched_fields": int(parsed),
126
+ }
127
+ return rows, meta
128
+
129
+
130
+ def parse_cadence_skill(text: str) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
131
+ rows_by_q: Dict[int, Dict[str, Any]] = {}
132
+ matched_rows = 0
133
+ for raw_line in str(text or "").splitlines():
134
+ line = raw_line.strip()
135
+ if not line:
136
+ continue
137
+ m = _CAD_ROW_RE.match(line)
138
+ if not m:
139
+ continue
140
+ q = int(m.group(1))
141
+ row = rows_by_q.setdefault(q, _default_row(q))
142
+ row["qubit"] = q
143
+ row["composite_risk"] = float(m.group(2))
144
+ row["tier"] = str(m.group(3)).upper()
145
+ row["timing_derate"] = float(m.group(4))
146
+ row["guardband_mv"] = float(m.group(5))
147
+ row["layout_row"] = int(m.group(6))
148
+ row["layout_col"] = int(m.group(7))
149
+ row["route_priority"] = str(m.group(8)).upper()
150
+ matched_rows += 1
151
+
152
+ rows = _finalize_rows(rows_by_q)
153
+ meta = {
154
+ "format": "cadence_skill",
155
+ "parsed_rows": len(rows),
156
+ "matched_rows": int(matched_rows),
157
+ }
158
+ return rows, meta
159
+
160
+
161
+ def parse_eda_text(text: str, format_hint: str = "auto") -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
162
+ hint = str(format_hint or "auto").strip().lower()
163
+ if hint == "auto":
164
+ fmt = detect_eda_format(text)
165
+ if fmt == "synopsys_tcl":
166
+ rows, meta = parse_synopsys_tcl(text)
167
+ if rows:
168
+ return rows, meta
169
+ if fmt == "cadence_skill":
170
+ rows, meta = parse_cadence_skill(text)
171
+ if rows:
172
+ return rows, meta
173
+ # fallback trial, then pick richer parse
174
+ syn_rows, syn_meta = parse_synopsys_tcl(text)
175
+ cad_rows, cad_meta = parse_cadence_skill(text)
176
+ if len(syn_rows) >= len(cad_rows) and syn_rows:
177
+ return syn_rows, syn_meta
178
+ if cad_rows:
179
+ return cad_rows, cad_meta
180
+ raise ValueError("No recognizable EDA reliability rows found in input.")
181
+
182
+ if hint in ("synopsys", "synopsys_tcl", "tcl"):
183
+ rows, meta = parse_synopsys_tcl(text)
184
+ if not rows:
185
+ raise ValueError("No Synopsys TCL risk rows found in input.")
186
+ return rows, meta
187
+
188
+ if hint in ("cadence", "cadence_skill", "skill", "il"):
189
+ rows, meta = parse_cadence_skill(text)
190
+ if not rows:
191
+ raise ValueError("No Cadence SKILL risk rows found in input.")
192
+ return rows, meta
193
+
194
+ raise ValueError(f"Unsupported format hint: {format_hint}")