On Oct 8, 2007, at 9:44 PM, David Roe 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 probably yet another one in the pipeline as Greg released Pyrex 0.9.6.1 just the other day.) > 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. 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? > 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): > > > > > --~--~---------~--~----~------------~-------~--~----~ 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/ -~----------~----~----~----~------~----~------~--~---