#11255: Enhance the e_one_star.Patch class
-----------------------------+----------------------------------------------
Reporter: tjolivet | Owner: sage-combinat
Type: enhancement | Status: needs_work
Priority: major | Milestone: sage-4.7.1
Component: combinatorics | Keywords:
Work_issues: | Upstream: N/A
Reviewer: | Author: Timo Jolivet
Merged: | Dependencies:
-----------------------------+----------------------------------------------
Comment(by slabbe):
> Here is why I added a `__hash__` method to Patch:
>
> {{{
> sage: P = Patch([Face([0,0,0],1), Face([0,0,0],2)])
> sage: Q = Patch([Face([0,0,0],2), Face([0,0,0],1)])
> sage: P == Q
> True
> sage: hash(P)
> 1297676529065262660
> sage: hash(Q)
> -8173426908364432914
> }}}
>
> I had a lot of problems because of this when I used some `DiGraphs`
whose
> vertices were `Patches`. If you have a better solution, let me know. I
added it
> in the doctest under a TEST section.
If we want Patches to be keys of dictionnary, vertices of graphs or
elements of
sets, it must be hashable. The easiest solution I see is that an object
Patch
be always hashable and never mutable. That means we made a mistake earlier
by
allowing to modify a Patch. I am responsible for this as I remember I
disliked
methods like {{{apply_substitution}}} but I were not able to verbalize it
and
relate this with the ability of hashing the object.
There are three methods that change self : {{{add}}},
{{{apply_substitution}}}
and {{{repaint}}}. I think we can keep {{{repaint}}} as it does not change
the
mathematical object and hence won't affect the result of the hash method
(a
doctest making sure of that the hash method is independant of color
changes
should be added). Surprisingly, we did not made the mistake with the
method
{{{translate}}} which does not change self and return a new patch. I think
it
is easy to remove the method {{{apply_substitution}}} since (1) one can
apply a
substitution by just applying a substiution directly on it : ``E(P)`` and
(2)
the only reason I can understand the existence of the method
{{{apply_substitution}}} is that it is faster than doing ``E(P)`` which is
not
the case anyway since it calls ``E(P)`` anyway. I also think the method
{{{add}}} can be easily removed. We should replace it by a method
{{{__add__}}} or {{{union}}} which adds two patches and return a new
patch.
Now, the method {{{adds}}} and {{{apply_substitution}}} should not be
removed
right now. Deprecation warnings should be added. Well usually, a
deprecation
warning should be raised for one year before removing the method. But,
since I
believe fixing the immutable/hashable issue is very important. I think
their
behavior could be changed now. A deprecation warning saying something like
:
"Object sage.combinat.e_one_star.Patch are immutable since Sage-4.7.1. Use
the
usual addition instead which returns a new object: P + Q." A similar
warning
should be added to the method {{{apply_substitution}}}.
> Here is the problem with colors if we don't create new faces in
Patch.__init__:
>
> {{{
> sage: P = Patch([Face([0,0,0],1), Face([0,0,0],2)])
> sage: Q = Patch(P)
> sage: P[0].color()
> RGB color (1.0, 0.0, 0.0)
> sage: Q[0].color('yellow')
> sage: P[0].color()
> RGB color (1.0, 1.0, 0.0)
> }}}
>
> Let me know if you have a better solution. I added it in the doctest
under a TEST section.
One can create a Patch from a (1) iterable of faces or (2) from a Patch.
The
problem comes from the case (2) were a copy should be done. Here is my
first
suggestion:
{{{
if isinstance(faces, Patch):
self._faces = [Face(f.vector(), f.type(), f.color()) for f in faces]
else:
self._faces = list(faces)
}}}
> Please tell me if you agree with what I said concerning the main two
issues you raised (`__hash__` and creating new faces in `Patch.__init__`).
I will upload a new patch if you confirm.
>
> Also, do you think the following code of `Patch.remove` can be made
better? (It looks pretty naive but I'm not sure if using `set` would be
more efficient...):
>
> {{{
> if isinstance(faces, Face):
> while faces in self._faces:
> self._faces.remove(faces)
> else:
> for f in faces:
> while f in self._faces:
> self._faces.remove(f)
> }}}
First, there is a problem with the method {{{remove}}} because it changes
the
Patch. Compare the methods and their name of the mutable unhashable Python
set
and the immutable and hashable Python frozenset :
{{{
sage: python_set = set([])
sage: [method for method in dir(python_set) if not method.startswith('_')]
['add', 'clear', 'copy', 'difference', 'difference_update', 'discard',
'intersection', 'intersection_update', 'isdisjoint', 'issubset',
'issuperset',
'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update',
'union', 'update']
sage: frozen_set = frozenset()
sage: [method for method in dir(frozen_set) if not method.startswith('_')]
['copy', 'difference', 'intersection', 'isdisjoint', 'issubset',
'issuperset',
'symmetric_difference', 'union']
}}}
Hence, I suggest to implement a method called {{{difference}}} which
returns a
new Patch instead of the method remove.
My last question concerns the representation of the Patch. Now, we
represent a
patch as a list of faces. I think this choice was made because we wanted
an
object Patch to be mutable without loosing time on unicity of faces
concerns
which did not bothered us, since it is guarenteed mathematically (well at
least
for the application of E1Stars). But, if a Patch is now immutable, maybe a
Python frozenset or maybe a Sage Set (also immutable) would be better.
{{{
sage: sage_set = Set([])
sage: [method for method in dir(sage_set) if not method.startswith('_')]
['CartesianProduct', 'Hom', 'algebra', 'an_element', 'base', 'base_ring',
'cardinality', 'cartesian_product', 'categories', 'category', 'coerce',
'coerce_embedding', 'coerce_map_from', 'construction', 'convert_map_from',
'db', 'difference', 'dump', 'dumps', 'element_class', 'frozenset',
'gens_dict',
'get_action', 'has_base', 'has_coerce_map_from', 'hom',
'inject_variables',
'injvar', 'intersection', 'is_exact', 'is_finite', 'latex_name',
'latex_variable_names', 'list', 'normalize_names', 'object', 'objgen',
'objgens', 'register_action', 'register_coercion', 'register_conversion',
'register_embedding', 'rename', 'reset_name', 'save', 'set',
'some_elements',
'subsets', 'symmetric_difference', 'union', 'variable_name',
'variable_names',
'version']
}}}
What do you think?
Sébastien
--
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/11255#comment:6>
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 post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sage-trac?hl=en.