On 10/9/07, Robert Bradshaw <[EMAIL PROTECTED]> wrote: > > I'm working on bringing __call__ into the coercion framework. > > Unlike coerce, we need to worry about additional arguments besides > > just the object x to be cast into the parent (I've included the > > list of all parent __call__ methods currently defined at the bottom > > of this e-mail). > > Before we do too much, lets get the cdef overrideable cython package > mainstreamed into SAGE. (Working on this now, and there will be
What's the time estimate? I definitely like the idea of having cdef overridable in before doing more architecture stuff, since things are very complicated without it, and we'll just have to rewrite things once cdef overridable exists. > probably yet another one in the pipeline as Greg released Pyrex > 0.9.6.1 just the other day.) Do you meant that Greg's 0.9.6.1 has an analogue of cdef overridable? I didn't see anything in the release notes about that. I wish there were a shorter word than "overridable". I'm not even sure how to spell it (I.e., I don't agree with what you wrote above). Hmm. Some other options: cdef overloadable foo(...) cdef overwritable foo(...) cdef redefinable foo(...) cdef redefable foo(...) rdef foo(...) Hey, what's wrong with "rdef"? An rdef'd method is like a cdef'd one, but it can be redefined in a derived class with a def or cdef method? > > Define call_map_from in parent.pyx similarly to coerce_map_from. > > Just as in the coerce case, there would be a fallback onto older > > code at the bottom of call_map_from_impl. > > Before this all gets set in stone, I think the name "call map" is > misleading. For instance, if I were asked "what is the call map of Z > [x]?" the first thought that comes to mind is the map Z -> Z induced > by a specific polynomial. The terminology call is purely a python thing. I chose call mainly because it matches object constructor notation. > There are two goals we are trying to accomplish here. The first > objective, non-canonical/everywhere defined coercions (e.g. sections > of canonical coercions, Q -> F_p, etc.). The second objective is > element creation. These may have a myriad of different keywords, > (e.g. check, precision) and take multiple arguments. Of course the > line between these two may be blurred, but I think there should be a > fast(er) pathway for the former and perhaps even separate functions. > force? cast? construct? to_element? I like to_element the best of those choice, since after all, what you are doing is creating an element. Names like "force" are very ambiguous, since they could mean almost anything depending on context. Cast is OK, but maybe too technical -- it's not too bad. Construct is ambiguous. So I like to_element and cast the best for this second notion. For the first -- fast section, maybe it should be a separate function like you suggest. > > > In parent.pyx, > > def __call__(self, x, *args, **kwds): > > from sage.structure.element cimport coercion_model > > coercion_model.call_map_c(parent_c(x))._call_with_extra_args(x, > > *args, **kwds) > > > > The coercion model would cache call maps. The default call > > morphism's implementation of _call_with_extra_args would be > > cdef _call_with_extra_args(self, x, *args, **kwds): > > self.codomain()._call_(x, *args, **kwds) > > > > This design allows for the coercion_model's call_map_c to first > > check to see if there's a coercion map defined, check to see if it > > can take a standard section of a coercion map going in the opposite > > direction, and do other smart things. > > This sounds like a good idea, if we can streamline the len(args) == > len(kwds) == 0 case. Would functions such as from_str, from_int, > from_list, from_dict, etc. take optional arguments? Two versions--one > with and one without? > > > Robert mentioned *args and **kwds causing a performance hit in > > cython. How serious is that? Any other thoughts? > > One can't even have *args and **kwds in a cdef functions (without > explicitly creating and manipulating dictionaries oneself). Also, if > one explicitly lists **kwds in the signature of a def function, a > dictionary has to be created even if it is empty. (The python > language may pass NULL for an empty dictionary for performance > reasons internally, but this won't work if its explicit). > > > For reference, here are all of the current parent __call__ methods: > > Here's a list of unique __call__ signatures (mostly parents I think, > not __element__ classes). > > 95 def __call__(self, x) > 15 def __call__(self, x, check=True) > 15 def __call__(self, *args, **kwds) > 11 def __call__(self, R) > 9 def __call__(self, *args) > 6 def __call__(self, v) > 5 def __call__(self, x, absprec = infinity, relprec = infinity) > 5 def __call__(self, im_gens, check=True) > 4 def __call__(self, M, mode = "ECB") > 4 def __call__( self, g ) > 3 def __call__(self, n) > 3 def __call__(self, K) > 3 def __call__(self, *v) > 2 def __call__(self, x=None, check=True, is_gen = False, > construct=False) > 2 def __call__(self, x, im=None) > 2 def __call__(self, x, base=0) > 2 def __call__(self, x, base = 0) > 2 def __call__(self, points, coerce=True, **kwds) > 2 def __call__(self, key) > 2 def __call__(self, facets) > 2 def __call__(self, args) > 2 def __call__(self, P, K) > 2 def __call__(self, P) > 2 def __call__(self, *x) > 1 def __call__(self,x0) > 1 def __call__(self,x) > 1 def __call__(self,w) > 1 def __call__(self, xdata, ydata, **kwds) > 1 def __call__(self, x=None, check=True, is_gen = False, > construct=False, absprec = None) > 1 def __call__(self, x, y=None, int base=10) > 1 def __call__(self, x, y=None, check=True) > 1 def __call__(self, x, y=None) > 1 def __call__(self, x, y=1, coerce=True) > 1 def __call__(self, x, type='def') > 1 def __call__(self, x, n=0) > 1 def __call__(self, x, globals=None) > 1 def __call__(self, x, gens=None) > 1 def __call__(self, x, computed_with_hecke=False) > 1 def __call__(self, x, coerce=True, copy=True, check=True) > 1 def __call__(self, x, coerce=True) > 1 def __call__(self, x, check=True, reduce=True) > 1 def __call__(self, x, bits=None) > 1 def __call__(self, x, base=10) > 1 def __call__(self, x, *args, **kwds) > 1 def __call__(self, x, *args) > 1 def __call__(self, value) > 1 def __call__(self, val, offset=0, check=True) > 1 def __call__(self, val, offset=0) > 1 def __call__(self, toktype, toktext, (srow,scol) > 1 def __call__(self, string, point, **kwds) > 1 def __call__(self, s, c=None) > 1 def __call__(self, s) > 1 def __call__(self, r) > 1 def __call__(self, pov_file, outfile='sage.ppm', block=True, > **kwargs) > 1 def __call__(self, point, radius, angle, **kwds) > 1 def __call__(self, point, radius, **kwds) > 1 def __call__(self, p) > 1 def __call__(self, obj, _=None) > 1 def __call__(self, ntl_ZZ a) > 1 def __call__(self, n, watch=False) > 1 def __call__(self, mv) > 1 def __call__(self, minpoint, maxpoint, **kwds) > 1 def __call__(self, message=None) > 1 def __call__(self, mat, **kwds) > 1 def __call__(self, m) > 1 def __call__(self, line) > 1 def __call__(self, im_gen, base_hom=None, check=True) > 1 def __call__(self, funcs, *args, **kwds) > 1 def __call__(self, f, xrange, yrange, **kwds) > 1 def __call__(self, f, prec=infinity, check=True) > 1 def __call__(self, entries=0, coerce=True, copy=True) > 1 def __call__(self, elt) > 1 def __call__(self, element) > 1 def __call__(self, e, coerce=True, copy=True, check=True) > 1 def __call__(self, double x) > 1 def __call__(self, dict=None, **kwds) > 1 def __call__(self, datalist, **kwds) > 1 def __call__(self, data, coerce=True, **kwds) > 1 def __call__(self, command, extension, options='', verbose=False) > 1 def __call__(self, code, strip=True, columns=0) > 1 def __call__(self, cmd=None, interactive=True) > 1 def __call__(self, cmd, globals_=None, job_name=None) > 1 def __call__(self, cmd, check_initialized=True) > 1 def __call__(self, cmd) > 1 def __call__(self, ambient) > 1 def __call__(self, alpha) > 1 def __call__(self, X) > 1 def __call__(self, Q, P) > 1 def __call__(self, M) > 1 def __call__(self, I, cmd='', verbose=False, format=True) > 1 def __call__(self, A, name='') > 1 def __call__(self, A, check=True) > 1 def __call__(self, *xs) > 1 def __call__(self, *x, **kwds) > 1 def __call__(self, *args, **kw) > 1 def __call__(self, *args, **argv) > 1 def __call__(self, **kwds) > 1 def __call__(self, (f, g) > 1 def __call__(gen self, y) > 1 def __call__(FiniteField_givaro self, e) > > > > algebras/free_algebra.py: def __call__(self, x): > > algebras/free_algebra_quotient.py: def __call__(self, x): > > algebras/quaternion_algebra.py: def __call__(self, x): > > algebras/quaternion_algebra.py: def __call__(self, x): > > calculus/calculus.py: def __call__(self, x): > > calculus/calculus.py: def __call__(self, x): > > combinat/combinatorial_algebra.py: def __call__(self, x): > > combinat/sfa.py: def __call__(self, x): > > crypto/classical.py: def __call__(self, K): > > crypto/classical.py: def __call__(self, K): > > crypto/classical.py: def __call__(self, K): > > crypto/stream.py: def __call__(self, key): > > crypto/stream.py: def __call__(self, key): > > functions/elementary.py: def __call__(self,z): > > functions/functions.py: def __call__(self, x): > > geometry/lattice_polytope.py: def __call__(self, x): > > interfaces/expect.py: def __call__(self, x): > > interfaces/maxima.py: def __call__(self, x): > > interfaces/mwrank.py: def __call__(self, cmd): > > interfaces/sage0.py: def __call__(self, x): > > lfunctions/lcalc.py: def __call__(self, args): > > modular/cusps.py: def __call__(self, x): > > modular/dirichlet.py: def __call__(self, x): > > monoids/free_abelian_monoid.py: def __call__(self, x): > > probability/random_variable.py: def __call__(self,x): > > rings/algebraic_real.py: def __call__(self, x): > > rings/finite_field.py: def __call__(self, x): > > rings/ideal_monoid.py: def __call__(self, x): > > rings/infinity.py: def __call__(self, x): > > rings/infinity.py: def __call__(self, x): > > rings/integer_mod_ring.py: def __call__(self, x): > > rings/laurent_series_ring.py: def __call__(self, x, n=0): > > rings/pari_ring.py: def __call__(self, x): > > groups/abelian_gps/dual_abelian_group.py: def __call__(self, > > x): > > groups/matrix_gps/matrix_group.py: def __call__(self, x): > > groups/perm_gps/cubegroup.py: def __call__(self, mv): > > groups/perm_gps/permgroup.py: def __call__(self, x): > > modular/abvar/finite_subgroup.py: def __call__(self, x): > > modular/hecke/algebra.py: def __call__(self, x): > > modular/hecke/ambient_module.py: def __call__(self, x): > > modular/modsym/boundary.py: def __call__(self, x): > > rings/number_field/number_field.py: def __call__(self, x): > > rings/number_field/number_field.py: def __call__(self, x): > > rings/number_field/number_field.py: def __call__(self, x): > > rings/number_field/order.py: def __call__(self, x): > > rings/number_field/order.py: def __call__(self, x): > > rings/padics/local_generic.py: def __call__(self, x): > > rings/polynomial/polynomial_quotient_ring.py: def __call__ > > (self, x): > > schemes/elliptic_curves/monsky_washnitzer.py: def __call__ > > (self, value): > > schemes/generic/divisor_group.py: def __call__(self, v): > > schemes/generic/spec.py: def __call__(self, x): > > schemes/hyperelliptic_curves/jacobian_homset.py: def __call__ > > (self, P): > > groups/group.pyx: def __call__(self, x): > > modules/module.pyx: def __call__(self, x): > > rings/finite_field_givaro.pyx: def __call__ > > (FiniteField_givaro self, e): > > rings/mpc.pyx: def __call__(self, x): > > rings/real_double.pyx: def __call__(self, x): > > rings/real_rqdf.pyx: def __call__(self, x): > > rings/residue_field.pyx: def __call__(self, x): > > rings/residue_field.pyx: def __call__(self, x): > > rings/residue_field.pyx: def __call__(self, x): > > rings/ring.pyx: def __call__(self, x): > > rings/sparse_poly.pyx: def __call__(self, x): > > structure/parent.pyx: def __call__(self, x): > > structure/wrapper_parent.pyx: def __call__(self, x): > > structure/wrapper_parent.pyx: def __call__(self, x): > > libs/pari/gen.pyx: def __call__(self, s): > > rings/polynomial/multi_polynomial_libsingular.pyx: def > > __call__(self, element): > > > > > > > > algebras/algebra_order.py: def __call__(self, x, check=True): > > algebras/quaternion_order.py: def __call__(self, x, > > check=True): > > groups/matrix_gps/homset.py: def __call__(self, im_gens, > > check=True): > > modular/congroup.py: def __call__(self, x, check=True): > > modular/congroup.py: def __call__(self, x, check=True): > > modules/free_module_homspace.py: def __call__(self, A, > > check=True): > > monoids/free_monoid.py: def __call__(self, x, check=True): > > monoids/string_monoid.py: def __call__(self, x, check=True): > > monoids/string_monoid.py: def __call__(self, x, check=True): > > monoids/string_monoid.py: def __call__(self, x, check=True): > > monoids/string_monoid.py: def __call__(self, x, check=True): > > monoids/string_monoid.py: def __call__(self, x, check=True): > > modular/hecke/submodule.py: def __call__(self, x, check=True): > > modular/modform/space.py: def __call__(self, x, check=True): > > rings/homset.py: def __call__(self, im_gens, check=True): > > rings/homset.py: def __call__(self, im_gens, check=True): > > rings/number_field/morphism.py: def __call__(self, im_gens, > > check=True): > > rings/polynomial/multi_polynomial_ring.py: def __call__ > > (self, x, check=True): > > schemes/generic/homset.py: def __call__(self, x, check=True): > > > > categories/homset.py: def __call__(self, x, y=None, > > check=True): #don't use y, check) > > interfaces/magma.py: def __call__(self, x, gens=None): > > interfaces/singular.py: def __call__(self, x, type='def'): > > matrix/matrix_space.py: def __call__(self, entries=0, > > coerce=True, copy=True): > > modules/free_module.py: def __call__(self, x, coerce=True, > > copy=True, check=True): > > modules/free_module.py: def __call__(self, e, coerce=True, > > copy=True, check=True): > > rings/complex_field.py: def __call__(self, x, im=None): > > rings/contfrac.py: def __call__(self, x, bits=None): > > rings/extended_integer_ring.py: def __call__(self, x, base = 0): > > rings/extended_rational_field.py: def __call__(self, x, base = 0): > > rings/fraction_field.py: def __call__(self, x, y=1, coerce=True): > > rings/interval.py: def __call__(self, x, y=None): > > rings/power_series_ring.py: def __call__(self, f, prec=infinity, > > check=True): > > rings/quotient_ring.py: def __call__(self, x, coerce=True): > > rings/rational_field.py: def __call__(self, x, base=0): > > structure/formal_sum.py: def __call__(self, x, check=True, > > reduce=True): > > groups/abelian_gps/abelian_group.py: def __call__(self, x): > > modular/hecke/homspace.py: def __call__(self, A, name=''): > > modular/modsym/ambient.py: def __call__(self, x, > > computed_with_hecke=False): > > rings/number_field/class_group.py: def __call__(self, *args, > > **kwds): > > rings/number_field/morphism.py: def __call__(self, im_gen, > > base_hom=None, check=True): > > rings/padics/padic_field_lazy.py: def __call__(self, x, absprec > > = infinity, relprec = infinity): > > rings/padics/padic_field_lazy.py: def __call__(self, x, absprec > > = infinity, relprec = infinity): > > rings/padics/padic_generic.py: def __call__(self, x, absprec = > > infinity, relprec = infinity): > > rings/padics/padic_ring_lazy.py: def __call__(self, x, absprec = > > infinity, relprec = infinity): > > rings/padics/padic_ring_lazy.py: def __call__(self, x, absprec = > > infinity, relprec = infinity): > > rings/polynomial/polynomial_ring.py: def __call__(self, x=None, > > check=True, is_gen = False, construct=False, absprec = None): > > rings/polynomial/polynomial_ring.py: def __call__(self, x=None, > > check=True, is_gen = False, construct=False): > > rings/polynomial/polynomial_ring.py: def __call__(self, x=None, > > check=True, is_gen = False, construct=False): > > schemes/elliptic_curves/ell_generic.py: def __call__(self, > > *args, **kwds): > > schemes/elliptic_curves/monsky_washnitzer.py: def __call__(self, > > val, offset=0, check=True): > > schemes/elliptic_curves/monsky_washnitzer.py: def __call__(self, > > val, offset=0): > > schemes/generic/homset.py: def __call__(self, *v): > > schemes/generic/homset.py: def __call__(self, *v): > > schemes/generic/homset.py: def __call__(self, *v): > > schemes/generic/scheme.py: def __call__(self, *args): > > rings/complex_double.pyx: def __call__(self, x, im=None): > > rings/integer_ring.pyx: def __call__(self, x, base=0): > > rings/real_mpfi.pyx: def __call__(self, x, y=None, int base=10): > > rings/real_mpfr.pyx: def __call__(self, x, base=10): > > > > > > > > > > > > > > -- William Stein Associate Professor of Mathematics University of Washington http://wstein.org --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://sage.scipy.org/sage/ and http://modular.math.washington.edu/sage/ -~----------~----~----~----~------~----~------~--~---