-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathport.py
More file actions
210 lines (169 loc) · 7.37 KB
/
Copy pathport.py
File metadata and controls
210 lines (169 loc) · 7.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import numpy as np
from typing import Type, Union, TypeVar, Callable, Dict, List, Set, Tuple, Any
from dataclasses import dataclass, field
from collections import defaultdict
from enum import Enum
from abc import ABC, abstractmethod
class ConnectionStrategy(ABC):
"""Base strategy for port connections in quantum circuits."""
@abstractmethod
def assign_global_index(
self,
source_port: "Port",
target_port: "Port",
port_count: int,
port_to_global: Dict["Port", int],
) -> int:
# Each port gets unique index; allocate width consecutive slots
source_port.global_index = port_count
port_to_global[source_port] = port_count
return port_count + source_port.width
@abstractmethod
def synthesize_connection_sparse(
self, source_idx: int, target_idx: int, J_global: Dict[int, Dict[int, float]]
) -> None:
"""Add connection weights to global J matrix during synthesis (sparse format)."""
pass
@abstractmethod
def synthesize_connection_dense(
self, source_idx: int, target_idx: int, J_global: np.ndarray
) -> None:
"""Add connection weights to global J matrix during synthesis (dense format)."""
pass
def synthesize_connection(
self,
source_idx: int,
target_idx: int,
J_global: Union[Dict[int, Dict[int, float]], np.ndarray],
format: str = "sparse",
) -> None:
"""Dispatch to appropriate synthesis method based on format."""
if format == "sparse":
self.synthesize_connection_sparse(source_idx, target_idx, J_global)
else:
self.synthesize_connection_dense(source_idx, target_idx, J_global)
class NoCopyConnection(ConnectionStrategy):
"""Direct connection between ports with shared global index."""
def assign_global_index(self, source_port, target_port, port_count, port_to_global):
source_port.global_index = port_count
target_port.global_index = port_count
port_to_global[source_port] = port_count
port_to_global[target_port] = port_count
return port_count + source_port.width
def synthesize_connection_sparse(
self, source_idx: int, target_idx: int, J_global: Dict[int, Dict[int, float]]
) -> None:
# No weights added for NO_COPY - they share a global index
pass
def synthesize_connection_dense(
self, source_idx: int, target_idx: int, J_global: np.ndarray
) -> None:
# No weights added for NO_COPY - they share a global index
pass
def synthesize_connection(self, source_idx, target_idx, J_global, format="sparse"):
return super().synthesize_connection(source_idx, target_idx, J_global, format)
class VanillaCopyConnection(ConnectionStrategy):
"""Standard copy connection with weight 1.0."""
def assign_global_index(self, source_port, target_port, port_count, port_to_global):
return super().assign_global_index(
source_port, target_port, port_count, port_to_global
)
def synthesize_connection_sparse(
self, source_idx: int, target_idx: int, J_global: Dict[int, Dict[int, float]]
) -> None:
J_global[source_idx][target_idx] = 1.0
J_global[target_idx][source_idx] = 1.0
def synthesize_connection_dense(
self, source_idx: int, target_idx: int, J_global: np.ndarray
) -> None:
J_global[source_idx, target_idx] = 1.0
J_global[target_idx, source_idx] = 1.0
def synthesize_connection(self, source_idx, target_idx, J_global, format="sparse"):
return super().synthesize_connection(source_idx, target_idx, J_global, format)
class WeightedCopyConnection(ConnectionStrategy):
"""Copy connection with customizable weight."""
def __init__(self, weight: float):
self.weight = weight
def assign_global_index(self, source_port, target_port, port_count, port_to_global):
return super().assign_global_index(
source_port, target_port, port_count, port_to_global
)
def synthesize_connection_sparse(
self, source_idx: int, target_idx: int, J_global: Dict[int, Dict[int, float]]
) -> None:
J_global[source_idx][target_idx] = self.weight
J_global[target_idx][source_idx] = self.weight
def synthesize_connection_dense(
self, source_idx: int, target_idx: int, J_global: np.ndarray
) -> None:
J_global[source_idx, target_idx] = self.weight
J_global[target_idx, source_idx] = self.weight
def synthesize_connection(self, source_idx, target_idx, J_global, format="sparse"):
return super().synthesize_connection(source_idx, target_idx, J_global, format)
@dataclass
class Port:
"""
Represents a port in a quantum circuit that can be connected to other ports.
The Port class handles connections between different components of quantum circuits,
managing both local and global indices for matrix operations.
Attributes:
name (str): Name identifier for the port
circuit (Any): Reference to the parent circuit
index (int): Local index within the parent circuit
global_index (int): Global index in the synthesized system
_connections (Dict): Connection information to other ports
Example:
>>> port1 = Port("input1")
>>> port2 = Port("output1")
>>> port1.connect(port2, ConnectionType.NO_COPY)
"""
name: str
circuit: Any = None
index: int = None
global_index: int = None
width: int = 1
_connections: Dict = field(default_factory=dict)
@property
def global_indices(self) -> List[int]:
"""Returns all global indices covered by this port (one per bit)."""
if self.global_index is None:
return []
return list(range(self.global_index, self.global_index + self.width))
def __hash__(self):
"""
Generates a hash based on the combination of circuit reference and port name.
Returns:
int: Hash value for the port
"""
return hash((id(self.circuit), self.name))
def __eq__(self, other):
"""
Compares two ports for equality based on circuit reference and name.
Args:
other (Port): Another port to compare with
Returns:
bool: True if ports are equal, False otherwise
"""
if not isinstance(other, Port):
return False
return id(self.circuit) == id(other.circuit) and self.name == other.name
def connect(self, other_port: "Port", strategy: ConnectionStrategy):
"""
Establishes a connection between this port and another port.
Args:
other_port (Port): Target port to connect to
strategy: Connection strategy defining the connection behavior
"""
if self.circuit is None or other_port.circuit is None:
raise ValueError("Both ports must be bound to circuits")
if self.index is None or other_port.index is None:
raise ValueError("Both ports must have assigned indices")
if self.width != other_port.width:
raise ValueError(
f"Cannot connect ports of different widths: {self.width} vs {other_port.width}"
)
if isinstance(strategy, type):
self._connection_strategy = strategy()
else:
self._connection_strategy = strategy
self._connected_port = other_port