| dmitriy@138 | 1 | #!/usr/bin/env python |
| dmitriy@138 | 2 | |
| dmitriy@138 | 3 | from cvxopt import spmatrix, matrix |
| dmitriy@138 | 4 | from cvxopt.blas import copy |
| dmitriy@138 | 5 | from lsqr import lsqr |
| dmitriy@138 | 6 | from sys import argv, exit |
| dmitriy@138 | 7 | import os.path |
| dmitriy@138 | 8 | |
| dmitriy@186 | 9 | def smooth(boundary_list, cocycle_list): |
| dmitriy@138 | 10 | dimension = max((max(d[1], d[2]) for d in boundary_list)) |
| dmitriy@138 | 11 | dimension += 1 |
| dmitriy@138 | 12 | |
| dmitriy@138 | 13 | # NB: D is a coboundary matrix; 1 and 2 below are transposed |
| dmitriy@138 | 14 | D = spmatrix([d[0] for d in boundary_list], |
| dmitriy@138 | 15 | [d[2] for d in boundary_list], |
| dmitriy@138 | 16 | [d[1] for d in boundary_list], (dimension, dimension)) |
| dmitriy@138 | 17 | |
| dmitriy@138 | 18 | |
| dmitriy@138 | 19 | z = spmatrix([zz[0] for zz in cocycle_list], |
| dmitriy@138 | 20 | [zz[1] for zz in cocycle_list], |
| dmitriy@138 | 21 | [0 for zz in cocycle_list], (dimension, 1)) |
| dmitriy@138 | 22 | |
| dmitriy@138 | 23 | v1 = D * z |
| dmitriy@138 | 24 | # print "D^2 is zero:", not bool(D*D) |
| dmitriy@138 | 25 | # print "D*z is zero:", not bool(v1) |
| dmitriy@138 | 26 | z = matrix(z) |
| dmitriy@138 | 27 | |
| dmitriy@138 | 28 | def Dfun(x,y,trans = 'N'): |
| dmitriy@138 | 29 | if trans == 'N': |
| dmitriy@138 | 30 | copy(D * x, y) |
| dmitriy@138 | 31 | elif trans == 'T': |
| dmitriy@138 | 32 | copy(D.T * x, y) |
| dmitriy@138 | 33 | else: |
| dmitriy@138 | 34 | assert False, "Unexpected trans parameter" |
| dmitriy@138 | 35 | |
| dmitriy@138 | 36 | tol = 1e-10 |
| dmitriy@138 | 37 | show = False |
| dmitriy@138 | 38 | maxit = None |
| dmitriy@138 | 39 | solution = lsqr(Dfun, matrix(z), show = show, atol = tol, btol = tol, itnlim = maxit) |
| dmitriy@138 | 40 | |
| dmitriy@138 | 41 | v = z - D*solution[0] |
| dmitriy@138 | 42 | |
| dmitriy@138 | 43 | # print sum(v**2) |
| dmitriy@138 | 44 | # assert sum((D*v)**2) < tol and sum((D.T*v)**2) < tol, "Expected a harmonic cocycle" |
| dmitriy@138 | 45 | if not (sum((D*v)**2) < tol and sum((D.T*v)**2) < tol): |
| dmitriy@138 | 46 | print "Expected a harmonic cocycle:", sum((D*v)**2), sum((D.T*v)**2) |
| dmitriy@138 | 47 | |
| dmitriy@190 | 48 | return solution[0], v |
| dmitriy@186 | 49 | |
| dmitriy@186 | 50 | |
| dmitriy@186 | 51 | def vertex_values(solution, vertices): |
| dmitriy@138 | 52 | values = [None]*len(vertices) |
| dmitriy@165 | 53 | for i,v in vertices: |
| dmitriy@186 | 54 | values[v] = solution[i] |
| dmitriy@138 | 55 | return values |
| dmitriy@186 | 56 | |
| dmitriy@138 | 57 | |
| dmitriy@146 | 58 | def read_list_file(filename): |
| dmitriy@146 | 59 | list = [] |
| dmitriy@146 | 60 | with open(filename) as fp: |
| dmitriy@146 | 61 | for line in fp.xreadlines(): |
| dmitriy@146 | 62 | if line.startswith('#'): continue |
| dmitriy@146 | 63 | list.append(map(int, line.split())) |
| dmitriy@146 | 64 | return list |
| dmitriy@146 | 65 | |
| dmitriy@146 | 66 | |
| dmitriy@138 | 67 | if __name__ == '__main__': |
| dmitriy@138 | 68 | if len(argv) < 4: |
| dmitriy@138 | 69 | print "Usage: %s BOUNDARY COCYCLE VERTEXMAP" % argv[0] |
| dmitriy@138 | 70 | exit() |
| dmitriy@138 | 71 | |
| dmitriy@138 | 72 | boundary_filename = argv[1] |
| dmitriy@138 | 73 | cocycle_filename = argv[2] |
| dmitriy@138 | 74 | vertexmap_filename = argv[3] |
| dmitriy@146 | 75 | |
| dmitriy@146 | 76 | boundary_list = read_list_file(boundary_filename) |
| dmitriy@146 | 77 | cocycle_list = read_list_file(cocycle_filename) |
| dmitriy@146 | 78 | vertexmap_list = read_list_file(vertexmap_filename) |
| dmitriy@146 | 79 | |
| dmitriy@190 | 80 | solution, v = smooth(boundary_list, cocycle_list) |
| dmitriy@186 | 81 | values = vertex_values(solution, vertexmap_list) |
| dmitriy@138 | 82 | |
| dmitriy@138 | 83 | outfn = os.path.splitext(cocycle_filename)[0] + '.val' |
| dmitriy@138 | 84 | with open(outfn, 'w') as f: |
| dmitriy@138 | 85 | for i,v in enumerate(values): |
| dmitriy@138 | 86 | f.write('%d %f\n' % (i,v)) |