- 閉曲面に広げるには、頂点集合・辺集合に加えて、面集合を考えた「単体複体」を扱うこと
- それに伴って、境界準同型に辺と面との関係が登場し、ホモロジー群がちょっと込み入るだけ
- 面の向き、向き付き可能という考え方が分類上、大事
- computing homology(python)
- phom(Rパッケージ)
- pythonの方のソースは
- (1) グラフ・複体の頂点集合・辺集合・面集合を完全グラフだった場合の要素として作る
- (2) 実際のグラフ・複体に合わせて、各チェインでの存在具合を0,1,-1を要素とする行列で作る。これが写像に対応する行列
- (3) ホモロジー群を考えるときには、隣り合わせの2行列を「簡略化」する。「簡略化」する、とは、オイラーの掃出し法で行列を一意で解釈しやすい形にすること。ただし、それをするときに、一つの行列に関して掃出しながら、隣の行列についても同じ掃出しを実行する
- (4) betti数の計算は、このようにして、一緒に変形した2行列から、非0行・列の数を数えることで求まる
import numpy
import numpy.linalg
def rowSwap(A, i, j):
temp = numpy.copy(A[i, :])
A[i, :] = A[j, :]
A[j, :] = temp
def colSwap(A, i, j):
temp = numpy.copy(A[:, i])
A[:, i] = A[:, j]
A[:, j] = temp
def scaleCol(A, i, c):
A[:, i] *= c*numpy.ones(A.shape[0])
def scaleRow(A, i, c):
A[i, :] *= c*numpy.ones(A.shape[1])
def colCombine(A, addTo, scaleCol, scaleAmt):
A[:, addTo] += scaleAmt * A[:, scaleCol]
def rowCombine(A, addTo, scaleRow, scaleAmt):
A[addTo, :] += scaleAmt * A[scaleRow, :]
def simultaneousReduce(A, B):
if A.shape[1] != B.shape[0]:
raise Exception("Matrices have the wrong shape.")
numRows, numCols = A.shape
i,j = 0,0
while True:
if i >= numRows or j >= numCols:
break
if A[i,j] == 0:
nonzeroCol = j
while nonzeroCol < numCols and A[i,nonzeroCol] == 0:
nonzeroCol += 1
if nonzeroCol == numCols:
i += 1
continue
colSwap(A, j, nonzeroCol)
rowSwap(B, j, nonzeroCol)
pivot = A[i,j]
scaleCol(A, j, 1.0 / pivot)
scaleRow(B, j, 1.0 / pivot)
for otherCol in range(0, numCols):
if otherCol == j:
continue
if A[i, otherCol] != 0:
scaleAmt = -A[i, otherCol]
colCombine(A, otherCol, j, scaleAmt)
rowCombine(B, j, otherCol, -scaleAmt)
i += 1; j+= 1
return A,B
def finishRowReducing(B):
numRows, numCols = B.shape
i,j = 0,0
while True:
if i >= numRows or j >= numCols:
break
if B[i, j] == 0:
nonzeroRow = i
while nonzeroRow < numRows and B[nonzeroRow, j] == 0:
nonzeroRow += 1
if nonzeroRow == numRows:
j += 1
continue
rowSwap(B, i, nonzeroRow)
pivot = B[i, j]
scaleRow(B, i, 1.0 / pivot)
for otherRow in range(0, numRows):
if otherRow == i:
continue
if B[otherRow, j] != 0:
scaleAmt = -B[otherRow, j]
rowCombine(B, otherRow, j, scaleAmt)
i += 1; j+= 1
return B
def numPivotCols(A):
z = numpy.zeros(A.shape[0])
return [numpy.all(A[:, j] == z) for j in range(A.shape[1])].count(False)
def numPivotRows(A):
z = numpy.zeros(A.shape[1])
return [numpy.all(A[i, :] == z) for i in range(A.shape[0])].count(False)
def bettiNumber(d_k, d_kplus1):
A, B = numpy.copy(d_k), numpy.copy(d_kplus1)
simultaneousReduce(A, B)
finishRowReducing(B)
dimKChains = A.shape[1]
print(dimKChains)
kernelDim = dimKChains - numPivotCols(A)
print(kernelDim)
imageDim = numPivotRows(B)
print(imageDim)
return kernelDim - imageDim
bd0 = numpy.array([[0,0,0,0,0]])
bd1 = numpy.array([[-1,-1,-1,-1,0,0,0,0], [1,0,0,0,-1,-1,0,0],
[0,1,0,0,1,0,-1,-1], [0,0,1,0,0,1,1,0], [0,0,0,1,0,0,0,1]])
bd2 = numpy.array([[1,1,0,0],[-1,0,1,0],[0,-1,-1,0],
[0,0,0,0],[1,0,0,1],[0,1,0,-1],
[0,0,1,1],[0,0,0,0]])
bd3 = numpy.array([[-1],[1],[-1],[1]])
print("Example complex from post")
print("0th homology: %d" % bettiNumber(bd0,bd1))
print("1st homology: %d" % bettiNumber(bd1,bd2))
print("2nd homology: %d" % bettiNumber(bd2,bd3))
mobiusD1 = numpy.array([
[-1,-1,-1,-1, 0, 0, 0, 0, 0, 0],
[ 1, 0, 0, 0,-1,-1,-1, 0, 0, 0],
[ 0, 1, 0, 0, 1, 0, 0,-1,-1, 0],
[ 0, 0, 0, 1, 0, 0, 1, 0, 1, 1],
])
mobiusD2 = numpy.array([
[ 1, 0, 0, 0, 1],
[ 0, 0, 0, 1, 0],
[-1, 0, 0, 0, 0],
[ 0, 0, 0,-1,-1],
[ 0, 1, 0, 0, 0],
[ 1,-1, 0, 0, 0],
[ 0, 0, 0, 0, 1],
[ 0, 1, 1, 0, 0],
[ 0, 0,-1, 1, 0],
[ 0, 0, 1, 0, 0],
])
print("Mobius Band")
print("1st homology: %d" % bettiNumber(mobiusD1, mobiusD2))