class Unique(object): def __init__(self,name): self.name = name def __str__(self): return self.name def __repr__(self): return "Unique(\"%s\")" % self.name class Idealized(object): UNION = ["UNION"] def __init__(self, R, idealMap = 0, vars = {}): self.varnames = vars if not isinstance(idealMap,dict): idealMap = {()*R:idealMap} self.idealMap = idealMap self.R = R self._sqrt = None self._isqrt = None @staticmethod def uvar(x): return Idealized.var(Unique(x)) @staticmethod def var(x): name = str(x) R = PolynomialRing(QQ,[name]) rx = R.gens()[0] return Idealized(R,rx,{x:(name,rx)}) @staticmethod def vars(xs): return tuple((Idealized.var(x) for x in xs)) @staticmethod def uvars(xs): return tuple((Idealized.uvar(x) for x in xs)) def __str__(self): def rep(I,x): x = str(x) gs = I.gens() gs = [g for g in gs if g != 0] if len(gs) == 0: return x else: g = ", ".join(["(%s)" % str(gen) for gen in gs]) return g + ": " + x return "\n".join([rep(I,self.idealMap[I]) for I in self.idealMap]) def __repr__(self): # HACK! if len(self.idealMap) == 0: return "undef" if len(self.idealMap) > 1: return str(self) for _,v in self.idealMap.iteritems(): return str(v) def prune(self): self.idealMap = {I:v for I,v in self.idealMap.iteritems() if not (I*self.R).is_one()} return self def __add__(self,other): def f(x,y): return x+y return self.op(other,f) def __radd__(self,other): def f(x,y): return y+x return self.op(other,f) def __rsub__(self,other): def f(x,y): return y-x return self.op(other,f) def __neg__(self): def f(x,y): return y-x return self.op(0,f) def __sub__(self,other): def f(x,y): return x-y return self.op(other,f) def is_square(self): for _,v in self.idealMap.iteritems(): if not is_square(v): return False return True def sqrt(self): if self._sqrt is None: s = Idealized.uvar("s") self._sqrt = s.assuming(s^2 - self) return self._sqrt def isqrt(self): if self._isqrt is None: s = Idealized.uvar("s") z = Idealized(0).assuming(Self) self._isqrt = s.assuming(s^2*self-1).union(z) return self._isqrt def __mul__(self,other): def f(x,y): return x*y return self.op(other,f) def __rmul__(self,other): def f(x,y): return y*x return self.op(other,f) def __pow__(self,n): if n < 0: return 1/self^(-n) if n == 0: return 1 if n == 1: return self if is_even(n): return (self*self)^(n//2) if is_odd(n): return (self*self)^(n//2) * self def __div__(self,other): def f(x,y): return x/y return self.op(other,f) def __rdiv__(self,other): def f(x,y): return y/x return self.op(other,f) def union(self,other): return self.op(other,Idealized.UNION) def __eq__(self,other): return (self - other).is_zero() def __ne__(self,other): return not (self==other) def __hash__(self): return 0 def assume_zero(self): out = {} for I,J in self.idealMap.iteritems(): IJ = I+J.numerator() if IJ.is_one(): continue out[IJ] = self.R(0) if len(out) == 0: raise Exception("Inconsistent assumption") return Idealized(self.R,out,self.varnames) def assuming(self,other): return self + other.assume_zero() def is_zero(self): for I,v in self.idealMap.iteritems(): if v.denominator() in I: return False if v.numerator() not in I: return False return True def op(self,other,f): if not isinstance(other,Idealized): other = Idealized(self.R,other,self.varnames) bad = False for v in self.varnames: if v not in other.varnames or self.varnames[v] != other.varnames[v]: bad = True break for v in other.varnames: if v not in self.varnames or self.varnames[v] != other.varnames[v]: bad = True break if bad: def incrVar(v): if v[-1] not in "0123456789": return v + "1" elif v[-1] == 9: return incrVar(v[:-1]) + "0" else: return v[:-1] + str(int(v[-1])+1) vars = {} names = set() for v,(name,_) in self.varnames.iteritems(): assert(name not in names) names.add(name) vars[v] = name subMe = {n:n for n in names} subThem = {} for v,(name,_) in other.varnames.iteritems(): if v in self.varnames: subThem[name] = self.varnames[v][0] else: oname = name while name in names: name = incrVar(name) names.add(name) subThem[oname] = name vars[v] = name R = PolynomialRing(QQ,sorted(list(names)),order="degrevlex") gd = R.gens_dict() subMe = {m:gd[n] for m,n in subMe.iteritems()} subThem = {m:gd[n] for m,n in subThem.iteritems()} vars = {v:(n,gd[n]) for v,n in vars.iteritems()} def subIdeal(I,sub): return [g(**sub) for g in I.gens()]*R idealMe = {subIdeal(I,subMe):v(**subMe) for I,v in self.idealMap.iteritems()} idealThem = {subIdeal(I,subThem):v(**subThem) for I,v in other.idealMap.iteritems()} else: R = self.R idealMe = self.idealMap idealThem = other.idealMap vars = self.varnames def consist(I,x,y): if (x-y).numerator() not in I: raise Exception("Inconsistent: %s != %s in ideal %s" % (str(x),str(y),str(I))) out = {} if f is Idealized.UNION: for I,v in idealMe.iteritems(): if I in idealThem: consist(I,v,idealThem[I]) out[I] = v for I,v in idealThem.iteritems(): if I in idealMe: consist(I,v,idealMe[I]) out[I] = v else: for I,v in idealMe.iteritems(): if I in idealThem: x = f(v,idealThem[I]) if I in out: consist(I,x,out[I]) else: out[I] = x else: for J,w in idealThem.iteritems(): IJ = I+J if not IJ.is_one(): x = f(v,w) if IJ in out: consist(IJ,x,out[IJ]) else: out[IJ] = x def gb(I): II = [0]*R for g in I.gens(): if g not in II: II = II+[g]*R return II def red(I,v): if I.is_zero(): return v return I.reduce(R(v.numerator())) / I.reduce(R(v.denominator())) out = {gb(I):v for I,v in out.iteritems()} out = {I:red(I,v) for I,v in out.iteritems()} return Idealized(R,out,vars) def reduce(self): def red(I,v): if I.is_zero(): return v return I.reduce(R(v.numerator())) / I.reduce(R(v.denominator())) out = {I:red(I,v) for I,v in self.idealMap.iteritems()} return Idealized(self.R,out,self.vars) Idealized.INF = Idealized.uvar("inf") Idealized.ZOZ = Idealized.uvar("zoz")