     }
     
     public static func == (a: Self, b: Self) -> Bool {
+        assert((a.rows, a.cols) == (b.rows, b.cols), "Mismatching matrix size.")
         return a.grid == b.grid
     }
     
     public static func + (a: Self, b: Self) -> Self {
+        assert((a.rows, a.cols) == (b.rows, b.cols), "Mismatching matrix size.")
         return Self(rows: a.rows, cols: a.cols) { (i, j) -> R in
             return a[i, j] + b[i, j]
         }

        }
    }
    
    public static func - (a: Self, b: Self) -> Self {
        return Self(rows: a.rows, cols: a.cols) { (i, j) -> R in
            return a[i, j] - b[i, j]
        }
    }
    
    public static func * (r: R, a: Self) -> Self {
        return Self(rows: a.rows, cols: a.cols) { (i, j) -> R in
            return r * a[i, j]

    public var grid: [R]
    
    // root initializer
    public init(rows r: Int = Auto, cols c: Int = Auto, grid: [R]) {
        let (rows, cols) = Matrix.determineSize(r, c, grid)
        
        self.rows = rows
        self.cols = cols
        
        let (l, required) = (grid.count, rows * cols)
        self.grid = (l == required) ? grid :
                    (l >  required) ? Array(grid[0 ..< required]) :
                                      (grid + Array(repeating: R.zero, count: required - l))
    }
    
    public init(rows r: Int = Auto, cols c: Int = Auto, gridGenerator g: (Int, Int) -> R) {
        let (rows, cols) = Matrix.determineSize(r, c, nil)
        
        let grid = (0 ..< rows * cols).map { (index: Int) -> R in
            let (i, j) = index /% cols
            return g(i, j)
        }
        
        self.rows = rows
        self.cols = cols
        self.grid = grid
    }

    public init(_ grid: R...) {
        self.init(rows: Auto, cols: Auto, grid: grid)
    }
    
    private static func determineSize(_ rows: Int, _ cols: Int, _ grid: [R]?) -> (rows: Int, cols: Int) {
        func ceilDiv(_ a: Int, _ b: Int) -> Int {
            return (a + b - 1) / b
        }
        
        switch(Rows.self, Cols.self) {
            
        // completely determined by type.
        case let (R, C) where !(R is Dynamic.Type) && !(C is Dynamic.Type):
            assert(rows == Auto || rows == R.intValue, "rows mismatch with type-parameter: \(rows) != \(R.intValue)")
            assert(cols == Auto || cols == C.intValue, "cols mismatch with type-parameter: \(cols) != \(C.intValue)")
            return (R.intValue, C.intValue)
            
        // rows is determined by type.
        case let (R, C) where !(R is Dynamic.Type) && (C is Dynamic.Type):
            assert(rows == Auto || rows == R.intValue, "rows mismatch with type-parameter: \(rows) != \(R.intValue)")
            let r = R.intValue
            switch (cols, grid) {
            case let (c, _) where c != Auto:
                return (r, c)
            case let (c, g?) where r > 0 && c == Auto:
                return (r, ceilDiv(g.count, r))
            default:
                fatalError("Matrix size indeterminable.")
            }
            
        // cols is determined by type.
        case let (R, C) where (R is Dynamic.Type) && !(C is Dynamic.Type):
            assert(cols == Auto || cols == C.intValue, "cols mismatch with type-parameter: \(cols) != \(C.intValue)")
            let c = C.intValue
            switch (rows, grid) {
            case let (r, _) where r != Auto:
                return (r, c)
            case let (r, g?) where r == Auto && c > 0:
                return (ceilDiv(g.count, c), c)
            default:
                fatalError("Matrix size indeterminable.")
            }
            
        // rows, cols are dynamic.
        case let (R, C) where  (R is Dynamic.Type) &&  (C is Dynamic.Type):
            switch (rows, cols, grid) {
            case let (r, c, _) where r != Auto && c != Auto:
                return (r, c)
            case let (r, _, g?) where r != Auto && r > 0:
                return (r, ceilDiv(g.count, r))
            case let (_, c, g?) where c != Auto && c > 0:
                return (ceilDiv(g.count, c), c)
            default:
                fatalError("Matrix size indeterminable.")
            }
            
        default:
            fatalError()
        }
    }
}

