Skip to content

Commit 9308fc6

Browse files
Merge pull request #29 from pnnl/develop
Develop
2 parents 7d48cd2 + c107a64 commit 9308fc6

File tree

4 files changed

+38
-45
lines changed

4 files changed

+38
-45
lines changed

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import os
2020
import shlex
2121

22-
__version__ = "0.3.0"
22+
__version__ = "0.3.1"
2323

2424

2525
# If extensions (or modules to document with autodoc) are in another directory,

hypernetx/algorithms/homology_mod2.py

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def kchainbasis(h,k):
6060
- Hypergraph node uids must be sortable.
6161
6262
"""
63+
6364
import itertools as it
6465
kchains = set()
6566
for e in h.edges():
@@ -70,6 +71,7 @@ def kchainbasis(h,k):
7071
return sorted(list(kchains))
7172

7273
def interpret(Ck,arr):
74+
7375
"""
7476
Returns the data as represented in Ck associated with the arr
7577
@@ -86,6 +88,7 @@ def interpret(Ck,arr):
8688
list of k-cells referenced by data in Ck
8789
8890
"""
91+
8992
output = list()
9093
for vec in arr:
9194
if len(Ck) != len(vec):
@@ -301,6 +304,7 @@ def matmulreduce(arr,reverse=False,mod=2):
301304
P : np.array
302305
Product of matrices in the list
303306
"""
307+
304308
if reverse:
305309
items = range(len(arr)-1,-1,-1)
306310
else:
@@ -333,6 +337,7 @@ def matsumreduce(arr,mod=2):
333337

334338
## Convenience methods for computing Smith Normal Form
335339
## All of these operations have themselves as inverses
340+
336341
def _sr(i,j,M,L):
337342
return swap_rows(i,j,M,L)
338343

@@ -409,6 +414,7 @@ def smith_normal_form_mod2(M,track=False):
409414
where $L = L[s]L[s-1]...L[1]L[0]$ and $R = R[0]R[1]...R[t]$.
410415
411416
"""
417+
412418
S = copy.copy(M)
413419
dimL,dimR = M.shape
414420
mod = 2
@@ -420,15 +426,15 @@ def smith_normal_form_mod2(M,track=False):
420426
L = np.eye(dimL,dtype=int)
421427
R = np.eye(dimR,dtype=int)
422428

423-
Linv = [IL] ## keep track of transformations to compute inverses at the end
424-
Rinv = [IR]
429+
Linv = np.eye(dimL,dtype=int)
425430

426431
if track:
427432
print(L,'L\n')
428433
print(M,'M\n')
429434
print(R,'R\n')
430435

431436
for s in range(min(dimL,dimR)):
437+
print('.'),
432438
if track:
433439
print(f'\ns={s}\n')
434440
## Find index pair (rdx,cdx) with value 1 in submatrix M[s:,s:]
@@ -442,42 +448,27 @@ def smith_normal_form_mod2(M,track=False):
442448
## Swap rows and columns as needed so that 1 is in the s,s position
443449
if rdx > s:
444450
S,L = _sr(s,rdx,S,L)
445-
# This is equivalent to
446-
# S = swap_rows(s,rdx,S)[0]
447-
# L = swap_rows(s,rdx,L)[0]
448-
Linv.append(swap_rows(s,rdx,IL)[0]) ## keep track of transformations on the left to reverse them for the inverse
451+
Linv = swap_columns(s,rdx,Linv)[0]
449452
if track:
450453
print(L,f'L\n',S,'S\n',)
451-
assert(np.all(S == matmulreduce([L,M,R],mod=mod)))
452454
if cdx > s:
453455
S,R= _sc(s,cdx,S,R)
454-
Rinv.append(swap_columns(s,cdx,IR)[0])
455456
if track:
456457
print(S,'S\n',R,f'R\n')
457-
assert(np.all(S == matmulreduce([L,M,R],mod=mod)))
458458

459459
# add sth row to every row with 1 in sth column & sth column to every column with 1 in sth row
460-
row_indices = [idx for idx in range(dimL) if idx != s and S[idx][s] == 1]
460+
row_indices = [idx for idx in range(s+1,dimL) if S[idx][s] == 1]
461461
for rdx in row_indices:
462462
S,L = _ar(rdx,s,S,L,mod=mod)
463-
temp = add_to_row(IL,rdx,s,mod=mod)
464-
Linv.append(temp)
463+
Linv = add_to_column(Linv,s,rdx,mod=mod)
465464
if track:
466465
print(L,f'L\n',S,'S\n',)
467-
assert(np.all(S == matmulreduce([L,M,R],mod=mod)))
468-
column_indices = [jdx for jdx in range(dimR) if jdx != s and S[s][jdx] == 1]
466+
column_indices = [jdx for jdx in range(s+1,dimR) if S[s][jdx] == 1]
469467
for jdx,cdx in enumerate(column_indices):
470468
S,R = _ac(cdx,s,S,R)
471-
temp = add_to_column(IR,cdx,s,mod=mod)
472-
Rinv.append(temp)
473469
if track:
474470
print(R,f'R\n',S,'S\n',)
475-
assert(np.all(S == matmulreduce([L,M,R],mod=mod)))
476-
Linv = matmulreduce(Linv,mod=mod)
477-
Rinv = matmulreduce(Rinv,reverse=True,mod=mod)
478-
assert(np.all(IL == matmulreduce([L,Linv],mod=mod)))
479-
assert(np.all(IR == matmulreduce([R,Rinv],mod=mod)))
480-
return L,R,S,Linv,Rinv
471+
return L,R,S,Linv
481472

482473

483474
def reduced_row_echelon_form_mod2(M,track=False,mod=2):
@@ -511,14 +502,15 @@ def reduced_row_echelon_form_mod2(M,track=False,mod=2):
511502
verify the product:
512503
L[s]L[s-1]...L[0] M = S .
513504
"""
505+
514506
S = copy.copy(M)
515507
dimL,dimR = M.shape
516508
mod = 2
517509

518510
## method with numpy
519511
IL = np.eye(dimL,dtype=int)
520512

521-
Linv = [np.eye(dimL,dtype=int)]
513+
Linv = np.eye(dimL,dtype=int)
522514
L = np.eye(dimL,dtype=int)
523515

524516
if track:
@@ -540,22 +532,17 @@ def reduced_row_echelon_form_mod2(M,track=False,mod=2):
540532
continue
541533
if rdx > s1:
542534
S,L = _sr(s1,rdx,S,L)
543-
Linv.append(swap_rows(s1,rdx,IL)[0]) ## keep track of transformations on the left to reverse them for the inverse
535+
Linv = swap_columns(rdx,s1,Linv)[0]
544536
if track:
545537
print(L,f'L\n',S,'S\n',)
546-
assert(np.all(S == matmulreduce([L,M],mod=mod)))
547-
548538
# add sth row to every nonzero row
549539
row_indices = [idx for idx in range(dimL) if idx != s1 and S[idx][cdx] == 1]
550540
for idx in row_indices:
551541
S,L = _ar(idx,s1,S,L,mod=mod)
552-
temp = add_to_row(IL,idx,s1,mod=mod)
553-
Linv.append(temp)
542+
Linv = add_to_column(Linv,s1,idx,mod=mod)
554543
if track:
555544
print(L,f'L\n',S,'S\n',)
556-
assert(np.all(S == matmulreduce([L,M],mod=mod)))
557-
Linv = matmulreduce(Linv,mod=mod)
558-
assert(np.all(IL == matmulreduce([L,Linv],mod=mod)))
545+
559546
return L,S,Linv
560547

561548
## Private
@@ -674,8 +661,8 @@ def homology_basis(bd,k,C=None,shortest=False):
674661
k-chains
675662
if shortest then returns a dictionary of shortest cycles for each coset.
676663
"""
677-
L1,R1,S1,L1inv,R1inv = smith_normal_form_mod2(bd[k])
678-
L2,R2,S2,L2inv,R2inv = smith_normal_form_mod2(bd[k+1])
664+
L1,R1,S1,L1inv = smith_normal_form_mod2(bd[k])
665+
L2,R2,S2,L2inv = smith_normal_form_mod2(bd[k+1])
679666

680667
rank1 = np.sum(S1); print(f"rank{k} = {rank1}")
681668
rank2 = np.sum(S2); print(f"rank{k+1} = {rank2}")
@@ -686,9 +673,9 @@ def homology_basis(bd,k,C=None,shortest=False):
686673
ker1 = R1[:,rank1:]
687674
im2 = L2inv[:,:rank2]
688675
cokernel2 = L2inv[:,rank2:]
676+
cokproj2 = L2[rank2:,:]
689677

690-
proj = matmulreduce([L2,ker1])[rank2:,:]
691-
proj = matmulreduce([L2inv[:,rank2:],proj]).transpose()
678+
proj = matmulreduce([cokernel2,cokproj2,ker1]).transpose()
692679
_,proj,_ = reduced_row_echelon_form_mod2(proj)
693680
proj = np.array([row for row in proj if np.sum(row)>0])
694681
print('hom basis reps\n',proj)

hypernetx/algorithms/tests/test_homology_mod_2.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,28 @@ def test_bkMatrix(triloop):
2424
def test_smith_normal_form_mod2(triloop):
2525
Ck = {k:hnx.kchainbasis(triloop.hypergraph,k) for k in range(0,2)}
2626
bd = bkMatrix(Ck[0],Ck[1])
27-
P1,Q1,S1,P1inv,Q1inv = smith_normal_form_mod2(bd)
27+
P1,Q1,S1,P1inv = smith_normal_form_mod2(bd)
2828
assert np.array_equal(P1[0],np.array([1, 0, 0, 0]))
2929
assert np.array_equal(Q1[:,2],np.array([0, 1, 1, 0, 0]))
30+
assert(np.all(S1 == matmulreduce([P1,bd,Q1],mod=2)))
31+
r = len(P1)
32+
assert(np.all(np.eye(r) == modmult(P1,P1inv,mod=2)))
33+
assert(np.all(S1 == matmulreduce([P1,bd,Q1],mod=2)))
3034

3135
def test_reduced_row_echelon_form_mod2():
3236
m = np.array([[0,1,0,1,0,0,1,0,0,1],
3337
[0,0,0,0,0,0,0,0,0,1],
3438
[1,0,0,1,0,0,0,0,0,0]])
35-
L,rm,R = reduced_row_echelon_form_mod2(m)
36-
assert np.array_equal(rm,np.array([[1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
37-
[0, 1, 0, 1, 0, 0, 1, 0, 0, 0],
38-
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]))
39+
r = 3
40+
L,S,Linv = reduced_row_echelon_form_mod2(m)
41+
assert np.array_equal(S,np.array([[1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
42+
[0, 1, 0, 1, 0, 0, 1, 0, 0, 0],
43+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]))
3944
assert np.array_equal(L,np.array([[0, 0, 1],
40-
[1, 1, 0],
41-
[0, 1, 0]]))
42-
45+
[1, 1, 0],
46+
[0, 1, 0]]))
47+
assert(np.all(S == modmult(L,m,mod=2)))
48+
assert(np.all(np.eye(3) == modmult(L,Linv,mod=2)))
4349

4450
def test_homology_basis(triloop):
4551
Ck = {k:hnx.kchainbasis(triloop.hypergraph,k) for k in range(0,3)}

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from setuptools import setup
22
import sys, os.path
33

4-
__version__ = '0.3.0'
4+
__version__ = '0.3.1'
55

66
if sys.version_info < (3,6):
77
sys.exit('HyperNetX requires Python 3.6 or later.')

0 commit comments

Comments
 (0)