         
         allDone = true
         
-        log("")
-        log("generators:")
-        log(generators.map{ "\t\($0.dim): \($0)"}.joined(separator: ",\n"))
-        
-        if !relations.isEmpty {
+        if debug {
             log("")
-            log("relations:")
-            log(relations.map { "\t\($0.anyElement!.0.dim): \($0)"}.joined(separator: ",\n"))
-        }
-        log("")
+            log("generators:")
+            log(generators.map{ "\t\($0.dim): \($0)"}.joined(separator: ",\n"))
+            
+            if !relations.isEmpty {
+                log("")
+                log("relations:")
+                log(relations.map { "\t\($0.anyElement!.0.dim): \($0)"}.joined(separator: ",\n"))
+            }
+            log("")
+            
+            assertChainContraction()
+        }
     }
     
     @_specialize(where R == ComputationSpecializedRing)

        let bs = C(s).boundary()
        let f_bs = f(bs)
        
        log("\(step)\t\(s): f∂ = \(f_bs)")
        log("")
        
        if isZero(f_bs) {

        }
        
        func collect(flatten: Bool = false) -> C {
            if refs.isEmpty {
                return self.value
            }
            
            var basket = [Node : R]()
            let value = _collect(1, &basket)
            
            assert(basket.forAll{ $0.value == R.zero }, "invalid: \(basket)")
            
            if flatten {
                self.value = value
