137 lines
3.0 KiB
Python
137 lines
3.0 KiB
Python
'''Pascal matrix generation'''
|
|
|
|
from functools import reduce
|
|
from itertools import chain
|
|
from operator import add
|
|
|
|
|
|
# pascalMatrix :: Int -> ((Int, Int) -> (Int, Int)) -> [[Int]]
|
|
def pascalMatrix(n):
|
|
'''Pascal S-, L-, or U- matrix of order n.
|
|
'''
|
|
return lambda f: chunksOf(n)(list(map(
|
|
compose(binomialCoefficent, f),
|
|
tupleRange((0, 0), (n, n))
|
|
)))
|
|
|
|
|
|
# binomialCoefficent :: (Int, Int) -> Int
|
|
def binomialCoefficent(nk):
|
|
'''The binomial coefficient of the tuple (n, k).
|
|
'''
|
|
n, k = nk
|
|
|
|
def go(a, x):
|
|
return a * (n - x + 1) // x
|
|
return reduce(go, enumFromTo(1)(k), 1)
|
|
|
|
|
|
# --------------------------TEST---------------------------
|
|
# main :: IO ()
|
|
def main():
|
|
'''Pascal S-, L-, and U- matrices of order 5.
|
|
'''
|
|
order = 5
|
|
for k, f in [
|
|
('Symmetric', lambda ab: (add(*ab), ab[1])),
|
|
('Lower', identity),
|
|
('Upper', swap)
|
|
]:
|
|
print(k + ':')
|
|
print(showMatrix(
|
|
pascalMatrix(order)(f)
|
|
))
|
|
print()
|
|
|
|
|
|
# --------------------REUSABLE GENERICS--------------------
|
|
|
|
# chunksOf :: Int -> [a] -> [[a]]
|
|
def chunksOf(n):
|
|
'''A series of lists of length n, subdividing the
|
|
contents of xs. Where the length of xs is not evenly
|
|
divible, the final list will be shorter than n.
|
|
'''
|
|
return lambda xs: reduce(
|
|
lambda a, i: a + [xs[i:n + i]],
|
|
range(0, len(xs), n), []
|
|
) if 0 < n else []
|
|
|
|
|
|
# compose :: ((a -> a), ...) -> (a -> a)
|
|
def compose(*fs):
|
|
'''Composition, from right to left,
|
|
of a series of functions.
|
|
'''
|
|
return lambda x: reduce(
|
|
lambda a, f: f(a),
|
|
fs[::-1], x
|
|
)
|
|
|
|
|
|
# enumFromTo :: Int -> Int -> [Int]
|
|
def enumFromTo(m):
|
|
'''Enumeration of integer values [m..n]'''
|
|
return lambda n: range(m, 1 + n)
|
|
|
|
|
|
# identity :: a -> a
|
|
def identity(x):
|
|
'''The identity function.'''
|
|
return x
|
|
|
|
|
|
# showMatrix :: [[Int]] -> String
|
|
def showMatrix(xs):
|
|
'''String representation of xs
|
|
as a matrix.
|
|
'''
|
|
def go():
|
|
rows = [[str(x) for x in row] for row in xs]
|
|
w = max(map(len, chain.from_iterable(rows)))
|
|
return unlines(
|
|
unwords(k.rjust(w, ' ') for k in row)
|
|
for row in rows
|
|
)
|
|
return go() if xs else ''
|
|
|
|
|
|
# swap :: (a, b) -> (b, a)
|
|
def swap(tpl):
|
|
'''The swapped components of a pair.'''
|
|
return tpl[1], tpl[0]
|
|
|
|
|
|
# tupleRange :: (Int, Int) -> (Int, Int) -> [(Int, Int)]
|
|
def tupleRange(lowerTuple, upperTuple):
|
|
'''Range of (Int, Int) tuples from
|
|
lowerTuple to upperTuple.
|
|
'''
|
|
l1, l2 = lowerTuple
|
|
u1, u2 = upperTuple
|
|
return [
|
|
(i1, i2) for i1 in range(l1, u1)
|
|
for i2 in range(l2, u2)
|
|
]
|
|
|
|
|
|
# unlines :: [String] -> String
|
|
def unlines(xs):
|
|
'''A single string formed by the intercalation
|
|
of a list of strings with the newline character.
|
|
'''
|
|
return '\n'.join(xs)
|
|
|
|
|
|
# unwords :: [String] -> String
|
|
def unwords(xs):
|
|
'''A space-separated string derived
|
|
from a list of words.
|
|
'''
|
|
return ' '.join(xs)
|
|
|
|
|
|
# MAIN ---
|
|
if __name__ == '__main__':
|
|
main()
|