add error handling & numpy to readme
[matrixnullspace.com.git] / matrix.py
1 import cgi
2 from scipy import compress, transpose
3 from scipy.linalg import svd, det
4 import json
5
6 def calculate_nullspace(A, eps=1e-15):
7 u, s, vh = svd(A)
8 null_mask = (s <= eps)
9 null_space = compress(null_mask, vh, axis=0)
10 return transpose(null_space)
11
12 def calculate_eigenvalues(A, eps=1e-15):
13 u, s, vh = svd(A)
14 return s
15
16 def fail(start_response, message):
17 start_response('400 Bad Request', [])
18 return 'error: ' + message
19
20 def application(environ, start_response):
21 parameters = cgi.parse_qs(environ.get('QUERY_STRING'))
22
23 if not 'matrix' in parameters or parameters['matrix'] == '':
24 return fail(start_response, 'missing matrix')
25 query_string = str(parameters['matrix'][0])
26 matrix = query_string.splitlines()
27 for index, row in enumerate(matrix):
28 matrix[index] = row.split()
29 if len(matrix[index]) != len(matrix[0]):
30 return fail(start_response, 'ragged matrix')
31 for index, n in enumerate(matrix[index]):
32 try: float(n)
33 except ValueError:
34 return fail(start_response, 'invalid matrix element')
35
36 while len(matrix) < len(matrix[0]):
37 matrix.append([0]*len(matrix[0]))
38
39 nullspace = calculate_nullspace(matrix)
40 if nullspace.max() != 0:
41 nullspace = nullspace / nullspace.max()
42
43 eigenvalues = calculate_eigenvalues(matrix)
44 determinant = det(matrix)
45
46 output = json.dumps({
47 'nullspace' : str(nullspace),
48 'eigenvalues' : str(eigenvalues),
49 'determinant' : str(determinant)
50 })
51
52 output_len = sum(len(line) for line in output)
53 start_response('200 OK', [('Content-type', 'application/json'),
54 ('Content-Length', str(output_len))])
55 return output