Nick Slavsky Nick Slavsky - 6 months ago 31
Python Question

An elegant, readable way to read Butcher tableau from a file

I'm trying to read a specifically formatted file (namely, the Butcher tableau) in python 3.5.
The file looks like this(tab separated):

S
a1 b11 b12 ... b1S
a2 b21 b22 ... b2S
...
aS bS1 bS2 ... bSS
0.0 c1 c2 ... cS
[tolerance]


for example, (tab separated)

2
0.0 0.0 0.0
1.0 0.5 0.5
0.0 0.5 0.5
0.0001


So my code looks like i'm writing in C. Is there a more pythonic approach to parsing this file? Maybe there are numpy methods that could be used here?

#the data from .dat file
S = 0 #method order, first char in .dat file
a = [] #S-dim left column of buther tableau
b = [] #S-dim matrix
c = [] #S-dim lower row
tolerance = 0 # for implicit methods

def parse_method(file_name):
'read the file_name, process lines, produce a Method object'
try:
with open('methods\\' + file_name) as file:
global S
S = int(next(file))
temp = []
for line in file:
temp.append([float(x) for x in line.replace('\n', '').split('\t')])
for i in range(S):
a.append(temp[i].pop(0))
b.append(temp[i])
global c
c = temp[S][1:]
global tolerance
tolerance = temp[-1][0] if len(temp)>S+1 else 0
except OSError as ioerror:
print('File Error: ' + str(ioerror))

Answer

My suggestion using Numpy:

import numpy as np

def read_butcher(filename):
    with open(filename, 'rb') as fh:
        S = int(fh.readline())
        array = np.fromfile(fh, float, (S+1)**2, b'\t')
        rest = fh.read().strip()

    array.shape = (S+1, S+1)
    a = array[:-1,  0]
    b = array[:-1, 1:]
    c = array[ -1, 1:]
    tolerance = float(rest) if rest else 0.0

    return a, b, c, tolerance

Although I'm not entirely sure how consistently numpy.fromfile advances the file pointer... There are no guarantees in the documentation.

Handling of file exceptions should probably be done outside of the parsing method.