#18756: Use cython and coercion for CombinatorialFreeModule
-------------------------------------------------+-------------------------
Reporter: SimonKing | Owner:
Type: defect | Status: new
Priority: major | Milestone: sage-6.8
Component: algebra | Resolution:
Keywords: CombinatorialFreeModule, | Merged in:
cython, coercion | Reviewers:
Authors: | Work issues:
Report Upstream: N/A | Commit:
Branch: | Stopgaps:
Dependencies: |
-------------------------------------------------+-------------------------
Comment (by SimonKing):
Replying to [comment:6 nthiery]:
> > - `ELement` uses `_acted_on_/_acted_upon_` to implement actions. It
has no `_lmul_`, which means that the comment "for backward compatibility"
fails entirely.
> > - `ModuleElement` provides the infrastructure for both general actions
(inherited from `Element`) and a special path for scalar multiplication
(`_lmul_/_rmul_`). Problem: You can not implement a ring multiplication
when you just inherit from `ModuleElement`, since `ModuleElement.__mul__`
raises an error if both arguments belong to the same parent.
> > - `RingElement` provides the infrastructure for general actions,
scalar multiplication, and ring multiplication (via `_mul_`).
>
> Yup, the single inheritance of Cython is a very strong constraint. It
> pushes us to do crap.
Perhaps it would really be better to change `ModuleElement.__mul__`? The
fact that it raises an error if both parents are equal is not good. It may
haVe been motivated by an attempt to break an infinite recursion (namely:
To test existence of an action, you would try to multiply elements, but to
multiply elements, you need to know of there is an action). Perhaps that
cycle should be broken in a different way?
> This would make things complicated for subclasses of
> `CombinatorialModule` that have an Element class that inherits from
> `CombinatorialFreeModuleElement`.
Right. In contrast to the category framework, where the element class of a
super-category is mixed in, the `.Element` attribute of a super-class is
not mixed in `:-/`. Perhaps this could be implemented? Perhaps the
`.element_class` lazy attribute could also have a look at
`super(self,type(self)).Element` or so?
> Now a question: what are the speed critical things that we really need
> to be Cythonized? If it's just the `__mul__` methods and friends, it
> would be worth experimenting with replacing their Python
> implementations in the Modules/Rings/Algebras categories by Cythonized
> methods (with recent versions of Cython, this is possible). Maybe this
> would be sufficient.
If I understand the general pattern: To implement an algebraic structure
using `CombinatorialFreeModule`, one implements methods such as
`product_on_basis` or `degree_on_basis`.
I must admit that by searching the code for the past 30 minutes, I did not
really succeed to find out at what place "product_on_basis" is actually
turned into a `__mul__` method for `FreeModuleElement`s. But after
searching 60 minutes, I found:
- `Magmas().element_class` provides a `__mul__` method that mimics the
`__mul__` method of ring elements. Fine, but Python.
- `Magmas().parent_class.__init_extra__` assigns a `_mul_` method for the
element class by setting it to `_mul_parent`
- `_mul_parent` calls `self.parent().product`
- `.product` calls `product_on_basis`.
These are many indirections---too many python calls for a single
multiplication in high performance code, I'd say.
One detail: Apparently, setting `_mul_` to an attribute of the class
results in slower access than what is possible when providing a method
during **creation** of the class (such as `_mul_parent`):
{{{
sage: A = DiGraph({1:{2:['a']}, 2:{3:['b']}, 3:{1:['c'], 4:['m']},
4:{5:['n']}, 5:{6:['x'],7:['y']}, 6:{7:['z']}}).path_semigroup().algebra
(QQ)
sage: A.inject_variables()
Defining e_1, e_2, e_3, e_4, e_5, e_6, e_7, a, b, c, m, n, x, y, z
sage: %timeit x.__mul__
The slowest run took 122.24 times longer than the fastest. This could mean
that an intermediate result is being cached
10000000 loops, best of 3: 50.7 ns per loop
sage: %timeit x._mul_parent
The slowest run took 100.65 times longer than the fastest. This could mean
that an intermediate result is being cached
10000000 loops, best of 3: 61.6 ns per loop
sage: %timeit x._mul_
The slowest run took 41.40 times longer than the fastest. This could mean
that an intermediate result is being cached
10000000 loops, best of 3: 121 ns per loop
}}}
Hence, we would already gain a tiny bit by providing `_mul_` during
creation of the element class, not afterwards.
By the way, why is all this in `Magmas()`? It uses "product_on_basis",
hence, it uses the notion of a basis, which isn't defined for magmas,
right? In fact, I first searched in `AlgebrasWithBasis` to find the
definition of multiplication with `product_on_basis`.
--
Ticket URL: <http://trac.sagemath.org/ticket/18756#comment:8>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica,
and MATLAB
--
You received this message because you are subscribed to the Google Groups
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.