pyqrack-cuda 1.40.2__tar.gz → 1.41.1__tar.gz
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.
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/Makefile +1 -1
- {pyqrack_cuda-1.40.2/pyqrack_cuda.egg-info → pyqrack_cuda-1.41.1}/PKG-INFO +1 -1
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/__init__.py +1 -0
- pyqrack_cuda-1.41.1/pyqrack/qrack_neuron_torch_layer.py +121 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack_cuda.egg-info/SOURCES.txt +1 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/setup.py +1 -1
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/LICENSE +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/README.md +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyproject.toml +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.40.2 → pyqrack_cuda-1.41.1}/setup.cfg +0 -0
@@ -18,7 +18,7 @@ help:
|
|
18
18
|
build-deps:
|
19
19
|
ifneq ($(OS),Windows_NT)
|
20
20
|
ifeq ($(QRACK_PRESENT),)
|
21
|
-
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout
|
21
|
+
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout e68917fdcd2d2ca0da0fabe5e8aea7da5602cfae; cd ..
|
22
22
|
endif
|
23
23
|
mkdir -p qrack/build
|
24
24
|
ifeq ($(UNAME_S),Linux)
|
@@ -6,6 +6,7 @@
|
|
6
6
|
from .qrack_system import QrackSystem, Qrack
|
7
7
|
from .qrack_simulator import QrackSimulator
|
8
8
|
from .qrack_neuron import QrackNeuron
|
9
|
+
from .qrack_neuron_torch_layer import QrackNeuronTorchLayer
|
9
10
|
from .qrack_circuit import QrackCircuit
|
10
11
|
from .pauli import Pauli
|
11
12
|
from .neuron_activation_fn import NeuronActivationFn
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Initial draft by Elara (OpenAI custom GPT)
|
2
|
+
# Refined and architecturally clarified by Dan Strano
|
3
|
+
|
4
|
+
_IS_TORCH_AVAILABLE = True
|
5
|
+
try:
|
6
|
+
import torch
|
7
|
+
import torch.nn as nn
|
8
|
+
from torch.autograd import Function
|
9
|
+
except ImportError:
|
10
|
+
_IS_TORCH_AVAILABLE = False
|
11
|
+
|
12
|
+
from .qrack_simulator import QrackSimulator
|
13
|
+
from .qrack_neuron import QrackNeuron
|
14
|
+
from .neuron_activation_fn import NeuronActivationFn
|
15
|
+
|
16
|
+
from itertools import chain, combinations
|
17
|
+
|
18
|
+
|
19
|
+
# From https://stackoverflow.com/questions/1482308/how-to-get-all-subsets-of-a-set-powerset#answer-1482316
|
20
|
+
def powerset(iterable):
|
21
|
+
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3,) (1,2,3)"
|
22
|
+
s = list(iterable)
|
23
|
+
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
|
24
|
+
|
25
|
+
|
26
|
+
class QrackTorchNeuron(nn.Module):
|
27
|
+
def __init__(self, neuron: QrackNeuron) -> None:
|
28
|
+
super().__init__()
|
29
|
+
self.neuron = neuron
|
30
|
+
|
31
|
+
def forward(self, x):
|
32
|
+
neuron = self.neuron
|
33
|
+
neuron.predict(True, False)
|
34
|
+
|
35
|
+
return neuron.simulator.prob(neuron.target)
|
36
|
+
|
37
|
+
|
38
|
+
class QrackNeuronFunction(Function if _IS_TORCH_AVAILABLE else object):
|
39
|
+
@staticmethod
|
40
|
+
def forward(ctx, neuron: object):
|
41
|
+
# Save for backward
|
42
|
+
ctx.neuron = neuron
|
43
|
+
|
44
|
+
init_prob = neuron.simulator.prob(neuron.target)
|
45
|
+
neuron.predict(True, False)
|
46
|
+
final_prob = neuron.simulator.prob(neuron.target)
|
47
|
+
ctx.delta = final_prob - init_prob
|
48
|
+
|
49
|
+
return torch.tensor([ctx.delta], dtype=torch.float32) if _IS_TORCH_AVAILABLE else ctx.delta
|
50
|
+
|
51
|
+
@staticmethod
|
52
|
+
def backward(ctx, grad_output):
|
53
|
+
neuron = ctx.neuron
|
54
|
+
|
55
|
+
pre_unpredict = neuron.simulator.prob(neuron.output_id)
|
56
|
+
neuron.unpredict()
|
57
|
+
post_unpredict = neuron.simulator.prob(neuron.output_id)
|
58
|
+
reverse_delta = pre_unpredict - post_unpredict
|
59
|
+
|
60
|
+
grad = reverse_delta - ctx.delta
|
61
|
+
|
62
|
+
return torch.tensor([grad], dtype=torch.float32) if _IS_TORCH_AVAILABLE else grad
|
63
|
+
|
64
|
+
|
65
|
+
class QrackNeuronTorchLayer(nn.Module if _IS_TORCH_AVAILABLE else object):
|
66
|
+
def __init__(self, simulator: object, input_indices: list[int], output_size: int, parameters: list[float] = None,
|
67
|
+
activation: int = int(NeuronActivationFn.Generalized_Logistic)):
|
68
|
+
super(QrackNeuronTorchLayer, self).__init__()
|
69
|
+
self.simulator = simulator
|
70
|
+
self.input_indices = input_indices
|
71
|
+
self.output_size = output_size
|
72
|
+
self.activation = NeuronActivationFn(activation)
|
73
|
+
self.fn = QrackNeuronFunction.apply if _IS_TORCH_AVAILABLE else lambda x: QrackNeuronFunction.forward(object(), x)
|
74
|
+
|
75
|
+
# Create neurons from all powerset input combinations, projecting to coherent output qubits
|
76
|
+
self.neurons = nn.ModuleList([
|
77
|
+
QrackTorchNeuron(QrackNeuron(simulator, list(input_subset), len(input_indices) + output_id, activation))
|
78
|
+
for input_subset in powerset(input_indices)
|
79
|
+
for output_id in range(output_size)
|
80
|
+
])
|
81
|
+
|
82
|
+
# Set Qrack's internal parameters:
|
83
|
+
param_count = 0
|
84
|
+
for neuron_wrapper in self.neurons:
|
85
|
+
neuron = neuron_wrapper.neuron
|
86
|
+
p_count = 1 << len(neuron.controls)
|
87
|
+
neuron.set_angles(parameters[param_count:(param_count+p_count+1)] if parameters else ([0.0] * p_count))
|
88
|
+
param_count += p_count
|
89
|
+
|
90
|
+
self.weights = nn.ParameterList()
|
91
|
+
for pid in range(param_count):
|
92
|
+
self.weights.append(nn.Parameter(torch.tensor(parameters[pid] if parameters else 0.0)))
|
93
|
+
|
94
|
+
def forward(self, _):
|
95
|
+
# Assume quantum outputs should overwrite the simulator state
|
96
|
+
for output_id in range(self.output_size):
|
97
|
+
if self.simulator.m(len(self.input_indices) + output_id):
|
98
|
+
self.simulator.x(output_id)
|
99
|
+
self.simulator.h(output_id)
|
100
|
+
|
101
|
+
# Set Qrack's internal parameters:
|
102
|
+
param_count = 0
|
103
|
+
for neuron_wrapper in self.neurons:
|
104
|
+
neuron = neuron_wrapper.neuron
|
105
|
+
p_count = 1 << len(neuron.controls)
|
106
|
+
angles = [w.item() for w in self.weights[param_count:(param_count+p_count)]]
|
107
|
+
neuron.set_angles(angles)
|
108
|
+
param_count += p_count
|
109
|
+
|
110
|
+
# Assume quantum inputs already loaded into simulator state
|
111
|
+
for neuron_wrapper in self.neurons:
|
112
|
+
self.fn(neuron_wrapper.neuron)
|
113
|
+
|
114
|
+
# These are classical views over quantum state; simulator still maintains full coherence
|
115
|
+
outputs = [
|
116
|
+
self.simulator.prob(len(self.input_indices) + output_id)
|
117
|
+
for output_id in range(self.output_size)
|
118
|
+
]
|
119
|
+
|
120
|
+
return torch.tensor(outputs, dtype=torch.float32)
|
121
|
+
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|