Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 44 additions & 15 deletions viz/to_json.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# viz/to_json.py
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -17,13 +18,20 @@
import re
import numpy as np

INT_RE = re.compile(r'-?\d+')

def parse_int_list(text):
"""Extract all integers from a string, tolerant to spaces/commas/brackets."""
return [int(x) for x in INT_RE.findall(text)]

def parse_implicit_list(line, prefix):
if not line.startswith(prefix):
raise ValueError(f"Expected line to start with '{prefix}', got: {line}")
list_part = line[len(prefix):].strip().rstrip(',')
if not list_part:
return []
return [int(x.strip()) for x in list_part.split(',') if x.strip()]
# Be tolerant: accept "1, 2, 3" or "1 2 3"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha "be tolerant" :))

return parse_int_list(list_part)

def parse_logfile(filepath):
detector_coords = {}
Expand All @@ -38,21 +46,37 @@ def parse_logfile(filepath):
line = lines[i].strip()

if not any(line.startswith(s) for s in ['Error', 'Detector', 'activated_errors', 'activated_detectors']):
continue
i += 1
continue

if line.startswith("Detector D"):
match = re.match(r'Detector D(\d+) coordinate \(([-\d.]+), ([-\d.]+), ([-\d.]+)\)', line)
# Example: "Detector D123 coordinate (1.0, 2.0, 3.0)"
match = re.match(
r'Detector D(\d+)\s+coordinate\s*\(\s*([-\d.]+)\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)',
line
)
if match:
idx = int(match.group(1))
coord = tuple(float(match.group(j)) for j in range(2, 5))
detector_coords[idx] = coord

elif line.startswith("Error{"):
match = re.search(r'Symptom\{([^\}]+)\}', line)
if match:
dets = match.group(1).split()
det_indices = [int(d[1:]) for d in dets if d.startswith('D')]
error_to_detectors.append(det_indices)
# New format: Error{..., symptom=Symptom{detectors=[75 89 93 100], observables=[...]}}
# Fallback: old format with "D###" tokens inside Symptom{...}
dets = []

m_detlist = re.search(r'detectors=\[([^\]]*)\]', line)
if m_detlist:
dets = parse_int_list(m_detlist.group(1))
else:
# Old fallback: scrape Symptom{...} and look for D###
m_sym = re.search(r'Symptom\{([^}]*)\}', line)
if m_sym:
tokens = m_sym.group(1).split()
dets = [int(t[1:]) for t in tokens if t.startswith('D') and t[1:].isdigit()]

# Store (even if empty—we keep the index alignment with errors)
error_to_detectors.append(dets)

elif line.startswith("activated_errors"):
try:
Expand All @@ -62,34 +86,39 @@ def parse_logfile(filepath):
activated_errors = parse_implicit_list(error_line, "activated_errors =")
activated_dets = parse_implicit_list(det_line, "activated_detectors =")

frame = {
frames.append({
"activated": activated_dets,
"activated_errors": activated_errors
}
frames.append(frame)
i += 1
})

# We consumed two lines in this block
i += 2
continue # skip the unconditional i+=1 below (already advanced)
except Exception as e:
print(f"\n⚠️ Error parsing frame at lines {i}-{i+1}: {e}")
print(f" {lines[i].strip()}")
print(f" {lines[i+1].strip() if i+1 < len(lines) else ''}")

i += 1

if not detector_coords:
raise RuntimeError("No detectors parsed!")

# Center detector coordinates
coords_array = np.array(list(detector_coords.values()))
mean_coord = coords_array.mean(axis=0)
for k in detector_coords:
detector_coords[k] = (np.array(detector_coords[k]) - mean_coord).tolist()

# Error coordinates as mean of their detectors (if known)
error_coords = {}
for i, det_list in enumerate(error_to_detectors):
for ei, det_list in enumerate(error_to_detectors):
try:
pts = np.array([detector_coords[d] for d in det_list if d in detector_coords])
if len(pts) > 0:
error_coords[i] = pts.mean(axis=0).tolist()
error_coords[ei] = pts.mean(axis=0).tolist()
except KeyError as e:
print(f"⚠️ Skipping error {i}: unknown detector {e}")
print(f"⚠️ Skipping error {ei}: unknown detector {e}")

error_to_detectors_dict = {str(i): dets for i, dets in enumerate(error_to_detectors)}

Expand Down
Loading