def nontrivial_degrees(self, reg): if reg is None: reg = region() ans = [] for (i, e, s) in list(self._domain._gb.keys()): r = region(t=i, e=e, s=s) if reg.contains(r): ans.append(r) return ans
def __classcall_private__(cls, other, **kwargs): dct = {"i": 0, "e": 0, "s": 0} dct.update(kwargs) reg = region(**dct) if region(t=0, e=0, s=0).contains(reg): return other noff = other._off + reg return YacopGrading_SuspendedObjects(other._other, t=noff.tmin, e=noff.emin, s=noff.smin)
def _test_element_grading(self, tester=None, **options): tester = self._tester(tester=tester, **options) par = self.parent() for (deg, elem) in self.homogeneous_decomposition().items(): tester.assertTrue( not elem == par.zero(), LazyFormat("zeroes in homogeneous_decomposition of %s") % (self,), ) try: t, e, s = elem.t, elem.e, elem.s except: tester.assertTrue( False, LazyFormat("element %s of %s does not have t,e,s attributes") % (self, par), ) reg = region(t=t, e=e, s=s) gb = par.graded_basis(reg) tester.assertTrue( len(gb) > 0, LazyFormat("graded basis of %s in %s empty, should contain %s") % (par, reg, elem), ) gbm = set.union(*[set(x.monomials()) for x in gb]) for m in elem.monomials(): tester.assertTrue( m in gbm, LazyFormat( "element %s of degree (%d,%d,%d) not in graded_basis of its degree" ) % (m, t, e, s), ) for (toff, eoff, soff) in [ (1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1), ]: rg = region(t=t + toff, e=e + eoff, s=s + soff) gb = par.graded_basis(rg) if len(gb) > 0: gbm = set.union(*[set(x.monomials()) for x in gb]) for m in elem.monomials(): tester.assertTrue( not m in gbm, LazyFormat( "element %s of degree (%d,%d,%d) is also in graded_basis(%s)" ) % (m, t, e, s, rg), )
def __init__(self, algebra, gens, subalgebra, unstable, bbox, facade): self._algebra = algebra self._unstable = unstable self._amil = algebra.an_element().change_basis("milnor").parent() self._subalg = subalgebra self._prime = self._algebra.characteristic() self._emask = 0 self._trunc = bbox self._rmask = [] if facade is None: print("WARNING: you should supply a reasonable facade") facade = self if subalgebra is not None: assert subalgebra._truncation_type == 0 # FIXME if not algebra.is_generic(): e, r = (), subalgebra._profile else: r, e = subalgebra._profile msk = 1 for i in e: if 2 == i: self._emask = self._emask | msk msk = msk << 1 self._rmask = r self._gens = gens if hasattr(gens, "dump_element"): self._dumpfuncs = gens.dump_element, gens.load_element else: import base64 from sage.misc.persist import dumps, loads self._dumpfuncs = lambda x: base64.b64encode(dumps( x)), lambda x: loads(base64.b64decode(x)) if self.is_finite(): cat = FiniteEnumeratedSets() if not self._algebra.is_generic(): emax = 0 else: assert self._algebra._has_nontrivial_profile() rp, ep = self._profile emax = len(k for k in ep if k == 2) self._algbox = region(tmin=0, tmax=self._algebra.top_class().degree(), emin=0, emax=emax, s=0) else: cat = InfiniteEnumeratedSets() self._algbox = region(tmin=0, emin=0, s=0) Parent.__init__(self, facade=facade, category=(cat, YacopGradedSets()))
def bbox(self, reg=None): lst = self._list if len(lst) == 0: return region(tmax=5, tmin=10) tmax = max(x[1] for x in lst) emax = max(x[2] for x in lst) smax = max(x[3] for x in lst) tmin = min(x[1] for x in lst) emin = min(x[2] for x in lst) smin = min(x[3] for x in lst) res = region(tmax=tmax, tmin=tmin, emax=emax, emin=emin, smin=smin, smax=smax) if not reg is None: res = res.intersect(reg) return res
def compute(self, quiet=False, **kwargs): """ TESTS:: sage: from yacop.resolutions.smashres import SmashResolution sage: from yacop.resolutions.minres import MinimalResolution sage: from yacop.modules.classifying_spaces import BZp sage: A=SteenrodAlgebra(5) sage: D=BZp(5) sage: # use a fresh resolution for this test. it should be automatically extended sage: C=MinimalResolution(A,filename='file:newresolutionxxx?mode=memory') sage: S=SmashResolution(D,C) sage: S.compute(smax=20,nmax=80,quiet=True) sage: E=S.Homology() sage: sorted(list(E.free_basis(s=3,imax=10))) sage: # the "free_basis" reports only the degrees that have already sage: # been computed; it does not trigger an extension of the resolution sage: S.free_basis(s=3) """ if self._worker is None: raise ValueError("Smash resolution does not have database backing") reg = region(kwargs) self._worker.extend(reg=reg, quiet=quiet)
def TruncatedObjectsFactory(self, module, *args, **kwargs): reg = region(**kwargs) topexp = min(reg.tmax, self._top) botexp = max(reg.tmin, self._bot) fielddim = self._field prefix = self._prefix return GenericProjectiveSpace(fielddim, topexp, botexp, prefix)
def basis(self, reg=None): from sage.sets.set import Set assert hasattr(self, "_domain") from functools import partial from sage.sets.set_from_iterator import EnumeratedSetFromIterator if reg is None: reg = region() reg = reg.intersect(self.bbox()) reg2 = (reg + self._totaloff).var_mult( dict(list(zip(("t", "e", "s"), self._signs)))) iterfunc = partial(self.__degree_walker_tc, idx=len(self._factors) - 1, elems=[], reg=reg2) sz = 0 for var in ("t", "e", "s"): ma, mi = reg.max(var), reg.min(var) if mi > ma: return Set(()) sz += ma - mi category = (FiniteEnumeratedSets() if sz < +Infinity else InfiniteEnumeratedSets()) return EnumeratedSetFromIterator( iterfunc, category=category, cache=False, name="basis in %s of %s" % (reg, self._domain), )
def __init__(self, gradings, **options): YacopGrading.__init__(self) self._factors = gradings self._bboxes = [u.bbox() for u in gradings] bxs = self._bboxes # rewrite M1 # ... # Mn as # S^totoff ( S^(i1)M1 # ... # S^(in)Mn ) # with connected or coconnected factors S^(ik) M_k sgns, offs, totoff = [], [], [] for var in ("t", "e", "s"): if all(g.min(var) > -Infinity for g in bxs): tsgn, toffs = +1, [g.min(var) for g in bxs] elif all(g.max(var) < +Infinity for g in bxs): tsgn, toffs = -1, [g.max(var) for g in bxs] else: # need SmashResolution ( dual-steenrod-algebra * minimal resolution ) for the psi-map print( "WARNING: tensor product not locally finite in the %s-direction" % var) tsgn, toffs = 0, [0 for g in bxs ] # not sure if this is a good idea ... sgns.append(tsgn) offs.append(toffs) totoff.append(-sum(toffs)) self._signs = sgns self._endpoints = offs t, e, s = totoff self._totaloff = region(t=t, e=e, s=s)
def _element_constructor_(self, *args, **kwargs): if len(args) == 3: try: t, e, s = args return self._from_dict({0: t, 1: e, 2: s}) except: ar2 = ["%s" % u for u in args] raise ValueError("suspender not recognized: %s" % ", ".join(ar2)) try: r = region(**kwargs) dct = {0: 0, 1: 0, 2: 0} if r.tmin != -Infinity: assert r.tmax == r.tmin dct[0] = r.tmin if r.emin != -Infinity: assert r.emax == r.emin dct[1] = r.emin if r.smin != -Infinity: assert r.smax == r.smin dct[2] = r.smin return self._from_dict(dct) except KeyError: pass if len(args) == 1 and args[0] == 0: return self.zero() ar2 = ["%s" % x for x in args] kw2 = ["%s=%s" % (a, b) for (a, b) in kwargs.items()] raise ValueError("cannot make suspender from %s" % ", ".join(ar2 + kw2))
def _degree_on_basis(self, exponents): xt, xe, xs = 0, 0, 0 for (e, (wt, we, ws)) in zip(exponents, self._degrees): xt = xt + e * wt xs = xs + e * ws xe = xe + e * we return region(t=xt, e=xe, s=xs)
def SuspendedObjectsFactory(module, *args, **kwopts): """ TESTS:: sage: from yacop.modules.serre_cartan import SerreCartanModule sage: from yacop.modules.projective_spaces import ComplexProjectiveSpace sage: M = SerreCartanModule.Clone(ComplexProjectiveSpace(botexp=3,topexp=7),letter='f') ; M Free module generated by [f6, f8, f10, f12, f14] over Finite Field of size 2 sage: for m in M.graded_basis(): ....: print((m,[Sq(i)*m for i in range(5)])) (f6, [f6, 0, f8, 0, f10]) (f8, [f8, 0, 0, 0, 0]) (f10, [f10, 0, f12, 0, 0]) (f12, [f12, 0, 0, 0, 0]) (f14, [f14, 0, 0, 0, 0]) sage: from yacop.categories.functors import suspension sage: N = suspension(M,s=2,t=3) sage: for n in N.graded_basis(): ....: print((n.s,n.e,n.t,n)) (2, 0, 9, f6) (2, 0, 11, f8) (2, 0, 13, f10) (2, 0, 15, f12) (2, 0, 17, f14) sage: for n in N.graded_basis(): ....: print((n,[Sq(i)*n for i in range(5)])) (f6, [f6, 0, f8, 0, f10]) (f8, [f8, 0, 0, 0, 0]) (f10, [f10, 0, f12, 0, 0]) (f12, [f12, 0, 0, 0, 0]) (f14, [f14, 0, 0, 0, 0]) """ # FIXME: why does the category framework not handle this # FIXME: the internal differential is lost (?) limits = region(kwopts) t, s, e = 0, 0, 0 try: s = limits.s except: pass try: t = limits.t except: pass try: e = limits.e except: pass newbasis = [(key, tdeg + t, edeg + e, sdeg + s) for (key, tdeg, edeg, sdeg) in module._basis()] ans = SerreCartanModule( module._yacop_base_ring, newbasis, latexnames=tuple(module._latex_names.items()), ) newops = [(a, ans(x), ans(y)) for (a, x, y) in module.operations()] ans.set_operations(newops) return ans
def __region(self, reg2, **kwargs): if not reg2 is None and not isinstance(reg2, region): # might be dealing with a sample grading return reg2 reg = region(**kwargs) if not reg2 is None: reg = reg2.intersect(reg) return reg
def TruncatedObjectsFactory(module, *args, **kwopts): """ TESTS:: sage: from yacop.modules.serre_cartan import SerreCartanModule sage: from yacop.modules.projective_spaces import ComplexProjectiveSpace sage: M = SerreCartanModule.Clone(ComplexProjectiveSpace(botexp=3,topexp=7),letter='f') ; M Free module generated by [f6, f8, f10, f12, f14] over Finite Field of size 2 sage: from yacop.categories.functors import truncation sage: N = truncation(M,tmin=8, tmax=12) ; N Free module generated by [f8, f10, f12] over Finite Field of size 2 sage: N.coerce_embedding() Generic morphism: From: Free module generated by [f8, f10, f12] over Finite Field of size 2 To: Free module generated by [f6, f8, f10, f12, f14] over Finite Field of size 2 sage: for g in N.graded_basis(): ....: print("%-3s -> %s" % (g,M(g))) ....: assert(g == N(M(g))) ....: assert(M(g) == M(N(M(g)))) f8 -> f8 f10 -> f10 f12 -> f12 sage: N2 = truncation(M,tmin=8, tmax=12) ;# make sure it can be constructed a second time sage: N is N2 True """ # FIXME: why does the category framework not handle this # FIXME: the internal differential is lost (?) limits = region(kwopts) tmin, tmax = limits.trange smin, smax = limits.srange emin, emax = limits.erange gens = [(k, module.monomial(k)) for k in list(module.basis().keys())] tbasis = [(k, g.t, g.e, g.s) for (k, g) in gens if g.t >= tmin and g.t <= tmax and g.s >= smin and g.s <= smax and g.e >= emin and g.e <= emax] ans = SerreCartanModule(module._yacop_base_ring, tbasis) if not hasattr(ans, "_yacop_sc_truncation"): # the SerreCartanModule class has unqiue representation, so if # we construct the same truncation twice we might already have # a completely constructed ans here (and re-registering the embedding # will fail). we use a dummy attribute to detect this situation emb = ans.module_morphism(codomain=module, on_basis=module.monomial) ans.register_embedding(emb) conv = module.module_morphism(codomain=ans, function=ans._element_constructor_) ans.register_conversion(conv) ans._coerce_keys += [k for (k, g) in gens if g.t > tmax] ans._ops = { (op, m): ans(n) for ((op, m), n) in module._ops.items() if m in list(ans.basis().keys()) and not ans(n).is_zero() } ans._yacop_sc_truncation = True return ans
def __degree_walker(self, idx, elems, reg): r""" An iterator for the basis of a tensor product. INPUT: - ``idx`` - iterate through basis of ``M_0 # ... # M_idx`` - ``elems`` - elements of ``M_(idx+1) # ... # M_n`` that have already been chosen - ``reg`` - region to iterate through """ assert idx >= 0 tmax, emax, smax = reg.tmax, reg.emax, reg.smax if tmax < 0 or emax < 0 or smax < 0: return toff, eoff, soff = [u[idx] for u in self._endpoints] tsgn, esgn, ssgn = self._signs gr = self._factors[idx] if idx == 0: # this is the last tensor factor r2 = reg.var_mult({"t": tsgn, "e": esgn, "s": ssgn}) r2 = r2 + region(t=toff, e=eoff, s=soff) # print "reg=",reg,"r2=",r2 for elem in gr.basis(r2): yield [ elem, ] + elems else: # this is not the last tensor factor regmax = region(tmax=tmax, emax=emax, smax=smax) r2 = regmax.var_mult({"t": tsgn, "e": esgn, "s": ssgn}) r2 = r2 + region(t=toff, e=eoff, s=soff) for deg in gr.nontrivial_degrees(r2): dg2 = deg + region(t=-toff, e=-eoff, s=-soff) dg2 = dg2.var_mult({"t": -tsgn, "e": -esgn, "s": -ssgn}) regred = reg + dg2 for elem in gr.basis(deg): for x in self.__degree_walker( idx - 1, [ elem, ] + elems, regred, ): yield x
def an_element(self): """ TESTS:: sage: from yacop.resolutions.minres import GFR sage: C=GFR(SteenrodAlgebra(13),memory=True) sage: C.extend(s=2,n=30) sage: C.an_element() # random """ return self.generators(region(), extracondition="1 limit 1")[0]
def __iter__(self, reg=None): if reg is None: reg = region() tmin, tmax = reg.trange octs = self.module.octants() assert len(octs) == 1 # TODO: allow more than one octant tsign, esign, ssign = octs[0] from itertools import chain if tsign == +1: I = IntegerRange(Integer(0), tmax + 1) return chain.from_iterable( self._truncate_region(reg.intersect(region(t=n))) for n in I ) else: I = IntegerRange(Integer(0), -tmin) return chain.from_iterable( self._truncate_region(reg.intersect(region(t=-n))) for n in I )
def __init__(self, basering, basis, operations=None, latexnames=None, category=None): if category is None: category = YacopLeftModules(basering) dct = dict() grades = dict() items = [] for itm in basis: edeg = 0 sdeg = 0 if len(itm) == 2: elem, tdeg = itm elif len(itm) == 3: elem, tdeg, edeg = itm elif len(itm) == 4: elem, tdeg, edeg, sdeg = itm else: raise ValueError("item %s to understood" % itm) if elem in items: raise ValueError("duplicate item in basis") items.append(elem) grades[elem] = (tdeg, edeg, sdeg) reg = region(s=sdeg, e=edeg, t=tdeg) try: u = dct[reg] except KeyError: u = [] u.append(elem) dct[reg] = u # grading = YacopGradingFromDict((k,tuple(v)) for (k,v) in dct.iteritems()) self._latex_names = dict(latexnames) grbasis = FiniteGradedSet(items, tesfunc=lambda x: grades[x]) grading = SteenrodModuleGrading(grbasis, self) SerreCartanModuleBase.__init__(self, grbasis, grading=grading, category=category) # self.monomial is only available after refining the category, so we can # only set the proper grading now # grading = YacopGradingFromDict((k,tuple(self.monomial(_) for _ in v)) for (k,v) in dct.iteritems()) # self._set_grading(grading) self._assign_names([str(_) for _ in items]) self._ops = dict() if not operations is None: self.set_operations(operations) # list of keys that we accept in the element constructor # this can become bigger than the original keys if we deal # with a truncation where certain keys are to be treated as zero self._coerce_keys = list(self.basis().keys())
def basis(self, reg=None): if reg is None: reg = region() b = self._other.basis(reg + self._neg) if b.cardinality() == 0: return FiniteEnumeratedSet(()) x = next(iter(b)) dom = suspension(x.parent(), **self._kwargs) mapfunc = lambda x: x.suspend(**self._kwargs) unmapfunc = lambda x: x.suspend( t=self._neg.t, e=self._neg.e, s=self._neg.s) return SetOfElements(dom, b, b.cardinality(), mapfunc, unmapfunc)
def g(self, s, t, num=0): ans = [] for dct in self._res._worker.generators(region(s=s, t=t), "basid=%d" % num): ans.append(dct) if len(ans) > 1: raise ValueError( "internal error: more than one generator with (s,n,num)=(%d,%d,%d)" % (s, n, num)) if len(ans) == 0: raise ValueError("no such generator") return self(self._gens.element_class(self._gens, ans[0]))
def __classcall_private__(cls, other, **kwargs): reg = region(**kwargs) if reg.is_full(): return other shft = other._off reg = reg + shft.negative() return suspension( truncation(other._other, **(reg.as_dict())), t=shft.tmin, e=shft.emin, s=shft.smin, )
def extend(self, reg=None, quiet=True, dbg=False, **kwargs): """ extend the smasher computation to the required region automatically extends the reference resolution as required """ from yacop.utils.region import region from copy import copy, deepcopy reg = copy(reg) if reg is None: reg = region() reg = reg.intersect(region(kwargs)) mtrunc, sranges = self._find_region(reg) if dbg: print("reg", reg) print("mtrunc", mtrunc) print("sranges", sranges) for (s, n) in sranges: self._resolution.extend(reg=region(s=s, n=n), quiet=quiet) self._errors = [] self._errorlocation = None if quiet: self.tcl.eval("yacop::sectionizer quiet on") else: self.tcl.eval("yacop::sectionizer quiet off") self._make_smash_basis(mtrunc, dbg=dbg) self._make_smash_fragments(reg, dbg=dbg) self._make_smash_homology(reg, dbg=dbg) if not self._errorhandler is None and not self._errorlocation is None: self._errorhandler(self._errorlocation)
def _repr_(self): if self._subalg is None: xxx = "%s" % self._algebra else: xxx = "%s//%s" % (self._algebra, self._subalg) if self._trunc != region(): yyy = "truncation to %s of " % self._trunc else: yyy = "" return "%sbasis of a free module over %s with generators %s" % ( yyy, xxx, self.gens(), )
def __classcall_private__(cls, algebra, gens, subalgebra=None, unstable=None, bbox=None, facade=None): if unstable is None: unstable = False if bbox is None: bbox = region() return super(FreeModuleBasis, cls).__classcall__(cls, algebra, gens, subalgebra, unstable, bbox, facade)
def degree(self, elem): a, g = elem._a, elem._g ae = self._amil.monomial(a) if not self._algebra.is_generic(): e, r = (), a ideg = ae.degree() else: e, r = a ideg = ae.degree() areg = region(s=0, e=len(e), t=ideg) greg = self._gens.degree(g) tot = areg + greg # print "degree of %s = %s" % (elem,tot) return tot
def g(self, s=None, t=None, n=None, num=None, id=None): """ TESTS:: sage: from yacop.resolutions.minres import GFR sage: C=GFR(SteenrodAlgebra(3),memory=True) sage: C.extend(s=6,n=30) sage: g = C.g(s=5,n=0) sage: C.g(id=g["id"]) == g True sage: g.pop("id") # random 37 sage: sorted(g.iteritems()) [('e', 5), ('n', 0), ('num', 0), ('s', 5), ('t', 5)] sage: C.g(s=5,t=28) Traceback (most recent call last): ... ValueError: more than one generator in that region sage: C.g(s=5,t=28,num=1) # random {'e': 4, 'id': 53, 'n': 23, 'num': 1, 's': 5, 't': 28} """ extracondition = "" if not id is None: extracondition = "rowid=%d" % id reg = region() else: reg = region(s=s, n=n, t=t) if not num is None: extracondition = "basid=%d" % num # print reg,extracondition lst = self.generators(reg, extracondition) if len(lst) < 1: raise ValueError("no such generator") if len(lst) > 1: raise ValueError("more than one generator in that region") return lst[0]
def __iter__(self, reg=None): if reg is None: reg = region() tmin, tmax = reg.trange if tmin > tmax: return iter([]) from itertools import chain mi, ma = self.dim_min(), self.dim_max() mi = max(mi, tmin) ma = min(ma, tmax) if mi > -Infinity: mi = Integer(mi) if ma < +Infinity: ma = Integer(ma + 1) return chain.from_iterable( self._basis_in_dim(n, reg) for n in IntegerRange(mi, ma))
def __next__(self): owner = self.owner id = self.id self.id += 1 extendto = 0 while True: elems = owner._res.generators( owner._reg, extracondition=" rowid>%d order by rowid limit 1" % id ) if len(elems) == 0: if extendto < owner._reg.tmax or extendto < owner._reg.smax: extendto += 5 owner._res.extend(region(smax=extendto, tmax=extendto)) continue raise StopIteration assert len(elems) == 1 return owner.element_class(owner, elems[0])
def getmatrix(self, what, reg): """ Fetch one of the computed matrices from the database """ (cond, nexp, texp) = self._search_condition(reg) # self._tabledump("select s.sdeg, s.ideg, s.edeg, s.%s from smash_boxes s %s order by s.sdeg, s.ideg, s.edeg" % (what,cond)) res = ("[" + self.tcl.eval(""" join [smashprod db eval { select '(' || s.sdeg, %s, s.edeg, 'mat('||pymatrix(s.%s)||'))' from smash_boxes s %s order by s.sdeg, s.ideg, s.edeg }] , """ % (texp, what, cond)) + "]") mat = lambda x: matrix(self._gf, x) for (s, t, e, m) in eval(res): yield region(s=s, t=t, e=e), m
def __init__(self, algebra, memory=None, filename=None, category=None, istor=False): """ TESTS:: sage: from yacop.resolutions.minres import MinimalResolution sage: A=SteenrodAlgebra(3) sage: M=MinimalResolution(A,memory=True) ; M minimal resolution of mod 3 Steenrod algebra, milnor basis sage: M.category() Category of yacop left modules over mod 3 Steenrod algebra, milnor basis sage: TestSuite(M).run() """ self._worker = GFR(algebra, filename=filename, memory=memory) gens = Subset(self._worker, region()) self._algebra = algebra self._filename = filename self._memory = memory self._istor = istor self._defcategory = category pro = ((), ()) if algebra.is_generic() else () actalg = ( SteenrodAlgebra( p=algebra.prime(), generic=algebra.is_generic(), profile=pro ) if istor else algebra ) if istor: actalg.rename("F%s" % algebra.prime()) if category is None: category = YacopLeftModules(actalg) if istor: category = category.Subquotients() FreeModuleImpl.__init__( self, actalg, gens, None, True, False, category=category )