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

        }
        
        log("assertion complete.")
    }
    
    public var contractedChainComplex: ChainComplex<Simplex, R> {
        typealias CC = ChainComplex<S, R>
        let chain = K.validDims.map{ (i) -> (CC.ChainBasis, CC.BoundaryMap) in
            
            let from = generators.filter { s in s.dim == i }
            let map  = CC.BoundaryMap { s in self.diff[s] ?? C.zero }
            return (from, map)
        }
        
        return CC(name: K.name, chain)
    }
    
    public var contractedCochainComplex: CochainComplex<Dual<Simplex>, R> {
        typealias CC = CochainComplex<Dual<S>, R>
        let chain = K.validDims.map{ (i) -> (CC.ChainBasis, CC.BoundaryMap) in
            let from = generators.filter { s in s.dim == i }
            let map  = CC.BoundaryMap { d in
                let s = d.base
                let e = R(intValue: (-1).pow(d.degree + 1))
                let to = self.generators.filter { s in s.dim == i + 1 }
                let vals = to.flatMap { t -> (Dual<S>, R)? in
                    let a = self.diff[t]?[s] ?? R.zero
                    return (a != R.zero) ? (Dual(t), e * a) : nil
                }
                return SimplicialCochain(vals)
            }
            return (from.map{ Dual($0) }, map)
        }
        
        return CC(name: K.name, chain)
    }
    
    public var homologyGroup: Homology<Simplex, R> {
        let H = Homology(contractedChainComplex)
        let map = ChainMap { s in self.g(s) }
        
        // factorize by: z -> f(z) -> [r]
        
        let factorizer = { (z: C) -> [R] in
            if z == C.zero {
                return []
            }
            let i = z.anyElement!.0.degree
            return H[i].structure.factorize( self.f(z) )
        }
        return Homology(name: K.name, H, map, factorizer)
    }
    
    public var cohomologyGroup: Cohomology<Dual<Simplex>, R> {
        let H = Cohomology(contractedCochainComplex)
        let C = ChainComplex(K, R.self)
        let map = ChainMap { s in self.f(s) }.dualMap(domainChainComplex: C)
        
        // factorize by: c -> g^*(c) -> [r]

        let factorizer = { (c: SimplicialCochain<R>) -> [R] in
            if c == .zero {
                return []
            }
            let i = c.anyElement!.0.degree
            let basis = self.generators.filter{ $0.degree == i }
            
            // express cocycle as: (g^*)c = Σ c(g(s)) s^*
            
            let values = basis.flatMap { s -> (Dual<S>, R)? in
                let a = c.evaluate(self.g(s))
                return (a != .zero) ? (Dual(s), a) : nil
            }
            let cocycle = SimplicialCochain<R>(values)
            
            return H[i].structure.factorize( cocycle )
        }
        return Cohomology(name: K.name, H, map, factorizer)
    }
    
    internal class Node: Hashable, CustomStringConvertible {

        }
        
        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
