packages feed

resistor-cube-0.0.1.1: src/Main.hs

{- |
Consider a cube of resistors of equal resistance.
What is the overall resistance from one corner to the opposite one?
-}
{-# LANGUAGE TypeOperators #-}
module Main where

import qualified Numeric.LAPACK.Matrix.Shape as MatrixShape
import qualified Numeric.LAPACK.Matrix.Triangular as Triangular
import qualified Numeric.LAPACK.Matrix as Matrix
import qualified Numeric.LAPACK.Vector as Vector
import Numeric.LAPACK.Matrix.Triangular ((#%%%#))
import Numeric.LAPACK.Matrix ((#\|))
import Numeric.LAPACK.Format ((##))

import qualified Data.Array.Comfort.Boxed as BoxedArray
import qualified Data.Array.Comfort.Storable as Array
import qualified Data.Array.Comfort.Shape as Shape
import Data.Array.Comfort.Storable ((!))
import Data.Array.Comfort.Shape ((:+:)((:+:)))


data Coord = C0 | C1 deriving (Eq, Ord, Show, Enum, Bounded)
data Dim = D0 | D1 | D2 deriving (Eq, Ord, Show, Enum, Bounded)
type Corner = (Coord,Coord,Coord)
type Edge = (Dim,Coord,Coord)

type ShapeEnum = Shape.Enumeration
type CornerShape = (ShapeEnum Coord, ShapeEnum Coord, ShapeEnum Coord)
type EdgeShape = (ShapeEnum Dim, ShapeEnum Coord, ShapeEnum Coord)

type Matrix height width = Matrix.General height width


cornerShape :: CornerShape
cornerShape = Shape.static

edgeShape :: EdgeShape
edgeShape = Shape.static


{-
We also need a currentMatrix that implements Kirchhoff's current law
but it turns out to equal 'transpose voltageMatrix'.
This makes fullMatrix symmetric.
-}
voltageMatrix :: Matrix EdgeShape CornerShape Double
voltageMatrix =
   Matrix.fromRowArray cornerShape $
   fmap
      (\e ->
         Array.fromAssociations 0 cornerShape
            [(edgeCorner e C0, 1), (edgeCorner e C1, -1)]) $
   BoxedArray.indices edgeShape

edgeCorner :: Edge -> Coord -> Corner
edgeCorner (ed,ex,ey) coord =
   case ed of
      D0 -> (coord,ex,ey)
      D1 -> (ex,coord,ey)
      D2 -> (ex,ey,coord)

sourceCorner, destCorner :: Corner
sourceCorner = (C0,C0,C0)
destCorner = (C1,C1,C1)

resistances :: Vector.Vector EdgeShape Double
resistances = Vector.one edgeShape


fullMatrix :: Triangular.Symmetric (():+:(EdgeShape:+:CornerShape)) Double
fullMatrix =
   let order = MatrixShape.RowMajor
       symmetricZero sh = Matrix.zero $ MatrixShape.symmetric order sh
       unit = Vector.unit (edgeShape:+:cornerShape) (Right sourceCorner)
   in (symmetricZero (), Matrix.singleRow order unit)
      #%%%#
      (Triangular.diagonal order resistances, voltageMatrix)
      #%%%#
      symmetricZero cornerShape


main :: IO ()
main = do
   fullMatrix ## "%2.f"
   let ix = Right (Right destCorner)
   let solutionVec = fullMatrix #\| Vector.unit (Triangular.size fullMatrix) ix
   print $ - solutionVec ! ix

{-
result: total resistance is 5/(2+2+2)
-}