A pascal matrix is a two-dimensional square matrix holding numbers from   Pascal's triangle,   also known as   binomial coefficients   and which can be shown as   nCr.

Shown below are truncated   5-by-5   matrices   M[i, j]   for   i,j   in range   0..4. 


A Pascal upper-triangular matrix that is populated with   jCi:

[[1, 1, 1, 1, 1],
 [0, 1, 2, 3, 4],
 [0, 0, 1, 3, 6],
 [0, 0, 0, 1, 4],
 [0, 0, 0, 0, 1]]

A Pascal lower-triangular matrix that is populated with   iCj   (the transpose of the upper-triangular matrix):

[[1, 0, 0, 0, 0],
 [1, 1, 0, 0, 0],
 [1, 2, 1, 0, 0],
 [1, 3, 3, 1, 0],
 [1, 4, 6, 4, 1]]

A Pascal symmetric matrix that is populated with   i+jCi:

[[1, 1, 1, 1, 1],
 [1, 2, 3, 4, 5],
 [1, 3, 6, 10, 15],
 [1, 4, 10, 20, 35],
 [1, 5, 15, 35, 70]]



Task

Write functions capable of generating each of the three forms of   n-by-n   matrices.

Use those functions to display upper, lower, and symmetric Pascal   5-by-5   matrices on this page.

The output should distinguish between different matrices and the rows of each matrix   (no showing a list of 25 numbers assuming the reader should split it into rows).



Note
 
The   Cholesky decomposition   of a Pascal symmetric matrix is the Pascal lower-triangle matrix of the same size.




defmodule Pascal do
  defp ij(n), do: for i <- 1..n, j <- 1..n, do: {i,j}
 
  def upper_triangle(n) do
    Enum.reduce(ij(n), Map.new, fn {i,j},acc ->
      val = cond do
              i==1 -> 1
              j<i  -> 0
              true -> Map.get(acc, {i-1, j-1}) + Map.get(acc, {i, j-1})
            end
      Map.put(acc, {i,j}, val)
    end) |> print(1..n)
  end
 
  def lower_triangle(n) do
    Enum.reduce(ij(n), Map.new, fn {i,j},acc ->
      val = cond do
              j==1 -> 1
              i<j  -> 0
              true -> Map.get(acc, {i-1, j-1}) + Map.get(acc, {i-1, j})
            end
      Map.put(acc, {i,j}, val)
    end) |> print(1..n)
  end
 
  def symmetic_triangle(n) do
    Enum.reduce(ij(n), Map.new, fn {i,j},acc ->
      val = if i==1 or j==1, do: 1,
                           else: Map.get(acc, {i-1, j}) + Map.get(acc, {i, j-1})
      Map.put(acc, {i,j}, val)
    end) |> print(1..n)
  end
 
  def print(matrix, range) do
    Enum.each(range, fn i ->
      Enum.map(range, fn j -> Map.get(matrix, {i,j}) end) |> IO.inspect
    end)
  end
end
 
IO.puts "Pascal upper-triangular matrix:"
Pascal.upper_triangle(5)
IO.puts "Pascal lower-triangular matrix:"
Pascal.lower_triangle(5)
IO.puts "Pascal symmetric matrix:"
Pascal.symmetic_triangle(5)