-
-
Notifications
You must be signed in to change notification settings - Fork 599
Optimize MatchingCoveredGraph’s add_edge method #39678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize MatchingCoveredGraph’s add_edge method #39678
Conversation
Hi @dcoudert, I'm new to contributing to SageMath and actively exploring its environment as I prepare for GSoC. My goal is to become a long-term contributor, and I'm gaining familiarity with the codebase through various contributions. Looking forward to your feedback on this PR! |
Thank you for this PR. I think @janmenjayap should check as he is the main contributor of this module. I realize that we have no control on the algorithm used to check whether the graph is matching covered. It was already the case. May be we could store the parameters used for creating the instance and use them when calling |
Hi @dcoudert, Thank you for your suggestion! I've taken it into account and implemented it. Now, the instance parameters are preserved and used when calling Additionally, storing these parameters provides flexibility for potential future use in other validations or optimizations within the module. |
Thank you @mashraf8 for this PR. The way currently the I have mistakenly missed/ overlooked a better implementation of Case 1: Case 2: |
Hi, |
# Store all parameters used in this instance for reference if needed | ||
self._params = { | ||
"data": data, | ||
"matching": self._matching, | ||
"algorithm": algorithm, | ||
"solver": solver, | ||
"verbose": verbose, | ||
"integrality_tolerance": integrality_tolerance, | ||
"args": args, | ||
"kwds": kwds | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameters data
, args
and kwds
are essentially consumed by Graph.__init__()
method, while creating an instance of the matching covered graph. Thus, all the information and attributes of those parameters can be directly accessed from self
(for example immutability, or edges being weighted).
Other parameters, that are algorithm
, solver
, verbose
, integrality_tolerance
are used for obtaining self._matching
, and are not required afterwards.
This commit may be reverted.
cc: @dcoudert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you if you use the algorithm you proposed.
|
||
# Add the new edge to the graph using the original method from the base class | ||
super().add_edge(u, v, label=label) | ||
# Check if the graph is still matching covered after adding the edge | ||
if not self.is_matching_covered(**{k: self._params[k] for k in ["algorithm", "solver", "verbose","integrality_tolerance"]}): | ||
# If it is no longer matching covered, immediately remove the edge to restore the previous state and raise an exception | ||
super().delete_edge(u, v, label=label) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Add the new edge to the graph using the original method from the base class | |
super().add_edge(u, v, label=label) | |
# Check if the graph is still matching covered after adding the edge | |
if not self.is_matching_covered(**{k: self._params[k] for k in ["algorithm", "solver", "verbose","integrality_tolerance"]}): | |
# If it is no longer matching covered, immediately remove the edge to restore the previous state and raise an exception | |
super().delete_edge(u, v, label=label) | |
# If (u, v, label) is a multiple edge/ an existing edge | |
if self.has_edge(u, v): | |
self._backend.add_edge(u, v, label, self._directed) | |
return | |
# Check if there exists an M-alternating odd uv path starting and | |
# ending with edges in self._matching | |
from sage.graphs.matching import M_alternating_even_mark | |
w = next((b if a == u else a) for a, b, *_ in self.get_matching() if u in (a, b)) | |
if v in M_alternating_even_mark(self, w, self.get_matching()): | |
# There exists a perfect matching containing the edge (u, v, label) | |
self._backend.add_edge(u, v, label, self._directed) | |
return | |
# Update the matching only if the graph remains matching covered after adding the edge | ||
self._matching = self.get_matching() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Update the matching only if the graph remains matching covered after adding the edge | |
self._matching = self.get_matching() | |
raise ValueError('the graph obtained after the addition of ' | ||
'edge (%s) is not matching covered' | ||
% str((u, v, label))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise ValueError('the graph obtained after the addition of ' | |
'edge (%s) is not matching covered' | |
% str((u, v, label))) | |
raise ValueError('the graph obtained after the addition of edge (%s)' | |
'is not matching covered' % str((u, v, label))) |
Please remove these lines, as this will be taken care by the last commit of Let me know if any other query is there in this regard. |
It's better to use |
Hi @janmenjayap, Thank you so much for all your suggestions! I’ve actually been looking into changing At this last commit, is there anything else you would suggest? Thanks again! |
I tried this PR and all tests pass. |
Yes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some minor details.
|
||
except Exception: | ||
raise ValueError('the graph obtained after the addition of ' | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove trailing white spaces (this line should be empty)
# There exists a perfect matching containing the edge (u, v, label) | ||
self._backend.add_edge(u, v, label, self._directed) | ||
return | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove trailing white spaces (this line should be empty)
self._backend.add_edge(u, v, label, self._directed) | ||
return | ||
|
||
raise ValueError('the graph obtained after the addition of ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
improve alignment like
raise ValueError('the graph obtained after the addition of edge '
'(%s) is not matching covered' % str((u, v, label)))
return | ||
# Check if there exists an M-alternating odd uv path starting and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return | |
# Check if there exists an M-alternating odd uv path starting and | |
return | |
# Check if there exists an M-alternating odd uv path starting and |
Add an empty line in between.
w = next((b if a == u else a) for a, b, *_ in self.get_matching() if u in (a, b)) | ||
if v in M_alternating_even_mark(self, w, self.get_matching()): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
w = next((b if a == u else a) for a, b, *_ in self.get_matching() if u in (a, b)) | |
if v in M_alternating_even_mark(self, w, self.get_matching()): | |
w = next((b if a == u else a) for a, b, *_ in self.get_matching() if u in (a, b)) | |
if v in M_alternating_even_mark(self, w, self.get_matching()): |
Add an empty line in between.
Thank you, @dcoudert and @janmenjayap |
No worries, @mashraf8. Welcome to SageMath. |
Looks good to me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Passes all tests on my laptop.
@vbraun, I cannot launch the CIs myself. I let you launch them if necessary. |
Documentation preview for this PR (built with commit 820d609; changes) is ready! 🎉 |
sagemathgh-39678: Optimize MatchingCoveredGraph’s add_edge method The `add_edge` method has been optimized to ensure that edges are added while preserving the **matching-covered** property without fully reinitializing or creating a new graph. First, the edge is added using the base method, then the graph is checked to confirm that it remains matching-covered. If it is no longer valid, the edge is immediately removed to restore the previous state. The matching is updated only if the graph remains valid. **Doctests** were successfully executed to verify the correctness of the modifications. ### 📝 Checklist - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. URL: sagemath#39678 Reported by: Mohammed Ashraf Reviewer(s): David Coudert, Janmenjaya Panda
The
add_edge
method has been optimized to ensure that edges are added while preserving the matching-covered property without fully reinitializing or creating a new graph.First, the edge is added using the base method, then the graph is checked to confirm that it remains matching-covered. If it is no longer valid, the edge is immediately removed to restore the previous state. The matching is updated only if the graph remains valid.
Doctests were successfully executed to verify the correctness of the modifications.
📝 Checklist