     
     public var left: Matrix<R, n, n> {
         var Q = target.leftIdentity
-        for s in eliminationProcess {
-            switch s {
-            case .AddRow(_, _, _), .InvRow(_), .SwapRows(_, _):
-                s.applyTo(&Q)
-            default: ()
-            }
-        }
+        
+        eliminationProcess
+            .filter{ $0.isRowOperation }
+            .forEach { Q.apply($0) }
+        
         return Q
     }
     
     public var leftInverse: Matrix<R, n, n> {
         var Q = target.leftIdentity
-        for s in eliminationProcess.reversed() {
-            switch s {
-            case .AddRow(_, _, _), .InvRow(_), .SwapRows(_, _):
-                s.applyInverseTo(&Q)
-            default: ()
-            }
-        }
+        
+        eliminationProcess
+            .filter{ $0.isRowOperation }
+            .reversed()
+            .map { invert($0) }
+            .forEach{ Q.apply($0) }
+        
         return Q
     }
     
     public var right: Matrix<R, m, m> {
         var P = target.rightIdentity
-        for s in eliminationProcess {
-            switch s {
-            case .AddCol(_, _, _), .InvCol(_), .SwapCols(_, _):
-                s.applyTo(&P)
-            default: ()
-            }
-        }
+        
+        eliminationProcess
+            .filter{ $0.isColOperation }
+            .forEach { P.apply($0) }
+        
         return P
     }
     
     public var rightInverse: Matrix<R, m, m> {
         var P = target.rightIdentity
-        for s in eliminationProcess.reversed() {
-            switch s {
-            case .AddCol(_, _, _), .InvCol(_), .SwapCols(_, _):
-                s.applyInverseTo(&P)
-            default: ()
-            }
-        }
+        
+        eliminationProcess
+            .filter{ $0.isColOperation }
+            .reversed()
+            .map { invert($0) }
+            .forEach{ P.apply($0) }
+        
         return P
     }
     

    case ColsOnly
}

// abstract class

public class BaseMatrixElimination<R: Ring, n: _Int, m: _Int> {
    public let target: Matrix<R, n, m>
    public let mode: EliminationMode

            // TODO maybe implement NumberType or Comparable
            if R.self == IntegerNumber.self && (result[i0, j0] as! IntegerNumber) < 0 {
                if doRows {
                    self.apply(.MulRow(at: i0, by: -1))
                } else {
                    self.apply(.MulCol(at: j0, by: -1))
                }
            }
            
