def simplexInCenter(vs):
    print "        in simplexInCenter"
    n = len(vs)
    nDims = len(vs[0])

    # 5 points in 2 dims is hopeless
    if n >= nDims+3:
        print "            hopeless!"
        print "        out simplexInCenter"
        return None

    weights = []
    for i in xrange(n):
        oppositeFacet = Mat([vs[j] for j in xrange(n) if j != i])
        #do('oppositeFacet')
        M = Mat([v-oppositeFacet[0] for v in oppositeFacet[1:]])
        #do('M')
        M2 = M * M.transposed()
        #do('M2')
        det = M2.det()
        #do('det')
        oppositeFacetContent = sqrt(det)
        weights.append(oppositeFacetContent)
    weights = Vec(weights)
    weights /= sum(weights)
    answer = Vec(weights) * Mat(vs)
    do('answer')
    print "        out simplexInCenter"
    return answer
class HyperbolicIsometry:

    @staticmethod
    def identity(nDims):
        return HyperbolicIsometry(Mat.identity(nDims), [0]*nDims)

    def __init__(self,R=None,t=None):
        # R and t can't both be None, or we wouldn't know the dimension
        if R == None: R = Mat.identity(len(t))
        if t == None: t = [0]*len(R)
        self.R = Mat(R)
        self.t = Vec(t)
    def apply(self,p):
        return translate(p * self.R, self.t)
    def applyInverse(self,p):
        return self.R * translate(p,-self.t) # R * p = p * R^-1 since R is orthogonal
    # Return f such that for all p,
    # f(p) = rhs(self(p))
    def compose(self,rhs):
        lhs = self
        nDims = len(self.t)
        t = rhs.apply(self.t) # = rhs(lhs(0))
        if True:
            R = Mat.identity(nDims)
            for i in xrange(nDims):
                R[i] = translate(rhs.apply(lhs.apply(R[i])), -t) # R[i] = Isometry(I,t)^-1(rhs(lhs(I[i])))
            R = Mat(R)
        else:
            # Argh, I thought this was right, but it's not?? wtf?
            R = self.R * rhs.R
        return HyperbolicIsometry(R,t)
    def inverse(self):
        return HyperbolicIsometry(None,-self.t).compose(HyperbolicIsometry(self.R.transposed(),None))
    def dist2(self,rhs):
        return (rhs.R-self.R).length2() + (rhs.t-self.t).length2()
    def __repr__(self):
        return 'HyperbolicIsometry('+`self.R`+','+`self.t`+')'
    def __str__(self):
        return self.__repr__()

    #
    # Operator notation:
    #    f(p) = f.apply(p)
    #     p*f = f.apply(p)
    #   f0*f1 = f0.compose(f1)
    # note that
    #     (f0*f1)*f2 == f0*(f1*f2)
    # and  (p*f0)*f1 == p*(f0*f1)
    #
    def __call__(self,p):
        return self.apply(p)
    def __rmul__(self,lhs):
        # actually relies on fact that Vec's __mul__
        # explicitly calls rhs.__rmul__ when rhs is unrecognized type
        return self.apply(lhs)
    def __mul__(self,rhs):
        return self.compose(rhs)
    def __pow__(self,rhs):
        assert type(rhs) == int
        if rhs == -1: # most common case
            return self.inverse()
        if rhs < 0:
            # either of the following work
            if True:
                return (self^-rhs).inverse()
            else:
                return self.inverse()^-rhs
        if rhs > 1:
            return self**int(rhs/2) * self**(rhs-int(rhs/2))
        if rhs == 1:
            return self
        assert rhs == 0
        return HyperbolicIsometry.identity(len(self.t))
    # XXX TODO: I think this is a bad idea, since ^ binds looser than * and even +
    def __xor__(self,rhs):
        return self.__pow__(rhs)