{-# LANGUAGE DataKinds #-}
{-|
Module: CSA
Description: Connectivity description using connection-set algebra
License: MIT
Maintainer: jensegholm@protonmail.com
Stability: experimental
This module uses connection-set algebra to describe connectivity between
two entities with a scalar ('Double') value. The library build on the concept
of M. Djurfeldt's Connection-Set Algebar [1].
The connection expressions can be compiled to a dependently typed
'AdjacencyMatrix' from the "Numeric.LinearAlgebra.Static" package. Such
a matrix can be used and exported as a regular n-dimensional vector.
Usage:
>>> toAdjacencyMatrix None :: L 2 2
(matrix
[ 0.0, 0.0
, 0.0, 0.0 ] :: L 2 2)
>>> toAdjacencyMatrix $ Minus (AllToAll 2) (OneToOne 1) :: L 2 2
(matrix
[ 1.0, 2.0
, 2.0, 1.0 ] :: L 2 2)
1: Mikael Djurfeldt. The Connection-set Algebra: a formalism for the
representation of connectivity structure in neuronal network models,
implementations in Python and C++, and their use in simulators,
BMC Neuroscience, 2011. https://doi.org/10.1186/1471-2202-12-S1-P80
-}
module CSA where
import GHC.TypeLits
import Numeric.LinearAlgebra.Static
-- | An adjacency matrix describing connections in a directed graph
type AdjacencyMatrix = L
-- | An expression algebra tree (AST) that describes connections
-- between two elements
data Expr
= None -- ^ An empty connection (only 0s)
| AllToAll ℝ -- ^ Full connectivity with the given value
| OneToOne ℝ -- ^ One-to-one (diagonally) connectivity
| Mask (ℝ -> ℝ -> ℝ) -- ^ A masked connectivity given by a function
| Plus Expr Expr -- ^ Addition of two connectivity expressions
| Minus Expr Expr -- ^ Subtraction of two connectivity expressions
-- | Converts an expression to an adjacency matrix by unrolling the
-- expression tree from left to right
toAdjacencyMatrix
:: (KnownNat m, KnownNat n) => Expr -- ^ The expression to turn into a 'AdjacencyMatrix'
-> AdjacencyMatrix m n -- ^ The resulting adjacency matrix
toAdjacencyMatrix expr = case expr of
None -> build (\_ _ -> 0)
Mask f -> build f
OneToOne v -> build (\x y -> if x == y then v else 0)
AllToAll v -> build (\_ _ -> v)
Plus left right -> (+) (toAdjacencyMatrix left) (toAdjacencyMatrix right)
Minus left right -> (-) (toAdjacencyMatrix left) (toAdjacencyMatrix right)