From d8591c387cd36d7c7a593692c484cc1393dfda07 Mon Sep 17 00:00:00 2001 From: Josiah Wolf Oberholtzer Date: Mon, 30 May 2016 15:36:23 -0700 Subject: [PATCH 1/4] Refactoring tuplet simplification. --- abjad/tools/agenttools/IterationAgent.py | 18 +++++++++++++++++- ...agenttools_IterationAgent_by_logical_tie.py | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/abjad/tools/agenttools/IterationAgent.py b/abjad/tools/agenttools/IterationAgent.py index c9cb54f5846..8f8812ef60c 100644 --- a/abjad/tools/agenttools/IterationAgent.py +++ b/abjad/tools/agenttools/IterationAgent.py @@ -384,7 +384,7 @@ def by_leaf( .. container:: example - **Example 1.** Iterates leaves: + **Example 1.** Iterates leaves: :: @@ -634,18 +634,34 @@ def by_logical_tie( prototype = (scoretools.Chord, scoretools.Note) if not reverse: for leaf in self.by_class(prototype): + yielded = False tie_spanners = leaf._get_spanners(spannertools.Tie) if not tie_spanners or \ tuple(tie_spanners)[0]._is_my_last_leaf(leaf): logical_tie = leaf._get_logical_tie() + if not nontrivial or not logical_tie.is_trivial: + yielded = True + yield logical_tie + if not yielded: + if tie_spanners and \ + tuple(tie_spanners)[0]._is_my_first_leaf(leaf): + logical_tie = leaf._get_logical_tie() if not nontrivial or not logical_tie.is_trivial: yield logical_tie else: for leaf in self.by_class(prototype, reverse=True): + yielded = False tie_spanners = leaf._get_spanners(spannertools.Tie) if not(tie_spanners) or \ tuple(tie_spanners)[0]._is_my_first_leaf(leaf): logical_tie = leaf._get_logical_tie() + if not nontrivial or not logical_tie.is_trivial: + yielded = True + yield logical_tie + if not yielded: + if tie_spanners and \ + tuple(tie_spanners)[0]._is_my_last_leaf(leaf): + logical_tie = leaf._get_logical_tie() if not nontrivial or not logical_tie.is_trivial: yield logical_tie diff --git a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py index 66e81826d40..54c146ac65d 100644 --- a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py +++ b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py @@ -112,3 +112,18 @@ def test_agenttools_IterationAgent_by_logical_tie_08(): assert logical_ties[0] == selectiontools.LogicalTie(staff[:2]) assert logical_ties[1] == selectiontools.LogicalTie(staff[3:5]) + + +def test_agenttools_IterationAgent_by_logical_tie_09(): + + staff = Staff("{ c'4 d'4 ~ } { d'4 e'4 ~ } { e'4 f'4 }") + + logical_ties = list(iterate(staff[1]).by_logical_tie()) + + assert len(logical_ties) == 2 + assert len(logical_ties[0]) == 2 + assert len(logical_ties[1]) == 2 + assert logical_ties[0][0] is staff[0][1] + assert logical_ties[0][1] is staff[1][0] + assert logical_ties[1][0] is staff[1][1] + assert logical_ties[1][1] is staff[2][0] From bb6f4e0dc9d44d7373a6a6b71baa541388597136 Mon Sep 17 00:00:00 2001 From: Josiah Wolf Oberholtzer Date: Mon, 30 May 2016 16:44:40 -0700 Subject: [PATCH 2/4] Added parentage_mask keyword to IterationAgent.by_logical_tie(). --- abjad/tools/agenttools/IterationAgent.py | 60 +++++++++++++++++++ ...genttools_IterationAgent_by_logical_tie.py | 15 +++++ 2 files changed, 75 insertions(+) diff --git a/abjad/tools/agenttools/IterationAgent.py b/abjad/tools/agenttools/IterationAgent.py index 8f8812ef60c..32aba113ef6 100644 --- a/abjad/tools/agenttools/IterationAgent.py +++ b/abjad/tools/agenttools/IterationAgent.py @@ -550,6 +550,7 @@ def by_logical_tie( nontrivial=False, pitched=False, reverse=False, + parentage_mask=None, ): r'''Iterates client by logical tie. @@ -626,8 +627,39 @@ def by_logical_tie( LogicalTie(Note("c'4"), Note("c'16")) LogicalTie(Note("f'4"), Note("f'16")) + .. container:: example + + **Example 5.** Iterates logical ties masked by parentage. + + .. note:: + + When iterating logical ties in a container, the yielded logical + ties may contain leaves outside that container's parentage. By + specifying a parentage mask, composers can constrain the + contents of the yielded logical ties to only those leaves + actually within the parentage of the container under iteration. + + :: + + >>> staff = Staff("{ c'1 ~ } { c'2 d'2 ~ } { d'1 }") + >>> for logical_tie in iterate(staff[1]).by_logical_tie(): + ... logical_tie + ... + LogicalTie(Note("c'1"), Note("c'2")) + LogicalTie(Note("d'2"), Note("d'1")) + + :: + + >>> for logical_tie in iterate(staff[1]).by_logical_tie( + ... parentage_mask=staff[1]): + ... logical_tie + ... + LogicalTie(Note("c'2"),) + LogicalTie(Note("d'2"),) + Returns generator. ''' + from abjad.tools import selectiontools nontrivial = bool(nontrivial) prototype = scoretools.Leaf if pitched: @@ -639,6 +671,13 @@ def by_logical_tie( if not tie_spanners or \ tuple(tie_spanners)[0]._is_my_last_leaf(leaf): logical_tie = leaf._get_logical_tie() + if parentage_mask: + logical_tie = selectiontools.LogicalTie( + x for x in logical_tie + if parentage_mask in x._get_parentage() + ) + if not logical_tie: + continue if not nontrivial or not logical_tie.is_trivial: yielded = True yield logical_tie @@ -646,6 +685,13 @@ def by_logical_tie( if tie_spanners and \ tuple(tie_spanners)[0]._is_my_first_leaf(leaf): logical_tie = leaf._get_logical_tie() + if parentage_mask: + logical_tie = selectiontools.LogicalTie( + x for x in logical_tie + if parentage_mask in x._get_parentage() + ) + if not logical_tie: + return if not nontrivial or not logical_tie.is_trivial: yield logical_tie else: @@ -655,6 +701,13 @@ def by_logical_tie( if not(tie_spanners) or \ tuple(tie_spanners)[0]._is_my_first_leaf(leaf): logical_tie = leaf._get_logical_tie() + if parentage_mask: + logical_tie = selectiontools.LogicalTie( + x for x in logical_tie + if parentage_mask in x._get_parentage() + ) + if not logical_tie: + continue if not nontrivial or not logical_tie.is_trivial: yielded = True yield logical_tie @@ -662,6 +715,13 @@ def by_logical_tie( if tie_spanners and \ tuple(tie_spanners)[0]._is_my_last_leaf(leaf): logical_tie = leaf._get_logical_tie() + if parentage_mask: + logical_tie = selectiontools.LogicalTie( + x for x in logical_tie + if parentage_mask in x._get_parentage() + ) + if not logical_tie: + return if not nontrivial or not logical_tie.is_trivial: yield logical_tie diff --git a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py index 54c146ac65d..55c520c4561 100644 --- a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py +++ b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py @@ -127,3 +127,18 @@ def test_agenttools_IterationAgent_by_logical_tie_09(): assert logical_ties[0][1] is staff[1][0] assert logical_ties[1][0] is staff[1][1] assert logical_ties[1][1] is staff[2][0] + + +def test_agenttools_IterationAgent_by_logical_tie_10(): + + staff = Staff("{ c'4 d'4 ~ } { d'4 e'4 ~ } { e'4 f'4 }") + + logical_ties = list(iterate(staff[1]) + .by_logical_tie(parentage_mask=staff[1]) + ) + + assert len(logical_ties) == 2 + assert len(logical_ties[0]) == 1 + assert len(logical_ties[1]) == 1 + assert logical_ties[0][0] is staff[1][0] + assert logical_ties[1][0] is staff[1][1] From 0c86c9be6828b63eaa079c4a2224e9375a6eb723 Mon Sep 17 00:00:00 2001 From: Josiah Wolf Oberholtzer Date: Mon, 30 May 2016 16:45:02 -0700 Subject: [PATCH 3/4] Refactored Tuplet._simplify_redundant_tuplet(). --- abjad/tools/scoretools/Tuplet.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/abjad/tools/scoretools/Tuplet.py b/abjad/tools/scoretools/Tuplet.py index 76661b0ee2a..3dcd523be56 100644 --- a/abjad/tools/scoretools/Tuplet.py +++ b/abjad/tools/scoretools/Tuplet.py @@ -5,6 +5,7 @@ from abjad.tools import mathtools from abjad.tools.scoretools.Container import Container from abjad.tools.topleveltools import inspect_ +from abjad.tools.topleveltools import iterate from abjad.tools.topleveltools import mutate from abjad.tools.topleveltools import override @@ -354,11 +355,24 @@ def _simplify_redundant_tuplet(self): from abjad.tools import scoretools if not self.is_redundant: return - leaves = self[:] - leaf_durations = [inspect_(_).get_duration() for _ in leaves] - tuplet_duration = sum(leaf_durations) - for leaf_duration, leaf in zip(leaf_durations, leaves): - leaf.written_duration = leaf_duration + leaves = [] + logical_ties = list(iterate(self).by_logical_tie(parentage_mask=self)) + durations = [_.get_duration() for _ in logical_ties] + tuplet_duration = sum(durations) + for i, logical_tie in enumerate(logical_ties): + duration = durations[i] + if i == len(logical_ties) - 1: + leaf = logical_tie[-1] + else: + leaf = logical_tie[0] + leaf.written_duration = duration + leaves.append(leaf) + self[:] = leaves + #leaves = self[:] + #leaf_durations = [inspect_(_).get_duration() for _ in leaves] + #tuplet_duration = sum(leaf_durations) + #for leaf_duration, leaf in zip(leaf_durations, leaves): + # leaf.written_duration = leaf_duration if isinstance(self, scoretools.FixedDurationTuplet): self.target_duration = tuplet_duration else: @@ -914,11 +928,8 @@ def is_redundant(self): Returns true or false. ''' - from abjad.tools import scoretools - if not all(isinstance(_, scoretools.Leaf) for _ in self): - return False - leaf_durations = [inspect_(_).get_duration() for _ in self] - return all(_.is_assignable for _ in leaf_durations) + logical_ties = iterate(self).by_logical_tie(parentage_mask=self) + return all(_.get_duration().is_assignable for _ in logical_ties) @property def is_trivial(self): From 3d488c8c92a0b9852fd3aebdcdc7c854cc17a6fb Mon Sep 17 00:00:00 2001 From: Josiah Wolf Oberholtzer Date: Mon, 30 May 2016 17:12:48 -0700 Subject: [PATCH 4/4] Fixed logical tie iteration edge-case. --- abjad/tools/agenttools/IterationAgent.py | 5 +++-- .../test/test_agenttools_IterationAgent_by_logical_tie.py | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/abjad/tools/agenttools/IterationAgent.py b/abjad/tools/agenttools/IterationAgent.py index 32aba113ef6..a4ee7cfdcee 100644 --- a/abjad/tools/agenttools/IterationAgent.py +++ b/abjad/tools/agenttools/IterationAgent.py @@ -664,6 +664,7 @@ def by_logical_tie( prototype = scoretools.Leaf if pitched: prototype = (scoretools.Chord, scoretools.Note) + leaf, yielded = None, False if not reverse: for leaf in self.by_class(prototype): yielded = False @@ -681,7 +682,7 @@ def by_logical_tie( if not nontrivial or not logical_tie.is_trivial: yielded = True yield logical_tie - if not yielded: + if leaf is not None and not yielded: if tie_spanners and \ tuple(tie_spanners)[0]._is_my_first_leaf(leaf): logical_tie = leaf._get_logical_tie() @@ -711,7 +712,7 @@ def by_logical_tie( if not nontrivial or not logical_tie.is_trivial: yielded = True yield logical_tie - if not yielded: + if leaf is not None and not yielded: if tie_spanners and \ tuple(tie_spanners)[0]._is_my_last_leaf(leaf): logical_tie = leaf._get_logical_tie() diff --git a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py index 55c520c4561..f3ae9669091 100644 --- a/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py +++ b/abjad/tools/agenttools/test/test_agenttools_IterationAgent_by_logical_tie.py @@ -142,3 +142,10 @@ def test_agenttools_IterationAgent_by_logical_tie_10(): assert len(logical_ties[1]) == 1 assert logical_ties[0][0] is staff[1][0] assert logical_ties[1][0] is staff[1][1] + + +def test_agenttools_IterationAgent_by_logical_tie_11(): + r'''No logical ties, but no errors either.''' + staff = Staff() + logical_ties = list(iterate(staff).by_logical_tie()) + assert len(logical_ties) == 0