MoMPy 0.0.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.
mompy-0.0.1/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
mompy-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.3
2
+ Name: MoMPy
3
+ Version: 0.0.1
4
+ Summary: Moment matrix generation package for SDP hierarchies
5
+ Project-URL: Homepage, https://github.com/pypa/sampleproject
6
+ Project-URL: Issues, https://github.com/pypa/sampleproject/issues
7
+ Author-email: Carles Roch i Carceller <chalswater@gmail.com>
8
+ License-File: LICENSE.md
9
+ Keywords: SDP hierarchy,moment matrix,semidefinite programming
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.8
14
+ Requires-Dist: numpy
15
+ Description-Content-Type: text/markdown
16
+
17
+ MoMPy: Moment matrix generation and managing package for SDP hierarchies.
18
+
19
+ This is a package to generate moment matrices for SDP hierarchies. The package contains the following relevant functions:
20
+
21
+ - MomentMatrix: generates the moment matrix with operational equivalences already taken into account (except normalisation).
22
+
23
+ - normalisation_contraints: takes into account normalisation constraints. This is to be called inside the SDP and added as a constraint!
24
+
25
+ More information in the code files.
mompy-0.0.1/README.md ADDED
@@ -0,0 +1,9 @@
1
+ MoMPy: Moment matrix generation and managing package for SDP hierarchies.
2
+
3
+ This is a package to generate moment matrices for SDP hierarchies. The package contains the following relevant functions:
4
+
5
+ - MomentMatrix: generates the moment matrix with operational equivalences already taken into account (except normalisation).
6
+
7
+ - normalisation_contraints: takes into account normalisation constraints. This is to be called inside the SDP and added as a constraint!
8
+
9
+ More information in the code files.
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "MoMPy"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Carles Roch i Carceller", email="chalswater@gmail.com" },
10
+ ]
11
+ description = "Moment matrix generation package for SDP hierarchies"
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ keywords = [
20
+ "semidefinite programming",
21
+ "moment matrix",
22
+ "SDP hierarchy"
23
+ ]
24
+ dependencies = ["NumPy"]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/pypa/sampleproject"
28
+ Issues = "https://github.com/pypa/sampleproject/issues"
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Jun 27 22:41:00 2024
5
+
6
+ @author: carles
7
+ """
8
+
9
+ import numpy as np
10
+
11
+ #------------------------------------------------------------------------------------------
12
+ #------------------------------------------------------------------------------------------
13
+
14
+ def Permute(v):
15
+ """ Cyclical permutation """
16
+ return [v[-1]] + v[:-1]
17
+
18
+ #------------------------------------------------------------------------------------------
19
+ #------------------------------------------------------------------------------------------
20
+
21
+ def Commute(v,index):
22
+ """ Commute v[index] in v """
23
+ store = v[index]
24
+
25
+ v_copy = [ii for ii in v]
26
+ v_copy.remove(store)
27
+
28
+ out = []
29
+ entered = False
30
+ for jj in range(len(v)):
31
+ if jj == index + 1:
32
+ out += [store]
33
+ entered = True
34
+ else:
35
+ if entered == True:
36
+ out += [v_copy[jj-1]]
37
+ else:
38
+ if jj < len(v_copy):
39
+ out += [v_copy[jj]]
40
+
41
+ if len(out) < len(v):
42
+ out = [store] + out
43
+
44
+ return out
45
+
46
+ #------------------------------------------------------------------------------------------
47
+ #------------------------------------------------------------------------------------------
48
+
49
+ def fmap(table,i):
50
+ ''' A funciton that maps a value on table[item][0] --> table[item][1] in the same row'''
51
+ found = False
52
+ for item in range(len(table)):
53
+ if i in table[item][0]: # For non-commuting variables, i is a vector!
54
+ found = True
55
+ item_saved = item
56
+
57
+ if found == True:
58
+ return table[item_saved][1]
59
+ else:
60
+ return 'ERROR: The value does not appear in the mapping rule'
61
+
62
+ #------------------------------------------------------------------------------------------
63
+ #------------------------------------------------------------------------------------------
64
+
65
+ def reverse_list(lista):
66
+ return[k for k in reversed(lista)]
67
+
68
+ #------------------------------------------------------------------------------------------
69
+ #------------------------------------------------------------------------------------------
70
+
71
+ def normalisation_contraints(element,list_identities_in):
72
+
73
+ """
74
+ Def:
75
+ List of elements which summed are equal to the last element in each list
76
+
77
+ Arguments:
78
+
79
+ element: list of elements that require normalisation
80
+
81
+ list_identities_in: lost of equivalences
82
+
83
+ """
84
+
85
+ # element: list of elements that require normalisation
86
+ # list_identities_in: list of exsisting equivalences
87
+
88
+ output_ct = []
89
+ already_counted = []
90
+
91
+ list_identities = list_identities_in[:]
92
+
93
+ for term in list_identities:
94
+ dd = 0
95
+ for pp in range(len(term[dd])):
96
+ yy = 0
97
+ string = []
98
+ if term[dd][pp] == element[yy]:
99
+ new_input = term[dd][:]
100
+ copy_without_element = new_input[:]
101
+ del copy_without_element[pp]
102
+ if len(copy_without_element) < 1:
103
+ copy_without_element += [0]
104
+ for hh in range(len(element)):
105
+ new_input[pp] = element[hh]
106
+ copy = new_input[:]
107
+ string += [copy]
108
+ string += [copy_without_element]
109
+
110
+ if len(string) > 1:
111
+ output_ct += [string]
112
+
113
+ """
114
+
115
+ Output:
116
+
117
+ list of indices which added are equal to the last one
118
+
119
+ """
120
+
121
+ return output_ct
122
+
123
+ #------------------------------------------------------------------------------------------
124
+ #------------------------------------------------------------------------------------------
125
+
126
+ def MomentMatrix(S_1,S_2,higher_order_elements,rank_1_projectors,orthogonal_projectors,commuting_elements,states):
127
+
128
+ """
129
+ Generator of SDP hierarchy Moment matrix
130
+
131
+ S_1:
132
+ list of first order elements (zero order not included)
133
+
134
+ S_2:
135
+ list of elements to generate second order terms (zero order not included)
136
+
137
+ higher_order_elements:
138
+ list of specific elements of higher orders
139
+
140
+ rank_1_projectors:
141
+ list of rank-1 projectors
142
+
143
+ orthogonal_projectors:
144
+ lists of orthogonal projectors
145
+
146
+ commuting_elements:
147
+ list of elements that commute with everything EXCEPT with the states
148
+
149
+ states:
150
+ delcare what are your states that don't commute with anything (only used for commutation constraints)
151
+ """
152
+
153
+ S = []
154
+ for v in S_1:
155
+ S += [[v]] # Add first order monomials
156
+
157
+ for k in S_2:
158
+ for h in S_2:
159
+ S += [[h,k]] # Compute second order monomials
160
+
161
+ S += higher_order_elements # Add additional higher order elements
162
+
163
+ Mexp = [] # Here we store the matrix for all explicit elements
164
+ complete_list_explicit = [] # Here we store all explicit elements in a list
165
+ for r in range(len(S)+1):
166
+ Mexp += [[]]
167
+ for c in range(len(S)+1):
168
+ if r == 0 and c > 0:
169
+ Mexp[r] += [reverse_list(S[c-1])]
170
+ elif c == 0 and r > 0:
171
+ Mexp[r] += [S[r-1]]
172
+ elif c == 0 and r == 0:
173
+ Mexp[r] += [[0]]
174
+ else:
175
+ Mexp[r] += [S[r-1]+reverse_list(S[c-1])]
176
+ if r >= c:
177
+ complete_list_explicit += [ Mexp[r][c] ]
178
+
179
+
180
+ # Detect the elemenets that are equal to zero by orthogonality rules
181
+ group_of_zeros = [] # Group of zeros
182
+ for r in range(len(S)+1):
183
+ for c in range(len(S)+1):
184
+
185
+ # Orthogonal projectors
186
+ if len(Mexp[r][c]) >= 2:
187
+ for ii in range(len(Mexp[r][c])):
188
+ for kk in range(len(orthogonal_projectors)):
189
+ if Mexp[r][c][ii] in orthogonal_projectors[kk] and Mexp[r][c][np.mod(ii+1,len(Mexp[r][c]))] in orthogonal_projectors[kk]:
190
+ if Mexp[r][c][ii] != Mexp[r][c][np.mod(ii+1,len(Mexp[r][c]))]:
191
+ new_vec = [Mexp[r][c][jj] for jj in range(len(Mexp[r][c]))]
192
+ if new_vec not in group_of_zeros: #if it is not in the list already, add it
193
+ group_of_zeros += [new_vec]
194
+ if Mexp[r][c] in complete_list_explicit:
195
+ complete_list_explicit.remove(Mexp[r][c]) # Remove element that was already taken into account
196
+
197
+ # Apply symmetry rules
198
+ id_elements = [] # list containing groups of identical elements
199
+ ss = 0
200
+ for element in complete_list_explicit:
201
+
202
+ print(f'\r Building Moment Matrix: {np.round(ss/(len(complete_list_explicit)),2)}%'+'\r',end=' ')
203
+ equivalences_vec = [] # vector of equivalent elements
204
+
205
+ missed_zero = False
206
+
207
+ # Identical elements by cyclic permutation in traces
208
+ new_vec = element[:]
209
+ for ii in range(len(element)+1):
210
+ if new_vec not in equivalences_vec: # if it is not in the list already, add it
211
+ equivalences_vec += [new_vec]
212
+ if new_vec in group_of_zeros:
213
+ missed_zero = True
214
+ new_vec = Permute(new_vec) # Permute members (monomials) of the element
215
+
216
+ # Identical elements by being rank-1 projectors (B^2 = B)
217
+ if len(element) >= 2:
218
+ for ii in range(len(element)):
219
+ if element[ii] in rank_1_projectors:
220
+ if element[ii] == element[np.mod(ii+1,len(element))]:
221
+ new_vec = [element[jj] for jj in range(len(element)) if jj != ii]
222
+ if new_vec not in equivalences_vec: #if it is not in the list already, add it
223
+ equivalences_vec += [new_vec]
224
+ if new_vec in group_of_zeros:
225
+ missed_zero = True
226
+
227
+ # Identical elements by commuting rules
228
+ # When you commute an element, you completely change the whole set of elements, and so one needs to re-check ciclicity and rank-1
229
+ new_vec = element[:]
230
+ new_lists = equivalences_vec
231
+ diff = len(commuting_elements) # if there are no commuting elements, we don't need to do this re-checking
232
+ already_counted = []
233
+ while diff > 0: # While we keep adding elements in "new_lists" we will do the following
234
+ len_ini = len(new_lists)
235
+ for term in new_lists:
236
+ if term not in already_counted:
237
+ already_counted += [term]
238
+ new_vec = term[:]
239
+ for hh in range(len(term)):
240
+ if term[hh] in commuting_elements: #if the element is in the list of commuting elements
241
+ for ii in range(len(new_vec)+1):
242
+ new_vec = Commute(new_vec,np.mod(hh+ii,len(new_vec))) # permute members (monomials) of the element
243
+ if new_vec not in new_lists:
244
+ new_lists += [new_vec]
245
+ if new_vec not in equivalences_vec:
246
+ equivalences_vec += [new_vec]
247
+ if new_vec in group_of_zeros:
248
+ missed_zero = True
249
+
250
+ new_vec = term[:]
251
+ for ii in range(len(new_vec)+1): # Include also the cyclic permutations of the new elements
252
+ if new_vec not in equivalences_vec: # if it is not in the list already, add it
253
+ equivalences_vec += [new_vec]
254
+ if new_vec in group_of_zeros:
255
+ missed_zero = True
256
+ new_vec = Permute(new_vec) # Permute members (monomials) of the element
257
+
258
+ new_vec = term[:]
259
+ if len(new_vec) >= 2:
260
+ for ii in range(len(new_vec)): # Also include all rank-1 element reductions that can happen
261
+ if new_vec[ii] in rank_1_projectors:
262
+ if new_vec[ii] == new_vec[np.mod(ii+1,len(new_vec))]:
263
+ new_vec_2 = [new_vec[jj] for jj in range(len(new_vec)) if jj != ii]
264
+ if new_vec_2 not in equivalences_vec: #if it is not in the list already, add it
265
+ equivalences_vec += [new_vec_2]
266
+ if new_vec_2 in group_of_zeros:
267
+ missed_zero = True
268
+
269
+ # Check if the new element is zero or not (and we did not count it initially)
270
+ new_vec = term[:]
271
+ if len(new_vec) >= 2:
272
+ for ii in range(len(new_vec)):
273
+ for kk in range(len(orthogonal_projectors)):
274
+ if new_vec[ii] in orthogonal_projectors[kk] and new_vec[np.mod(ii+1,len(new_vec))] in orthogonal_projectors[kk]:
275
+ if new_vec[ii] != new_vec[np.mod(ii+1,len(new_vec))]:
276
+ new_vec_2 = [new_vec[jj] for jj in range(len(new_vec))]
277
+ if new_vec_2 not in group_of_zeros: #if it is not in the list already, add it
278
+ group_of_zeros += [new_vec_2]
279
+ missed_zero = True
280
+
281
+ len_fin = len(new_lists)
282
+ diff = len_fin - len_ini
283
+
284
+ if missed_zero == True: # if we detected that an element is a zero, then all is zero
285
+ for el in equivalences_vec:
286
+ if el not in group_of_zeros:
287
+ group_of_zeros += [el]
288
+ else:
289
+ # Check if any of the elements in the equivalences is already accounted for
290
+ found_one = False
291
+ saved_id = []
292
+ for el in equivalences_vec:
293
+ for ids in id_elements:
294
+ if el in ids:
295
+ found_one = True
296
+ saved_id += [ids]
297
+ id_elements.remove(ids)
298
+
299
+ # If so, merge all elements in one without repetitions:
300
+ if found_one == True:
301
+ for tt in range(len(saved_id)):
302
+ for iss in saved_id[tt]:
303
+ if iss not in equivalences_vec:
304
+ equivalences_vec += [iss]
305
+
306
+ # Add the equivalences in a bigger list of identities
307
+ id_elements += [equivalences_vec]
308
+ ss += 1
309
+
310
+ # Add the zeros
311
+ id_elements += [group_of_zeros]
312
+
313
+ Moment_Matrix = np.zeros((len(Mexp),len(Mexp)),dtype=int) # This is the output Gama matrix with numbers in each element
314
+ map_table = [] # Table to map explicit elements to the number group of identities
315
+ already_counted = []
316
+ already_counted_2 = []
317
+
318
+ ll = 0
319
+ for l in range(int(len(id_elements))):
320
+ if id_elements[l] not in already_counted_2:
321
+ map_table += [[id_elements[l],ll]]
322
+ already_counted_2 += [id_elements[l]]
323
+ already_counted += id_elements[l]
324
+ ll += 1
325
+
326
+ for j in range(len(Mexp)):
327
+ for i in range(j,len(Mexp)):
328
+ Moment_Matrix[i][j] = fmap(map_table,Mexp[i][j])
329
+ Moment_Matrix[j][i] = Moment_Matrix[i][j]
330
+
331
+ list_of_eq_indices = np.unique(Moment_Matrix) # Unique elements in M
332
+
333
+ """
334
+ Outputs:
335
+
336
+ Moment_Matrix:
337
+ Moment Matrix with indices of equivalent elements
338
+
339
+ map_table:
340
+ table used to map explicit elements to their equivalence index in Moment_Matrix
341
+ the last element in map_table are all the zeros emerging from orthogonality
342
+
343
+ S:
344
+ complete list of all elements
345
+
346
+ list_of_eq_indices:
347
+ list of all equivalence indices in Moment_Matrix
348
+
349
+ Mexp:
350
+ Moment matrix with all explicit elements
351
+
352
+ """
353
+
354
+ return Moment_Matrix,map_table,S,list_of_eq_indices,Mexp
355
+
356
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Jun 27 22:05:20 2024
5
+
6
+ @author: carles
7
+ """
8
+
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Jun 27 23:02:24 2024
5
+
6
+ @author: carles roch i carceller
7
+ """
8
+
9
+ nX = 2 # number of state preparations
10
+ nY = 1 # number of measurement settings
11
+ nB = 2 # number of measurement outcomes
12
+ nK = 2 # number of photon states (for avg photon numbe nK => n_trunc + 1
13
+
14
+ #---------------------------------------------------------------------#
15
+ # Collect all monomials #
16
+ #---------------------------------------------------------------------#
17
+
18
+ # Track operators in the tracial matrix
19
+ w_R = [] # Prepared quantum state
20
+ w_B = [] # Measurement
21
+ w_P = [] # Observable (photon number projector)
22
+
23
+ S_1 = [] # List of first order elements
24
+ cc = 1
25
+
26
+ for x in range(nX):
27
+ S_1 += [cc]
28
+ w_R += [cc]
29
+ cc += 1
30
+
31
+ for y in range(nY):
32
+ w_B += [[]]
33
+ for b in range(nB):
34
+ S_1 += [cc]
35
+ w_B[y] += [cc]
36
+ cc += 1
37
+
38
+ for k in range(nK):
39
+ S_1 += [cc]
40
+ w_P += [cc]
41
+ cc += 1
42
+
43
+ # Additional higher order elements
44
+ S_high = [] # Some third order elements
45
+
46
+ for k in range(nK):
47
+ for x in range(nX):
48
+ for kk in range(nK):
49
+ S_high += [[w_P[k],w_R[x],w_P[kk]]]
50
+
51
+ for b in range(nB):
52
+ for k in range(nK):
53
+ for kk in range(nK):
54
+ for y in range(nY):
55
+ S_high += [[w_B[y][b],w_P[k],w_P[kk]]]
56
+
57
+ for x in range(nX):
58
+ for b in range(nB):
59
+ for bb in range(nB):
60
+ for y in range(nY):
61
+ for yy in range(nY):
62
+ S_high += [[w_R[x],w_B[y][b],w_B[yy][bb]]]
63
+
64
+ for x in range(nX):
65
+ for b in range(nB):
66
+ for k in range(nK):
67
+ for y in range(nY):
68
+ S_high += [[w_R[x],w_B[y][b],w_P[k]]]
69
+ S_high += [[w_B[y][b],w_R[x],w_P[k]]]
70
+
71
+ S_high = [] # Uncomment if we only allow up to some 2nd order elements in the hierarchy
72
+
73
+ # Second order elements
74
+ some_second = True
75
+ if some_second == True:
76
+ for x in range(nX):
77
+ for xx in range(nX):
78
+ S_high += [[w_R[x],w_R[xx]]]
79
+
80
+ for x in range(nX):
81
+ for b in range(nB):
82
+ for y in range(nY):
83
+ S_high += [[w_R[x],w_B[y][b]]]
84
+
85
+ for k in range(nK):
86
+ for b in range(nB):
87
+ for y in range(nY):
88
+ S_high += [[w_P[k],w_B[y][b]]]
89
+
90
+ for x in range(nX):
91
+ for k in range(nK):
92
+ S_high += [[w_P[k],w_R[x]]]
93
+
94
+ #S_high = []
95
+
96
+ # Set the operational rules within the SDP relaxation
97
+ list_states = [] # operators that do not commute with anything
98
+ rank_1_projectors = w_R
99
+ rank_1_projectors += [w_B[y][b] for y in range(nY) for b in range(nB)]
100
+ rank_1_projectors += [w_P[k] for k in range(nK)]
101
+ orthogonal_projectors = []
102
+ orthogonal_projectors += [ w_B[y] for y in range(nY)]
103
+ orthogonal_projectors += [ w_P ]
104
+ commuting_variables = [] # commuting elements (wxcept with elements in "list_states"
105
+
106
+ print('Rank-1 projectors',rank_1_projectors)
107
+ print('Orthogonal projectors',orthogonal_projectors)
108
+ print('commuting elements',commuting_variables)
109
+
110
+ [Moment_Matrix,map_table,S,list_of_eq_indices,Mexp] = MomentMatrix(S_1,[],S_high,rank_1_projectors,orthogonal_projectors,commuting_variables,list_states)
111
+
112
+ print('Matrix size:',np.shape(G_new))
113
+
114
+ print(Moment_Matrix)
115
+ for element in map_table:
116
+ print(element)