     }
     
     var description: String {
-        return ""
+        return DMatrix(self).description
+    }
+    
+    var detailDescription: String {
+        return DMatrix(self).detailDescription
     }
 }
 

    }
    
    @_specialize(where R == ComputationSpecializedRing)
    private static func mergeRows(_ row0: [(Int, R)], _ row1: [(Int, R)]) -> [(Int, R)]? {
        switch (row0.isEmpty, row1.isEmpty) {
        case (true,  true): return nil
        case (false, true): return row0
        case (true, false): return row1
        default: ()
        }
        
        var result: [(Int, R)] = []
        
        let (n0, n1) = (row0.count, row1.count)
        var (p0, p1) = (UnsafePointer(row0), UnsafePointer(row1))
        var (k0, k1) = (0, 0) // counters
        
        while k0 < n0 && k1 < n1 {
            let (j0, a0) = p0.pointee
            let (j1, a1) = p1.pointee
            
            if j0 == j1 {
                result.append((j0, a0 + a1))
                
                p0 += 1
                p1 += 1
                k0 += 1
                k1 += 1
                
            } else if j0 < j1 {
                result.append((j0, a0))
                
                p0 += 1
                k0 += 1
                
            } else if j0 > j1 {
                result.append( (j1, a1) )
                
                p1 += 1
                k1 += 1
            }
        }
        
        for _ in k0 ..< n0 {
            let (j0, a0) = p0.pointee
            result.append((j0, a0))
            
            p0 += 1
            k0 += 1
        }
        
        for _ in k1 ..< n1 {
            let (j1, a1) = p1.pointee
            result.append((j1, a1))
            
            p1 += 1
            k1 += 1
        }
        
        result = result.filter{ $0.1 != .zero }
        return !result.isEmpty ? result : nil
    }
    

    func multiplyRow(at i0: Int, by r: R) {
        switchAlignment(.horizontal)
        
        guard let row = table[i0] else {
            return
        }
        table[i0] = mergeRows(row, [], { (a, _) in r * a })
    }
    
    @_specialize(where R == ComputationSpecializedRing)
    func addRow(at i0: Int, to i1: Int, multipliedBy r: R = .identity) {
        switchAlignment(.horizontal)
        
        let row0 = table[i0] ?? []
        let row1 = table[i1] ?? []
        
        let merged = mergeRows(row0, row1, { r * $0 + $1 })
        table[i1] = merged
    }
    
    func swapRows(_ i0: Int, _ i1: Int) {
