-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsimplexEmbedding.py
More file actions
197 lines (152 loc) · 6.56 KB
/
simplexEmbedding.py
File metadata and controls
197 lines (152 loc) · 6.56 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
from scipy.linalg import lu
from scipy.sparse import csr_matrix
import numpy as np
import cvxpy as cp
from math_tools import rref, FindStateConeFacets, FindEffectConeFacets
def DefineAccessibleGPTFragment(statesOrEffects):
"""
Constructs the accessible Generalized Probabilistic Theory (GPT) fragment from a given set of states or effects.
Uses the Reduced Row Echelon Form (RREF) of the matrix of states/effects to construct the inclusion map (RREF without the kernel)
and projection (pseudo inverse of the inclusion), and the set of states/effects represented in the accessible fragment.
Args:
statesOrEffects (np.ndarray): A numpy array representing states or effects. Should be a 2D array.
shape = (gpt fragment dimension, number of states or effects)
Returns:
tuple: A tuple containing:
- inclusionMap (np.ndarray): The inclusion map matrix derived from the Reduced Row Echelon Form (RREF).
shape = (GPT fragment dimension, accessible fragment dimension)
- projectionMap (np.ndarray): The projection map matrix, which is the pseudo-inverse of the inclusion map.
shape = (accessible fragment dimension, GPT fragment dimension)
- accessibleFragment (np.ndarray): The accessible fragment, computed as the projection of statesOrEffects.
shape = (accessible fragment dimension, number of states or effects)
"""
REF = rref(statesOrEffects.T)
P, L, U = lu(statesOrEffects)
r = len(np.unique(csr_matrix(U).indptr)) - 1
inclusionMap = REF[:r, :].T
projectionMap = np.linalg.pinv(inclusionMap.T@inclusionMap)@inclusionMap.T
return inclusionMap, projectionMap, projectionMap @ statesOrEffects
def SimplicialConeEmbedding(H_S, H_E, accessibleFragmentBornRule, depolarizingMap):
"""
Solves Linear Program 2 from the paper by testing whether a simplicial cone embedding exists
given the GPT's state and effect cone facets, the bilinear form giving the Born rule in
the accessible fragment, and its depolarizing map.
Args:
H_S (np.ndarray): A numpy array representing the state cone facets.
shape = (number of state cone facets, dimension of states in the GPT accessible fragment)
H_E (np.ndarray): A numpy array representing the effect cone facets.
shape = (dimension of effects in the GPT accessible fragment, number of effect cone facets)
accessibleFragmentBornRule (np.ndarray): The bilinear form giving the Born rule in the accessible fragment.
shape = (dimension of states in the GPT accessible fragment, dimension of effects in the GPT accessible fragment)
depolarizingMap (np.ndarray): The depolarizing map, typically the outer product of accessible fragment unit and MMS.
shape = (dimension of effects in the GPT accessible fragment, dimension of states in the GPT accessible fragment)
Returns:
tuple: A tuple containing:
- robustness (float): The minimum amount of noise such that the depolarizing map causes a simplicial cone embedding to exist.
- sigma (np.ndarray): The sigma matrix obtained from the optimization problem.
"""
robustness, sigma = cp.Variable(nonneg=True), cp.Variable(
shape=(H_E.shape[1], H_S.shape[0]), nonneg=True
)
problem = cp.Problem(
cp.Minimize(robustness),
[
robustness * depolarizingMap
+ (1 - robustness) * accessibleFragmentBornRule
- H_E @ sigma @ H_S
== 0
],
)
problem.solve()
return robustness.value, sigma.value
def SimplexEmbedding(states, effects, unit, mms, debug=False):
"""
Constructs a noncontextual ontological model for the (possibly depolarized) GPT fragment.
Tests whether a simplex embedding exists given the GPT's states, effects, unit, and maximally mixed state.
Args:
states (np.ndarray): A numpy array of states.
effects (np.ndarray): A numpy array of effects.
unit (np.ndarray): The unit effect.
mms (np.ndarray): The maximally mixed state.
debug (bool, optional): Flag to print debug information. Default is False.
Returns:
tuple: A tuple containing:
- robustness (float): The robustness value.
- ResponseFunction (np.ndarray): The response function matrix.
- EpistemicStates (np.ndarray): The epistemic states matrix.
"""
inclusion_S, projection_S, accessibleFragmentStates = DefineAccessibleGPTFragment(
states
)
inclusion_E, projection_E, accessibleFragmentEffects = DefineAccessibleGPTFragment(
effects
)
accessibleFragmentUnit = projection_E @ unit
# MMS: Maximally mixed state
accessibleFragmentMMS = projection_S @ mms
H_S = FindStateConeFacets(accessibleFragmentStates)
H_E = FindEffectConeFacets(accessibleFragmentEffects)
# Bilinear form giving the Born rule in the accessible fragment:
accessibleFragmentBornRule = inclusion_E.T @ inclusion_S
depolarizingMap = np.outer(accessibleFragmentUnit, accessibleFragmentMMS)
robustness, sigma = SimplicialConeEmbedding(
H_S, H_E, accessibleFragmentBornRule, depolarizingMap
)
# Trivial factorization of the matrix sigma:
alpha = H_S
beta = H_E @ sigma
tau_S = np.array(
[
alpha[i, :] * (accessibleFragmentUnit @ beta[:, i])
for i in range(alpha.shape[0])
if not np.isclose((accessibleFragmentUnit @ beta[:, i]), 0)
]
)
tau_E = np.array(
[
beta[:, i] / (accessibleFragmentUnit @ beta[:, i])
for i in range(beta.shape[1])
if not np.isclose((accessibleFragmentUnit @ beta[:, i]), 0)
]
).T
ResponseFunction = tau_E.T @ inclusion_E.T @ effects
EpistemicStates = tau_S @ inclusion_S.T @ states
if debug:
print(
f"""
{inclusion_S.shape = },
{inclusion_E.shape = },
{H_S.shape = }
{H_E.shape = },
{accessibleFragmentBornRule.shape = },
{effects.shape = },
{inclusion_E.shape = },
{tau_E.shape = },
{tau_S.shape = },
{inclusion_S.shape = },
{states.shape = },
{robustness = },
{ResponseFunction.shape = },
{EpistemicStates.shape = },
Tau_E =
{tau_E},
Tau_S =
{tau_S},
effects =
{effects},
states =
{states},
Inc_E =
{inclusion_E},
Inc_S =
{inclusion_S},
{ResponseFunction},
{EpistemicStates},
"""
)
return robustness, ResponseFunction, EpistemicStates
if __name__ == "__main__":
from examples import example1
np.set_printoptions(precision=2, suppress=True)
states, effects, unit, mms = example1()
SimplexEmbedding(states, effects, unit, mms, debug=True)