codedistance 0.0.1__py3-none-any.whl
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.
- codedistance/.DS_Store +0 -0
- codedistance/NHow.py +804 -0
- codedistance/__init__.py +5 -0
- codedistance/code_library.py +556 -0
- codedistance/common.py +566 -0
- codedistance/complex_utils.py +117 -0
- codedistance/dem_detector_filtering.py +255 -0
- codedistance/distance.py +2473 -0
- codedistance-0.0.1.dist-info/METADATA +196 -0
- codedistance-0.0.1.dist-info/RECORD +12 -0
- codedistance-0.0.1.dist-info/WHEEL +4 -0
- codedistance-0.0.1.dist-info/licenses/LICENSE +674 -0
codedistance/common.py
ADDED
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import itertools as iter
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
#######################################
|
|
7
|
+
## Sorting and Indexing
|
|
8
|
+
#######################################
|
|
9
|
+
|
|
10
|
+
def argsort(seq,reverse=False):
|
|
11
|
+
'''Argsort but allowing for sorting of tuples'''
|
|
12
|
+
# http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python
|
|
13
|
+
return sorted(range(len(seq)), key=seq.__getitem__,reverse=reverse)
|
|
14
|
+
|
|
15
|
+
def argmin(seq,reverse=False):
|
|
16
|
+
'''Argsort but allowing for sorting of tuples'''
|
|
17
|
+
# http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python
|
|
18
|
+
compfun = max if reverse else min
|
|
19
|
+
return compfun(range(len(seq)), key=seq.__getitem__)
|
|
20
|
+
|
|
21
|
+
def ixRev(ix):
|
|
22
|
+
## return indices to restore original column order
|
|
23
|
+
## input: ix - permutation of [0..n-1]
|
|
24
|
+
## output: ixR such that ix[ixR] = [0..n-1]
|
|
25
|
+
n = max(ix) + 1
|
|
26
|
+
ixR = ZMatZeros(n)
|
|
27
|
+
ixR[ix] = range(len(ix))
|
|
28
|
+
return ixR
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def nonDecreasing(w):
|
|
33
|
+
'''Check whether vector w is non-decreasing'''
|
|
34
|
+
for i in range(1,len(w)):
|
|
35
|
+
if w[i] < w[i-1]:
|
|
36
|
+
return False
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
def printObj(params):
|
|
40
|
+
temp = []
|
|
41
|
+
for k,v in vars(params).items():
|
|
42
|
+
temp.append(f'{k}: {v}')
|
|
43
|
+
return "\n".join(temp)
|
|
44
|
+
|
|
45
|
+
#######################################
|
|
46
|
+
## ZMat - Integer Matrices
|
|
47
|
+
#######################################
|
|
48
|
+
|
|
49
|
+
#######################################
|
|
50
|
+
## Create ZMat
|
|
51
|
+
#######################################
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def Z2MatZeros(s):
|
|
55
|
+
'''Return integer array of zeros of length/shape s'''
|
|
56
|
+
return np.zeros(s,dtype=np.int8)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def Z2Mat(A):
|
|
60
|
+
return ZMat(A,dtype=np.int8)
|
|
61
|
+
|
|
62
|
+
def ZMat(A,n=None,dtype=int):
|
|
63
|
+
'''Create an integer numpy array. If n is set, ensure that the row length is n.'''
|
|
64
|
+
if typeName(A) in ['set','range']:
|
|
65
|
+
A = list(A)
|
|
66
|
+
if typeName(A) != 'ndarray' or A.dtype != dtype:
|
|
67
|
+
A = np.array(A,dtype=dtype)
|
|
68
|
+
if n is not None:
|
|
69
|
+
s = list(A.shape)
|
|
70
|
+
if s[-1] == 0:
|
|
71
|
+
A= np.empty((0,n),dtype=dtype)
|
|
72
|
+
return A
|
|
73
|
+
|
|
74
|
+
def ZMatI(n):
|
|
75
|
+
'''Identity n x n integer matrix'''
|
|
76
|
+
return np.eye(n,dtype=int)
|
|
77
|
+
|
|
78
|
+
def ZMatZeros(s):
|
|
79
|
+
'''Return integer array of zeros of length/shape s'''
|
|
80
|
+
return np.zeros(s,dtype=int)
|
|
81
|
+
|
|
82
|
+
def ZMat2Magma(A,N):
|
|
83
|
+
m,n = A.shape
|
|
84
|
+
temp = [f'C := LinearCode<GF({N}), {n} |']
|
|
85
|
+
for a in A:
|
|
86
|
+
temp.append(f'[{", ".join([str(x) for x in a])}],')
|
|
87
|
+
temp[-1] = temp[-1][:-1] + '>;'
|
|
88
|
+
return ("\n".join(temp))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
###################################################
|
|
92
|
+
## Calc Linear Combinations of up to t rows
|
|
93
|
+
###################################################
|
|
94
|
+
|
|
95
|
+
def Orbit2distIter(SX,t=None,return_u=False):
|
|
96
|
+
'''Interator yielding binary rows of form (u SX mod 2) for wt(u) <= t.
|
|
97
|
+
if return_u, yield u as well as the row.'''
|
|
98
|
+
r, n = np.shape(SX)
|
|
99
|
+
if t is None:
|
|
100
|
+
t = r
|
|
101
|
+
t = min(t, r)
|
|
102
|
+
for k in range(t+1):
|
|
103
|
+
for xSupp in iter.combinations(range(r),k):
|
|
104
|
+
vSX = np.mod(np.sum(SX[xSupp,:],axis=0),2)
|
|
105
|
+
if return_u:
|
|
106
|
+
u = set2Bin(r,xSupp)
|
|
107
|
+
yield vSX, u
|
|
108
|
+
else:
|
|
109
|
+
yield vSX
|
|
110
|
+
|
|
111
|
+
# def Orbit2dist(SX,t=None,return_u=False):
|
|
112
|
+
# '''Matrix with binary rows of form (q + u SX mod 2) for wt(u) <= t.
|
|
113
|
+
# if return_u, yield u as well as the row.'''
|
|
114
|
+
# temp = list(Orbit2distIter(SX,t,return_u))
|
|
115
|
+
# # temp = Orbit2dist(SX,t,return_u)
|
|
116
|
+
# print(temp)
|
|
117
|
+
# if return_u:
|
|
118
|
+
# temp = list(zip(*temp))
|
|
119
|
+
# return [ZMat(a) for a in temp]
|
|
120
|
+
# else:
|
|
121
|
+
# return ZMat(temp)
|
|
122
|
+
|
|
123
|
+
def Orbit2dist(SX,t=None,return_u=False):
|
|
124
|
+
r,n = SX.shape
|
|
125
|
+
if t is None:
|
|
126
|
+
t = r
|
|
127
|
+
t = min(t, r)
|
|
128
|
+
if return_u:
|
|
129
|
+
AList = binLinComb(ZMatHstack([SX,ZMatI(r)]),t)
|
|
130
|
+
A = ZMatVstack(AList)
|
|
131
|
+
return [A[:,:n],A[:,n:]]
|
|
132
|
+
AList = binLinComb(SX,t)
|
|
133
|
+
return ZMatVstack(AList)
|
|
134
|
+
|
|
135
|
+
binomCoeff = dict()
|
|
136
|
+
|
|
137
|
+
def binom(n,k):
|
|
138
|
+
# print('binom',n,k)
|
|
139
|
+
if k > n or k < 0 or n < 0:
|
|
140
|
+
return 0
|
|
141
|
+
global binomCoeff
|
|
142
|
+
ix = (n,k)
|
|
143
|
+
if ix not in binomCoeff:
|
|
144
|
+
if k == 0 or n-k == 0:
|
|
145
|
+
binomCoeff[ix] = 1
|
|
146
|
+
elif k == 1 or n-k == 1:
|
|
147
|
+
binomCoeff[ix] = n
|
|
148
|
+
else:
|
|
149
|
+
binomCoeff[ix] = binom(n-1,k-1) + binom(n-1,k)
|
|
150
|
+
return binomCoeff[ix]
|
|
151
|
+
|
|
152
|
+
def binom(n,k,mult=1):
|
|
153
|
+
# print('binom',n,k)
|
|
154
|
+
if k > n or k < 0 or n < 0:
|
|
155
|
+
return 0
|
|
156
|
+
global binomCoeff
|
|
157
|
+
ix = (n,k,mult)
|
|
158
|
+
if ix not in binomCoeff:
|
|
159
|
+
if k == 0 or n-k == 0:
|
|
160
|
+
binomCoeff[ix] = (mult ** k)
|
|
161
|
+
elif k == 1 or n-k == 1:
|
|
162
|
+
binomCoeff[ix] = n * (mult ** k)
|
|
163
|
+
else:
|
|
164
|
+
binomCoeff[ix] = binom(n-1,k-1,mult) * mult + binom(n-1,k,mult)
|
|
165
|
+
return binomCoeff[ix]
|
|
166
|
+
|
|
167
|
+
def binLinComb(A,d):
|
|
168
|
+
'''Linear combinations of up to d rows of A'''
|
|
169
|
+
r,n = A.shape
|
|
170
|
+
## Allocate space
|
|
171
|
+
AList = [np.empty((binom(r,k),n),dtype=np.int8) for k in range(d+1)]
|
|
172
|
+
## AList[0] is the all zero vector
|
|
173
|
+
AList[0][:,:] = 0
|
|
174
|
+
## AList[1] is A
|
|
175
|
+
AList[1] = A
|
|
176
|
+
## keep track of which parts of AList have been populated
|
|
177
|
+
populated = [n] * 2 + [0] * (d-1)
|
|
178
|
+
for k in range(2,d+1):
|
|
179
|
+
binLinCombRec(r,k,AList,populated)
|
|
180
|
+
return AList
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def binLinCombRec(c,d,AList,populated):
|
|
184
|
+
# print(func_name(),c,d)
|
|
185
|
+
'''Recursive step for binLinComb - update lin comb of d of the first c rows of A into AList'''
|
|
186
|
+
## Can't form lin comb if c < d; if c < 1, nothing to do
|
|
187
|
+
if c < d or c < 1:
|
|
188
|
+
return
|
|
189
|
+
## Check if we have already populated the relevant part of AList
|
|
190
|
+
if populated[d] < c:
|
|
191
|
+
## chose d rows from first c-1 rows of A
|
|
192
|
+
if c > d and populated[d] < c-1:
|
|
193
|
+
binLinCombRec(c-1,d,AList,populated)
|
|
194
|
+
## choose d-1 rows from first c-1 rows of A, then add row A[c-1]
|
|
195
|
+
if d > 1:
|
|
196
|
+
if populated[d-1] < c-1:
|
|
197
|
+
binLinCombRec(c-1,d-1,AList,populated)
|
|
198
|
+
## update AList
|
|
199
|
+
AList[d][binom(c-1,d): binom(c-1,d)+binom(c-1,d-1) ] = AList[d-1][:binom(c-1,d-1)] ^ AList[1][c-1]
|
|
200
|
+
## update populated
|
|
201
|
+
populated[d] = c
|
|
202
|
+
|
|
203
|
+
def binLinComb(A,d,mult=1):
|
|
204
|
+
'''Linear combinations of up to d rows of A'''
|
|
205
|
+
r,n = A.shape
|
|
206
|
+
r = r // mult
|
|
207
|
+
## Allocate space
|
|
208
|
+
AList = [np.empty((binom(r,k,mult),n),dtype=np.int8) for k in range(d+1)]
|
|
209
|
+
## AList[0] is the all zero vector
|
|
210
|
+
AList[0][:,:] = 0
|
|
211
|
+
## AList[1] is A
|
|
212
|
+
AList[1] = A
|
|
213
|
+
## keep track of which parts of AList have been populated
|
|
214
|
+
populated = [n] * 2 + [0] * (d-1)
|
|
215
|
+
for k in range(2,d+1):
|
|
216
|
+
binLinCombRec(r,k,AList,populated,mult)
|
|
217
|
+
return AList
|
|
218
|
+
|
|
219
|
+
def binLinCombRec(c,d,AList,populated,mult=1):
|
|
220
|
+
# print(func_name(),c,d)
|
|
221
|
+
'''Recursive step for binLinComb - update lin comb of d of the first c rows of A into AList'''
|
|
222
|
+
## Can't form lin comb if c < d; if c < 1, nothing to do
|
|
223
|
+
if c < d or c < 1:
|
|
224
|
+
return
|
|
225
|
+
## Check if we have already populated the relevant part of AList
|
|
226
|
+
if populated[d] < c:
|
|
227
|
+
## chose d rows from first c-1 rows of A
|
|
228
|
+
if c > d and populated[d] < c-1:
|
|
229
|
+
binLinCombRec(c-1,d,AList,populated,mult)
|
|
230
|
+
## choose d-1 rows from first c-1 rows of A, then add row A[c-1]
|
|
231
|
+
if d > 1:
|
|
232
|
+
if populated[d-1] < c-1:
|
|
233
|
+
binLinCombRec(c-1,d-1,AList,populated,mult)
|
|
234
|
+
## update AList
|
|
235
|
+
Bc1d = binom(c-1,d,mult)
|
|
236
|
+
Bc1d1 = binom(c-1,d-1,mult)
|
|
237
|
+
# print(func_name(),Bc1d + mult * Bc1d1 - len(AList[d]))
|
|
238
|
+
for i in range(mult):
|
|
239
|
+
# print('AList[d-1][:Bc1d1]',AList[d-1][:Bc1d1].shape)
|
|
240
|
+
# print('AList[1][(c-1)*mult+i]',AList[1][(c-1)*mult+i].shape)
|
|
241
|
+
X = AList[d-1][:Bc1d1] ^ AList[1][(c-1)*mult+i]
|
|
242
|
+
# print('X',[x for x in range(len(X)) if np.sum(X[x]) == 0])
|
|
243
|
+
# print('Bc1d1',Bc1d1,X.shape,AList[d].shape,d)
|
|
244
|
+
AList[d][Bc1d + i * Bc1d1: Bc1d + (i+1) * Bc1d1] = X
|
|
245
|
+
## update populated
|
|
246
|
+
populated[d] = c
|
|
247
|
+
|
|
248
|
+
def getdMax(r,maxLen=1 << 20):
|
|
249
|
+
s = 0
|
|
250
|
+
for i in range(r+1):
|
|
251
|
+
s += binom(r,i)
|
|
252
|
+
if s > maxLen:
|
|
253
|
+
# print(func_name(),s,i-1)
|
|
254
|
+
return i-1
|
|
255
|
+
return r
|
|
256
|
+
|
|
257
|
+
def weightEnumerator(A):
|
|
258
|
+
m,n = A.shape
|
|
259
|
+
temp = ZMatZeros(n+1)
|
|
260
|
+
for s in Orbit2dist(A):
|
|
261
|
+
temp[np.sum(s)] += 1
|
|
262
|
+
return temp
|
|
263
|
+
|
|
264
|
+
####################################
|
|
265
|
+
## Conversions to other formats
|
|
266
|
+
####################################
|
|
267
|
+
|
|
268
|
+
def isIter(A):
|
|
269
|
+
return hasattr(A,'__iter__')
|
|
270
|
+
|
|
271
|
+
def Lolshape(CC):
|
|
272
|
+
if len(CC) == 0 or not isIter(CC[0]):
|
|
273
|
+
return [len(CC)]
|
|
274
|
+
else:
|
|
275
|
+
return [len(CC)] + Lolshape(CC[0])
|
|
276
|
+
|
|
277
|
+
def SL2ZM(CC,ix,A):
|
|
278
|
+
'''recursive step for Sets2ZMat'''
|
|
279
|
+
if len(CC) == 0 or not isIter(CC[0]):
|
|
280
|
+
for i in CC:
|
|
281
|
+
ix2 = (ix + [i])
|
|
282
|
+
A[tuple(ix2)] = 1
|
|
283
|
+
else:
|
|
284
|
+
i = 0
|
|
285
|
+
for c in CC:
|
|
286
|
+
ix2 = ix + [i]
|
|
287
|
+
SL2ZM(c,ix2,A)
|
|
288
|
+
i+=1
|
|
289
|
+
|
|
290
|
+
def Sets2ZMat(n,CC):
|
|
291
|
+
'''Convert a list of lists or sets to a binary matrix with rows of length n
|
|
292
|
+
Fast method - matrix storage is allocated at beginning'''
|
|
293
|
+
## get shape of final matrix
|
|
294
|
+
s = Lolshape(CC)
|
|
295
|
+
s[-1] = n
|
|
296
|
+
## intialise to all zeros
|
|
297
|
+
A = np.zeros(s,dtype=np.int8)
|
|
298
|
+
## recursion
|
|
299
|
+
SL2ZM(CC,[],A)
|
|
300
|
+
return A
|
|
301
|
+
|
|
302
|
+
def ZMat2Sets(A):
|
|
303
|
+
'''Convert a binary matrix to a list of lists of non-zero entries
|
|
304
|
+
recursive method'''
|
|
305
|
+
if len(A.shape) == 1:
|
|
306
|
+
return bin2Set(A)
|
|
307
|
+
else:
|
|
308
|
+
return [ZMat2Sets(B) for B in A]
|
|
309
|
+
|
|
310
|
+
def ZMatVstack(AList):
|
|
311
|
+
'''Faster method for stacking 2xD matrices'''
|
|
312
|
+
if len(AList) == 0:
|
|
313
|
+
return ZMatZeros((0,0))
|
|
314
|
+
A = AList[0]
|
|
315
|
+
r,n = A.shape
|
|
316
|
+
dtype = A.dtype
|
|
317
|
+
ALen = [len(A) for A in AList]
|
|
318
|
+
m = np.sum(ALen)
|
|
319
|
+
B = np.empty((m,n),dtype=dtype)
|
|
320
|
+
c1 = 0
|
|
321
|
+
for i in range(len(AList)):
|
|
322
|
+
c2 = c1 + ALen[i]
|
|
323
|
+
B[c1:c2] = AList[i]
|
|
324
|
+
c1 = c2
|
|
325
|
+
return B
|
|
326
|
+
|
|
327
|
+
def ZMatHstack(AList):
|
|
328
|
+
'''Faster method for stacking 2xD matrices'''
|
|
329
|
+
# return ZMatVstack([A.T for A in AList]).T
|
|
330
|
+
if len(AList) == 0:
|
|
331
|
+
return ZMatZeros((0,0))
|
|
332
|
+
A = AList[0]
|
|
333
|
+
r,n = A.shape
|
|
334
|
+
dtype = A.dtype
|
|
335
|
+
# AList = [ZMat(A) for A in AList]
|
|
336
|
+
ALen = [len(A.T) for A in AList]
|
|
337
|
+
m = np.sum(ALen)
|
|
338
|
+
A = AList[0]
|
|
339
|
+
r,n = A.shape
|
|
340
|
+
B = np.empty((r,m),dtype=dtype)
|
|
341
|
+
c1 = 0
|
|
342
|
+
for i in range(len(AList)):
|
|
343
|
+
c2 = c1 + ALen[i]
|
|
344
|
+
B[:,c1:c2] = AList[i]
|
|
345
|
+
c1 = c2
|
|
346
|
+
return B
|
|
347
|
+
|
|
348
|
+
def Mnt(n,t,mink=1):
|
|
349
|
+
'''Rows are binary strings of length n of weight mink to t'''
|
|
350
|
+
CC = [s for k in range(mink, t+1) for s in iter.combinations(range(n),k)]
|
|
351
|
+
return Sets2ZMat(n,CC)
|
|
352
|
+
A = [set2Bin(n,s) for k in range(mink, t+1) for s in iter.combinations(range(n),k)]
|
|
353
|
+
return ZMat(A)
|
|
354
|
+
|
|
355
|
+
### multi dimensional versions?
|
|
356
|
+
def set2Bin(n,A,dtype=int):
|
|
357
|
+
'''Convert list of integers t to a binary vector of length n'''
|
|
358
|
+
temp = np.zeros(n,dtype=dtype)
|
|
359
|
+
temp[list(A)] = 1
|
|
360
|
+
return temp
|
|
361
|
+
|
|
362
|
+
def bin2Set(v):
|
|
363
|
+
'''Convert binary vector to a list of indices such that v[i] !=0'''
|
|
364
|
+
v = np.ravel(v)
|
|
365
|
+
return list(map(int,np.nonzero(v)[0]))
|
|
366
|
+
|
|
367
|
+
def ZMat2tuple(A):
|
|
368
|
+
'''Convert rows of A to tuples.'''
|
|
369
|
+
n = np.shape(A)[-1]
|
|
370
|
+
A = np.reshape(A,(-1,n))
|
|
371
|
+
return [tuple(a) for a in A]
|
|
372
|
+
|
|
373
|
+
def set2tuple(c):
|
|
374
|
+
return tuple(sorted(set(c)))
|
|
375
|
+
n = max(c) + 1
|
|
376
|
+
return tuple(inRange(n,c))
|
|
377
|
+
|
|
378
|
+
def invRange(n,S):
|
|
379
|
+
'''return list of elements of range(n) NOT in S'''
|
|
380
|
+
return sorted(set(range(n)) - set(S))
|
|
381
|
+
|
|
382
|
+
def inRange(n,S):
|
|
383
|
+
'''return list of elements of range(n) which ARE in S'''
|
|
384
|
+
return sorted(set(S).intersection(range(n)))
|
|
385
|
+
|
|
386
|
+
def int2bin(x,d,N=2):
|
|
387
|
+
'''convert integer to base N vector'''
|
|
388
|
+
temp = []
|
|
389
|
+
for i in range(d):
|
|
390
|
+
temp.append(x % N)
|
|
391
|
+
x = x // N
|
|
392
|
+
return ZMat(temp)
|
|
393
|
+
|
|
394
|
+
##############################
|
|
395
|
+
## ZMat Info
|
|
396
|
+
##############################
|
|
397
|
+
|
|
398
|
+
def leadingIndex(a):
|
|
399
|
+
'''Return leading index of vector a (ie smallest value for which a[i] !=0)'''
|
|
400
|
+
i = 0
|
|
401
|
+
n = len(a)
|
|
402
|
+
while i < n and a[i]==0:
|
|
403
|
+
i+=1
|
|
404
|
+
return i
|
|
405
|
+
|
|
406
|
+
def isZero(A,N=False):
|
|
407
|
+
'''Check if A modulo N = 0 for all values in A.'''
|
|
408
|
+
if N:
|
|
409
|
+
A = np.mod(A,N)
|
|
410
|
+
return np.all(A == 0)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
#######################################
|
|
414
|
+
## ZMat Analysis
|
|
415
|
+
#######################################
|
|
416
|
+
|
|
417
|
+
def freqTable(wList):
|
|
418
|
+
'''Dict of val:count for val in wList'''
|
|
419
|
+
temp = {w:0 for w in set(wList)}
|
|
420
|
+
for w in wList:
|
|
421
|
+
temp[w] += 1
|
|
422
|
+
return temp
|
|
423
|
+
|
|
424
|
+
def freqTablePrint(wList):
|
|
425
|
+
FT = freqTable(wList)
|
|
426
|
+
temp = [f'{k}:{FT[k]}' for k in sorted(FT.keys())]
|
|
427
|
+
return ",".join(temp)
|
|
428
|
+
|
|
429
|
+
##########################
|
|
430
|
+
## Changing Shape of ZMat
|
|
431
|
+
##########################
|
|
432
|
+
|
|
433
|
+
def ZMatInfo(A):
|
|
434
|
+
return f'{A.dtype} {A.shape}'
|
|
435
|
+
|
|
436
|
+
def ZMat2D(A):
|
|
437
|
+
'''Return a 2-dimensional integer numpy array from A.'''
|
|
438
|
+
s = A.shape
|
|
439
|
+
if len(s) == 2:
|
|
440
|
+
return A
|
|
441
|
+
d = s[-1]
|
|
442
|
+
return np.reshape(A,(-1,d))
|
|
443
|
+
|
|
444
|
+
##########################
|
|
445
|
+
## String I/0 for ZMat
|
|
446
|
+
##########################
|
|
447
|
+
|
|
448
|
+
def row2components(r):
|
|
449
|
+
'''For integer vector r return indices for the non-zero values ix=supp(r) and the non-zero values r[ix].
|
|
450
|
+
Useful for displaying large vectors.'''
|
|
451
|
+
ix = ZMat(np.nonzero(r))
|
|
452
|
+
return ix, r[ix]
|
|
453
|
+
|
|
454
|
+
def row2compStr(r):
|
|
455
|
+
'''Display row r using indices for non-zero values and list of non-zero values
|
|
456
|
+
Useful for displaying large vectors.'''
|
|
457
|
+
ix,vals = row2components(r)
|
|
458
|
+
return f'{ix}:= {vals}'.replace(" ","")
|
|
459
|
+
|
|
460
|
+
def ZMat2compStr(A):
|
|
461
|
+
'''Display 2D integer matrix A using indices for non-zero values and list of non-zero values
|
|
462
|
+
Useful for displaying large vectors.'''
|
|
463
|
+
return "\n".join([row2compStr(r) for r in A])
|
|
464
|
+
|
|
465
|
+
def str2ZMat(mystr):
|
|
466
|
+
'''Convert string of single digit numbers or multi digit numbers split by spaces to an integer array'''
|
|
467
|
+
if mystr.find(" ") > 0:
|
|
468
|
+
mystr = mystr.split()
|
|
469
|
+
return ZMat([int(s) for s in mystr])
|
|
470
|
+
|
|
471
|
+
def str2ZMatdelim(S=''):
|
|
472
|
+
'''Convert string with rows separated by \r, \n "," or ; to 2D integer array.'''
|
|
473
|
+
sep=','
|
|
474
|
+
for s in "\r\n;":
|
|
475
|
+
S = S.replace(s,sep)
|
|
476
|
+
S = S.split(sep)
|
|
477
|
+
return ZMat([str2ZMat(s) for s in S])
|
|
478
|
+
|
|
479
|
+
def bin2ZMat(SX):
|
|
480
|
+
'''Convert multiple types of binary vector input to integer matrix.
|
|
481
|
+
SX is either string or array.'''
|
|
482
|
+
if SX is None:
|
|
483
|
+
return SX
|
|
484
|
+
## convert string to ZMat
|
|
485
|
+
if isinstance(SX,str):
|
|
486
|
+
return str2ZMatdelim(SX.strip())
|
|
487
|
+
## convert array to ZMat
|
|
488
|
+
return ZMat(SX)
|
|
489
|
+
|
|
490
|
+
def ZMat2str(A,N=None):
|
|
491
|
+
'''Return string version of integer matrix A.'''
|
|
492
|
+
if np.size(A) == 0:
|
|
493
|
+
return ""
|
|
494
|
+
S = np.char.mod('%d', A)
|
|
495
|
+
sep = ""
|
|
496
|
+
if N is None:
|
|
497
|
+
N = np.amax(A) + 1
|
|
498
|
+
if N > 10:
|
|
499
|
+
Nw= len(str(N-1))
|
|
500
|
+
S = np.char.rjust(S,Nw)
|
|
501
|
+
sep = " "
|
|
502
|
+
return sep.join(S)
|
|
503
|
+
return np.apply_along_axis(func1d=sepjoin,axis=-1,arr=S,sep=sep)
|
|
504
|
+
|
|
505
|
+
def sepjoin(a,sep):
|
|
506
|
+
'''Join text vector a using sep - for display of ZMat.'''
|
|
507
|
+
return sep.join(a)
|
|
508
|
+
|
|
509
|
+
def ZMatPrint(A,N=None,nA=0,tB=1):
|
|
510
|
+
'''Print integer matrix A'''
|
|
511
|
+
temp = []
|
|
512
|
+
A = ZMat2D(A)
|
|
513
|
+
m,n = A.shape
|
|
514
|
+
nB = (n - nA)//tB
|
|
515
|
+
for r in A:
|
|
516
|
+
myRow = [ZMat2str(r[t*nB:(t+1)*nB],N) for t in range(tB)]
|
|
517
|
+
if tB*nB < n:
|
|
518
|
+
myRow.append(ZMat2str(r[tB*nB :],N))
|
|
519
|
+
temp.append("|".join(myRow))
|
|
520
|
+
return "\n".join(temp)
|
|
521
|
+
|
|
522
|
+
#################################################
|
|
523
|
+
## Debugging Functions
|
|
524
|
+
#################################################
|
|
525
|
+
|
|
526
|
+
def currTime():
|
|
527
|
+
'''Return current time'''
|
|
528
|
+
return time.perf_counter()
|
|
529
|
+
return time.process_time()
|
|
530
|
+
|
|
531
|
+
def startTimer():
|
|
532
|
+
'''Start timer for algorithm and set global variable startTime to be the current time.'''
|
|
533
|
+
global startTime
|
|
534
|
+
startTime = currTime()
|
|
535
|
+
return startTime
|
|
536
|
+
|
|
537
|
+
def elapsedTime():
|
|
538
|
+
'''Return the time elapsed from last startTimer() call.'''
|
|
539
|
+
global startTime
|
|
540
|
+
return -startTime + startTimer()
|
|
541
|
+
|
|
542
|
+
def func_name():
|
|
543
|
+
"""Return the name of the current function - for debugging."""
|
|
544
|
+
return sys._getframe(1).f_code.co_name
|
|
545
|
+
|
|
546
|
+
def typeName(val):
|
|
547
|
+
'''Return the name of the type of val in text form.'''
|
|
548
|
+
return type(val).__name__
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
##################################
|
|
552
|
+
## Integer logarithms
|
|
553
|
+
##################################
|
|
554
|
+
|
|
555
|
+
def logCeil(x,N=2):
|
|
556
|
+
'''Return min(t) where x <= N^t'''
|
|
557
|
+
i = 0
|
|
558
|
+
while x > 0:
|
|
559
|
+
x = x // N
|
|
560
|
+
i = i+1
|
|
561
|
+
return i
|
|
562
|
+
|
|
563
|
+
def log2int(N):
|
|
564
|
+
'''Find t such that N = 2**t or None otherwise'''
|
|
565
|
+
t = logCeil(N-1,2)
|
|
566
|
+
return t if 2 ** t == N else None
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .common import *
|
|
3
|
+
from .NHow import *
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
#################################
|
|
7
|
+
# Functions needed to work with complexes
|
|
8
|
+
#################################
|
|
9
|
+
|
|
10
|
+
def complexCheck(AList):
|
|
11
|
+
"""Check if AList is a valid complex"""
|
|
12
|
+
for i in range(len(AList) - 1):
|
|
13
|
+
Ai = AList[i]
|
|
14
|
+
mi, ni = np.shape(Ai)
|
|
15
|
+
Aj = AList[i + 1]
|
|
16
|
+
mj, nj = np.shape(Aj)
|
|
17
|
+
## check dimension of matrices
|
|
18
|
+
if ni != mj:
|
|
19
|
+
print(f"ni={ni} != mj={mj} for i={i},j={i+1}")
|
|
20
|
+
return False
|
|
21
|
+
## check that successive operators multiply to zero
|
|
22
|
+
AiAj = matMul(Ai, Aj, 2)
|
|
23
|
+
if not np.sum(AiAj) == 0:
|
|
24
|
+
print(f"Ai@Aj != 0 for i={i},j={i+1}")
|
|
25
|
+
return False
|
|
26
|
+
return True
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def complexTrim(AList):
|
|
30
|
+
"""Remove any all zero matrices from beginning of AList."""
|
|
31
|
+
temp = []
|
|
32
|
+
i = 0
|
|
33
|
+
while np.sum(AList[i]) == 0:
|
|
34
|
+
i += 1
|
|
35
|
+
return AList[i:]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def complexAppendZero(AList):
|
|
39
|
+
"""Add zero operator to beginning of AList"""
|
|
40
|
+
m, n = np.shape(AList[0])
|
|
41
|
+
return [ZMatZeros((1, m))] + AList
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def complexNew(AList):
|
|
45
|
+
"""Make a new complex - make sure there's a zero operator at the end"""
|
|
46
|
+
AList = complexTrim(AList)
|
|
47
|
+
AList = complexAppendZero(AList)
|
|
48
|
+
return AList
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def complexDims(AList):
|
|
52
|
+
"""Return dimensions of each space acted upon by AList."""
|
|
53
|
+
return [np.shape(A)[1] for A in AList]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def RG2Complex(myrow):
|
|
57
|
+
"""convert string format to RG complex boundary operators"""
|
|
58
|
+
boundaryOperators = []
|
|
59
|
+
## read boundary maps for each level of the complex
|
|
60
|
+
for myLabel in [f"Z{i}" for i in range(4, -1, -1)]:
|
|
61
|
+
if myLabel in myrow:
|
|
62
|
+
## convert to boundary operators
|
|
63
|
+
boundaryOperators.append(str2ZMatdelim(myrow[myLabel]))
|
|
64
|
+
return complexNew(boundaryOperators)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def importRGList(myfile):
|
|
68
|
+
"""Import hyperbolic surface codes stored in myfile.
|
|
69
|
+
Records in myfile are stored in JSON format.
|
|
70
|
+
Parse each record and return list of dict codeList."""
|
|
71
|
+
# mypath = sys.path[0] + "/hyperbolic_codes/"
|
|
72
|
+
# f = open(mypath + myfile, "r")
|
|
73
|
+
f = open(myfile, "r")
|
|
74
|
+
mytext = f.read()
|
|
75
|
+
mytext = mytext.replace("\\\n", "").replace("\n", "")
|
|
76
|
+
mytext = mytext.replace("{", "\n{")
|
|
77
|
+
mytext = mytext.split("\n")
|
|
78
|
+
codeList = []
|
|
79
|
+
for myline in mytext:
|
|
80
|
+
if len(myline) > 0 and myline[0] != "#":
|
|
81
|
+
myrow = json.loads(myline)
|
|
82
|
+
codeList.append([myrow["index"], RG2Complex(myrow)])
|
|
83
|
+
f.close()
|
|
84
|
+
return codeList
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def printRGList(codeList, myfile, checkValid=False):
|
|
88
|
+
"""Print parameters of the hyperbolic codes stored in list of dict codeList"""
|
|
89
|
+
temp = []
|
|
90
|
+
temp.append(f"Codes in File {myfile}:\n")
|
|
91
|
+
valTxt = "\tValid" if checkValid else ""
|
|
92
|
+
D = len(codeList[0][1])
|
|
93
|
+
myrow = f"i\tindex{valTxt}"
|
|
94
|
+
for i in range(D):
|
|
95
|
+
myrow += f"\t|C{i}|"
|
|
96
|
+
temp.append(myrow)
|
|
97
|
+
for i in range(len(codeList)):
|
|
98
|
+
myrow = codeList[i]
|
|
99
|
+
ix = myrow[0]
|
|
100
|
+
C = myrow[1]
|
|
101
|
+
rowDesc = [i, ix]
|
|
102
|
+
if checkValid:
|
|
103
|
+
rowDesc += [complexCheck(C)]
|
|
104
|
+
rowDesc += complexDims(C)
|
|
105
|
+
temp.append("\t".join([str(a) for a in rowDesc]))
|
|
106
|
+
return "\n".join(temp)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def complexCProduct(C):
|
|
110
|
+
if len(C) == 0:
|
|
111
|
+
return []
|
|
112
|
+
P = C[0]
|
|
113
|
+
temp = [P.T]
|
|
114
|
+
for i in range(1, len(C)):
|
|
115
|
+
P = mod1(P @ C[i])
|
|
116
|
+
temp.append(P.T)
|
|
117
|
+
return temp
|