From eca1a6ebbca98acc828403264590e400a43eba81 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 22:35:54 +0800 Subject: [PATCH 01/12] Added domain/codomain validation in the __mul__ method Updated error handling for morphism composition to provide clearer messages regarding codomain and domain compatibility. --- src/sage/combinat/words/morphism.py | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index fe77b50fcfd..0921e3bf675 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -894,6 +894,9 @@ def __mul__(self, other): r""" Return the morphism ``self``\*``other``. + The composition is valid only if the codomain alphabet of ``other`` + is contained in the domain alphabet of ``self``. + EXAMPLES:: sage: m = WordMorphism('a->ab,b->ba') @@ -934,17 +937,45 @@ def __mul__(self, other): sage: p.codomain() Finite words over {'a', 'b', 'c', 'd', 'e'} + The composition checks domain/codomain compatibility:: + + sage: s = WordMorphism('a->ba,b->a', domain=Words('ab'), codomain=Words('ba')) + sage: s * s + Traceback (most recent call last): + ... + ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism + TESTS:: sage: m = WordMorphism('a->b,b->c,c->a') sage: WordMorphism('')*m Traceback (most recent call last): ... - KeyError: 'b' + ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism sage: m * WordMorphism('') WordMorphism: """ + # Check that composition is valid: codomain(other) must equal domain(self) + # or at least be compatible (contained with same ordering) + Adom_self = self.domain().alphabet() + Acodom_other = other.codomain().alphabet() + + # Check equality first (handles same ordering requirement) + if Adom_self != Acodom_other: + # If not equal, check containment + if Adom_self.cardinality() < Acodom_other.cardinality(): + raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") + if Adom_self.cardinality() == Infinity: + raise NotImplementedError("composition with infinite alphabets not yet fully supported") + if not all(a in Adom_self for a in Acodom_other): + raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") + # Even if all elements are present, if alphabets have same cardinality but different order, + # this indicates a potential ordering mismatch that should be rejected + if Adom_self.cardinality() == Acodom_other.cardinality(): + raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") + return WordMorphism({key: self(w) for key, w in other._morph.items()}, + domain=other.domain(), codomain=self.codomain()) def __pow__(self, exp): @@ -982,7 +1013,7 @@ def __pow__(self, exp): sage: n^2 Traceback (most recent call last): ... - KeyError: 'c' + ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism """ # If exp is not an integer if not isinstance(exp, (int, Integer)): From f757b41b01cf0441c7a0c53aef9afcc90af05e1a Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 22:41:54 +0800 Subject: [PATCH 02/12] delete whitespaces Refactor composition validation logic in morphism.py. --- src/sage/combinat/words/morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 0921e3bf675..8aaa332aa38 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -959,7 +959,7 @@ def __mul__(self, other): # or at least be compatible (contained with same ordering) Adom_self = self.domain().alphabet() Acodom_other = other.codomain().alphabet() - + # Check equality first (handles same ordering requirement) if Adom_self != Acodom_other: # If not equal, check containment @@ -973,7 +973,7 @@ def __mul__(self, other): # this indicates a potential ordering mismatch that should be rejected if Adom_self.cardinality() == Acodom_other.cardinality(): raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") - + return WordMorphism({key: self(w) for key, w in other._morph.items()}, domain=other.domain(), codomain=self.codomain()) From 9b0073445e1a095dc5c91ff0796aaa753a1f1ad2 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 22:57:17 +0800 Subject: [PATCH 03/12] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/sage/combinat/words/morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 8aaa332aa38..101a82f389c 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -956,7 +956,7 @@ def __mul__(self, other): WordMorphism: """ # Check that composition is valid: codomain(other) must equal domain(self) - # or at least be compatible (contained with same ordering) + # Either the alphabets must be exactly equal (including ordering), or the codomain alphabet must be a proper subset of the domain alphabet (with smaller cardinality) Adom_self = self.domain().alphabet() Acodom_other = other.codomain().alphabet() From 5f3bd7ab512a1b542619b827ed44fcbda9dff55c Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 22:57:24 +0800 Subject: [PATCH 04/12] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/sage/combinat/words/morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 101a82f389c..41cc017da0b 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -960,7 +960,7 @@ def __mul__(self, other): Adom_self = self.domain().alphabet() Acodom_other = other.codomain().alphabet() - # Check equality first (handles same ordering requirement) + # Check equality first (exact match of alphabets including ordering) if Adom_self != Acodom_other: # If not equal, check containment if Adom_self.cardinality() < Acodom_other.cardinality(): From 993e5f1e7294062844da2142e82deb5ee5eb53eb Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 22:57:33 +0800 Subject: [PATCH 05/12] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/sage/combinat/words/morphism.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 41cc017da0b..65580ef027a 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -969,10 +969,6 @@ def __mul__(self, other): raise NotImplementedError("composition with infinite alphabets not yet fully supported") if not all(a in Adom_self for a in Acodom_other): raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") - # Even if all elements are present, if alphabets have same cardinality but different order, - # this indicates a potential ordering mismatch that should be rejected - if Adom_self.cardinality() == Acodom_other.cardinality(): - raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") return WordMorphism({key: self(w) for key, w in other._morph.items()}, domain=other.domain(), From 0f9ced78d31c7a386a18b289497f82821f43d934 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 23:04:27 +0800 Subject: [PATCH 06/12] Improve ValueError message for morphism validation Clarify error message for morphism order mismatch. --- src/sage/combinat/words/morphism.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 65580ef027a..dbefeb0d4f3 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -943,7 +943,7 @@ def __mul__(self, other): sage: s * s Traceback (most recent call last): ... - ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism + ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch) TESTS:: @@ -963,8 +963,8 @@ def __mul__(self, other): # Check equality first (exact match of alphabets including ordering) if Adom_self != Acodom_other: # If not equal, check containment - if Adom_self.cardinality() < Acodom_other.cardinality(): - raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") + if set(Adom_self) == set(Acodom_other): + raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch)") if Adom_self.cardinality() == Infinity: raise NotImplementedError("composition with infinite alphabets not yet fully supported") if not all(a in Adom_self for a in Acodom_other): From 2e4a63e8a8b2a7dabd174354d7d2778e0aff53cf Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Tue, 18 Nov 2025 23:36:36 +0800 Subject: [PATCH 07/12] Fix order mismatch error handling in morphism.py --- src/sage/combinat/words/morphism.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index dbefeb0d4f3..8f4d496cd79 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -963,10 +963,10 @@ def __mul__(self, other): # Check equality first (exact match of alphabets including ordering) if Adom_self != Acodom_other: # If not equal, check containment - if set(Adom_self) == set(Acodom_other): - raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch)") if Adom_self.cardinality() == Infinity: raise NotImplementedError("composition with infinite alphabets not yet fully supported") + if set(Adom_self) == set(Acodom_other): + raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch)") if not all(a in Adom_self for a in Acodom_other): raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") @@ -1244,12 +1244,12 @@ def is_self_composable(self): """ Adom = self.domain().alphabet() Acodom = self.codomain().alphabet() + if Adom.cardinality() == Infinity: + raise NotImplementedError if Adom == Acodom: return True - if Adom.cardinality() < Acodom.cardinality(): + elif Adom.cardinality() <= Acodom.cardinality(): return False - if Adom.cardinality() == Infinity: - raise NotImplementedError return all(a in Adom for a in Acodom) def image(self, letter): From fc8e3e24f73ef52617f71660bbde47bf830f9a92 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Wed, 19 Nov 2025 15:31:57 +0800 Subject: [PATCH 08/12] Refactor --- src/sage/combinat/words/morphism.py | 139 ++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 38 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 8f4d496cd79..f6c9810b7e7 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -894,9 +894,6 @@ def __mul__(self, other): r""" Return the morphism ``self``\*``other``. - The composition is valid only if the codomain alphabet of ``other`` - is contained in the domain alphabet of ``self``. - EXAMPLES:: sage: m = WordMorphism('a->ab,b->ba') @@ -937,41 +934,30 @@ def __mul__(self, other): sage: p.codomain() Finite words over {'a', 'b', 'c', 'd', 'e'} - The composition checks domain/codomain compatibility:: - - sage: s = WordMorphism('a->ba,b->a', domain=Words('ab'), codomain=Words('ba')) - sage: s * s - Traceback (most recent call last): - ... - ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch) - TESTS:: sage: m = WordMorphism('a->b,b->c,c->a') sage: WordMorphism('')*m Traceback (most recent call last): ... - ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism + KeyError: 'b' sage: m * WordMorphism('') WordMorphism: - """ - # Check that composition is valid: codomain(other) must equal domain(self) - # Either the alphabets must be exactly equal (including ordering), or the codomain alphabet must be a proper subset of the domain alphabet (with smaller cardinality) - Adom_self = self.domain().alphabet() - Acodom_other = other.codomain().alphabet() - - # Check equality first (exact match of alphabets including ordering) - if Adom_self != Acodom_other: - # If not equal, check containment - if Adom_self.cardinality() == Infinity: - raise NotImplementedError("composition with infinite alphabets not yet fully supported") - if set(Adom_self) == set(Acodom_other): - raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism (order mismatch)") - if not all(a in Adom_self for a in Acodom_other): - raise ValueError("the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism") - + sage: s = WordMorphism('a->ba,b->a', domain=Words('ab'), codomain=Words('ba')) + sage: s * s + Traceback (most recent call last): + ... + ValueError: the codomain alphabet of the second morphism must be included in the domain alphabet of the first morphism with the same ordering + """ + # Check that other's codomain alphabet is included in self's domain alphabet + # with the correct ordering + if not self._is_alphabet_included_with_order( + other.codomain().alphabet(), self.domain().alphabet()): + raise ValueError("the codomain alphabet of the second morphism must be " + "included in the domain alphabet of the first morphism " + "with the same ordering") + return WordMorphism({key: self(w) for key, w in other._morph.items()}, - domain=other.domain(), codomain=self.codomain()) def __pow__(self, exp): @@ -1009,7 +995,7 @@ def __pow__(self, exp): sage: n^2 Traceback (most recent call last): ... - ValueError: the codomain alphabet of the second morphism must be contained in the domain alphabet of the first morphism + KeyError: 'c' """ # If exp is not an integer if not isinstance(exp, (int, Integer)): @@ -1230,9 +1216,86 @@ def is_endomorphism(self): """ return self.codomain() == self.domain() + def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): + r""" + Check if ``source_alphabet`` is included in ``target_alphabet`` + with the correct ordering. + + This is a helper function for checking composition validity. + For composition ``self * other`` to preserve the incidence matrix + property, we need ``other.codomain().alphabet()`` to be included + in ``self.domain().alphabet()`` with matching order. + + INPUT: + + - ``source_alphabet`` -- the alphabet to check for inclusion + - ``target_alphabet`` -- the alphabet to check inclusion into + + OUTPUT: + + ``True`` if all letters of ``source_alphabet`` appear in + ``target_alphabet`` in the same relative order, ``False`` otherwise. + + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: m._is_alphabet_included_with_order( + ....: Words('ab').alphabet(), Words('ab').alphabet()) + True + sage: m._is_alphabet_included_with_order( + ....: Words('ab').alphabet(), Words('abc').alphabet()) + True + sage: m._is_alphabet_included_with_order( + ....: Words('ba').alphabet(), Words('ab').alphabet()) + False + sage: m._is_alphabet_included_with_order( + ....: Words('ba').alphabet(), Words('abc').alphabet()) + False + sage: m._is_alphabet_included_with_order( + ....: Words('ac').alphabet(), Words('abc').alphabet()) + True + sage: m._is_alphabet_included_with_order( + ....: Words('abc').alphabet(), Words('abc').alphabet()) + True + sage: m._is_alphabet_included_with_order( + ....: Words('abc').alphabet(), Words('ab').alphabet()) + False + """ + # Check if alphabets are equal first (fast path) + if source_alphabet == target_alphabet: + return True + + # Check cardinality constraints + if target_alphabet.cardinality() < source_alphabet.cardinality(): + return False + + if target_alphabet.cardinality() == Infinity: + raise NotImplementedError("cannot check alphabet inclusion for infinite alphabets") + + # Check that all letters in source_alphabet are in target_alphabet + source_list = list(source_alphabet) + target_list = list(target_alphabet) + + if not all(a in target_alphabet for a in source_list): + return False + + # Check that the relative order is preserved + # Find positions of source letters in target + target_positions = {letter: i for i, letter in enumerate(target_list)} + source_positions = [target_positions[letter] for letter in source_list] + + # Check if positions are in increasing order + return all(source_positions[i] < source_positions[i+1] + for i in range(len(source_positions)-1)) + def is_self_composable(self): r""" - Return whether the codomain of ``self`` is contained in the domain. + Return whether the codomain of ``self`` is contained in the domain + with the correct ordering. + + For a morphism to be self-composable (i.e., ``self * self`` to be valid), + the codomain alphabet must be included in the domain alphabet with the + same relative ordering of letters. EXAMPLES:: @@ -1241,16 +1304,16 @@ def is_self_composable(self): False sage: f.is_self_composable() True + + Check that alphabet ordering matters:: + + sage: s = WordMorphism('a->ba,b->a', domain=Words('ab'), codomain=Words('ba')) + sage: s.is_self_composable() + False """ Adom = self.domain().alphabet() Acodom = self.codomain().alphabet() - if Adom.cardinality() == Infinity: - raise NotImplementedError - if Adom == Acodom: - return True - elif Adom.cardinality() <= Acodom.cardinality(): - return False - return all(a in Adom for a in Acodom) + return self._is_alphabet_included_with_order(Acodom, Adom) def image(self, letter): r""" From 4c43ccc48e19d558c75790c70b8c08013e1dfe6d Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Wed, 19 Nov 2025 15:45:50 +0800 Subject: [PATCH 09/12] Improve error messages for WordMorphism Updated error messages to provide clearer feedback when the codomain alphabet is not included in the domain alphabet with the correct ordering. --- src/sage/combinat/words/morphism.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index f6c9810b7e7..ca7a0787c56 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -940,7 +940,7 @@ def __mul__(self, other): sage: WordMorphism('')*m Traceback (most recent call last): ... - KeyError: 'b' + ValueError: the codomain alphabet of the second morphism must be included in the domain alphabet of the first morphism with the same ordering sage: m * WordMorphism('') WordMorphism: sage: s = WordMorphism('a->ba,b->a', domain=Words('ab'), codomain=Words('ba')) @@ -955,8 +955,7 @@ def __mul__(self, other): other.codomain().alphabet(), self.domain().alphabet()): raise ValueError("the codomain alphabet of the second morphism must be " "included in the domain alphabet of the first morphism " - "with the same ordering") - + "with the same ordering") return WordMorphism({key: self(w) for key, w in other._morph.items()}, codomain=self.codomain()) @@ -995,7 +994,7 @@ def __pow__(self, exp): sage: n^2 Traceback (most recent call last): ... - KeyError: 'c' + ValueError: the codomain alphabet of the second morphism must be included in the domain alphabet of the first morphism with the same ordering """ # If exp is not an integer if not isinstance(exp, (int, Integer)): @@ -1218,8 +1217,7 @@ def is_endomorphism(self): def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): r""" - Check if ``source_alphabet`` is included in ``target_alphabet`` - with the correct ordering. + Check if ``source_alphabet`` is included in ``target_alphabet`` with the correct ordering. This is a helper function for checking composition validity. For composition ``self * other`` to preserve the incidence matrix @@ -1233,7 +1231,7 @@ def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): OUTPUT: - ``True`` if all letters of ``source_alphabet`` appear in + ``True`` if all letters of ``source_alphabet`` appear in ``target_alphabet`` in the same relative order, ``False`` otherwise. EXAMPLES:: @@ -1264,28 +1262,28 @@ def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): # Check if alphabets are equal first (fast path) if source_alphabet == target_alphabet: return True - + # Check cardinality constraints if target_alphabet.cardinality() < source_alphabet.cardinality(): return False - + if target_alphabet.cardinality() == Infinity: raise NotImplementedError("cannot check alphabet inclusion for infinite alphabets") - + # Check that all letters in source_alphabet are in target_alphabet source_list = list(source_alphabet) target_list = list(target_alphabet) - + if not all(a in target_alphabet for a in source_list): return False - + # Check that the relative order is preserved # Find positions of source letters in target target_positions = {letter: i for i, letter in enumerate(target_list)} source_positions = [target_positions[letter] for letter in source_list] - + # Check if positions are in increasing order - return all(source_positions[i] < source_positions[i+1] + return all(source_positions[i] < source_positions[i+1] for i in range(len(source_positions)-1)) def is_self_composable(self): From 169cdc524657ac76ac9423ef4b3d8a4c36da1c9b Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Wed, 19 Nov 2025 15:50:51 +0800 Subject: [PATCH 10/12] fix lint --- src/sage/combinat/words/morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index ca7a0787c56..74f8df3efc0 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -955,7 +955,7 @@ def __mul__(self, other): other.codomain().alphabet(), self.domain().alphabet()): raise ValueError("the codomain alphabet of the second morphism must be " "included in the domain alphabet of the first morphism " - "with the same ordering") + "with the same ordering") return WordMorphism({key: self(w) for key, w in other._morph.items()}, codomain=self.codomain()) From b739d8a835627ea75792895309810c19864f466c Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Wed, 19 Nov 2025 16:01:36 +0800 Subject: [PATCH 11/12] Add a doctest to check the empty imput --- src/sage/combinat/words/morphism.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 74f8df3efc0..d655f7728fc 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1258,6 +1258,9 @@ def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): sage: m._is_alphabet_included_with_order( ....: Words('abc').alphabet(), Words('ab').alphabet()) False + sage: m._is_alphabet_included_with_order( + ....: Words('').alphabet(), Words('ab').alphabet()) + True """ # Check if alphabets are equal first (fast path) if source_alphabet == target_alphabet: From 2bd4f9efbeaefa36850d0e18999863be2f6139f0 Mon Sep 17 00:00:00 2001 From: Chenxin Zhong Date: Wed, 19 Nov 2025 19:10:54 +0800 Subject: [PATCH 12/12] Do not appear internal function in document --- src/sage/combinat/words/morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index d655f7728fc..9f0eb992c13 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1216,7 +1216,7 @@ def is_endomorphism(self): return self.codomain() == self.domain() def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): - r""" + """ Check if ``source_alphabet`` is included in ``target_alphabet`` with the correct ordering. This is a helper function for checking composition validity.