import PIL.Image
import numpy
+import scipy.sparse
+import scipy.sparse.linalg
import sys
PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning)
#print('shape', image.shape)
#print('dtype', image.dtype)
assert len(image.shape) == 2 and image.dtype == numpy.uint8
-assert numpy.all(image < 4)
# colours are 0 = black, 1 = blue, 2 = red, 3 = white
-#print('xxx', image_pil.palette.tobytes()[:12])
+palette = numpy.array(list(image_pil.palette.tobytes()), numpy.uint8)
+#print('palette', palette)
+assert numpy.all(
+ (palette >= 0x80) == numpy.array(
+ [
+ False, False, False,
+ False, False, True,
+ True, False, False,
+ True, True, True,
+ ],
+ bool
+ )
+)
ys, xs = image.shape
n = ys * xs
# KCL is enforced as follows:
# A V = I where V = voltage at node, I = net current out of node
-# I is current "unaccounted for", i.e. current that cancels R currents
+# (when node is electrode, positive I means current is entering the array)
# resistor R connected n1 -> n2:
-# causes a current of (V(n2) - V(n1)) / R, positive when V(n2) > V(n1)
-# => when current is positive, it should decrease I(n1) and increase I(n2)
-# => I(n1) -= 1/R V(n2) - 1/R V(n1), I(n2) += 1/R V(n2) - 1/R V(n1)
-# => I(n1) += 1/R V(n1) - 1/R V(n1), I(n2) += -1/R V(n1) + 1/R V(n2)
-A = numpy.zeros((n, n), numpy.int8)
+# causes a current of (V(n1) - V(n2)) / R, positive when V(n1) > V(n2)
+# => when current is positive, it should increase I(n1) and decrease I(n2)
+# => I(n1) += 1/R V(n1) - 1/R V(n2), I(n2) -= 1/R V(n1) - 1/R V(n2)
+v = []
+i = []
+j = []
for n1 in numpy.nonzero(image_horiz.reshape((n,)))[0]:
n2 = n1 + 1
- A[n1, n1] += 1
- A[n1, n2] -= 1
- A[n2, n1] -= 1
- A[n2, n2] += 1
+ v.extend([1, -1, -1, 1])
+ i.extend([n1, n1, n2, n2])
+ j.extend([n1, n2, n1, n2])
for n1 in numpy.nonzero(image_vert.reshape((n,)))[0]:
n2 = n1 + ys
- A[n1, n1] += 1
- A[n1, n2] -= 1
- A[n2, n1] -= 1
- A[n2, n2] += 1
+ v.extend([1, -1, -1, 1])
+ i.extend([n1, n1, n2, n2])
+ j.extend([n1, n2, n1, n2])
+v = numpy.array(v, numpy.int32)
+i = numpy.array(i, numpy.int32)
+j = numpy.array(j, numpy.int32)
+A = scipy.sparse.coo_array(
+ (v, (i, j)),
+ shape = (n, n),
+ dtype = numpy.int32
+).tocsr()
# partition nodes into 3 groups:
# 0: black + blue (electrode), 1: red (electrode), 2: white (conductor)
A11_V1 = numpy.sum(A11.astype(numpy.int32), 1)
A21_V1 = numpy.sum(A21.astype(numpy.int32), 1)
print('solve')
-V2 = numpy.linalg.solve(
+V2 = scipy.sparse.linalg.spsolve(
A22.astype(numpy.double),
-A21_V1.astype(numpy.double)
)