def test_mathtools_Ratio___eq___01(): ratio_1 = mathtools.Ratio((1, 2, 1)) ratio_2 = mathtools.Ratio((1, 2, 1)) ratio_3 = mathtools.Ratio((2, 3, 3)) assert ratio_1 == ratio_1 assert ratio_1 == ratio_2 assert not ratio_1 == ratio_3 assert ratio_2 == ratio_1 assert ratio_2 == ratio_2 assert not ratio_2 == ratio_3 assert not ratio_3 == ratio_1 assert not ratio_3 == ratio_2 assert ratio_3 == ratio_3
def _get_ratios(self): if self.ratios: ratios = self.ratios else: ratios = (mathtools.Ratio([1]), ) ratios = datastructuretools.CyclicTuple(ratios) return ratios
def test_systemtools_StorageFormatAgent_get_import_statements_04(): subject = rhythmmakertools.IncisedRhythmMaker( incise_specifier=rhythmmakertools.InciseSpecifier( prefix_talea=(1, ), prefix_counts=(0, ), suffix_talea=(1, ), suffix_counts=(1, ), talea_denominator=16, body_ratio=mathtools.Ratio((1, )), outer_divisions_only=True, ), beam_specifier=rhythmmakertools.BeamSpecifier( beam_each_division=False, beam_divisions_together=False, ), duration_spelling_specifier=rhythmmakertools.DurationSpellingSpecifier( decrease_durations_monotonically=True, forbidden_written_duration=durationtools.Duration(1, 2), ), tuplet_spelling_specifier=rhythmmakertools.TupletSpellingSpecifier( avoid_dots=True, is_diminution=True, simplify_redundant_tuplets=True, ), ) agent = systemtools.StorageFormatAgent(subject) assert agent.get_import_statements() == ( 'from abjad.tools import durationtools', 'from abjad.tools import mathtools', 'from abjad.tools import rhythmmakertools', )
def __init__( self, ratios=None, ): if ratios is not None: ratios = ratios or () ratios = [mathtools.Ratio(_) for _ in ratios] ratios = tuple(ratios) self._ratios = ratios
def partition_sequence_by_ratio_of_lengths(sequence, ratio): '''Partitions `sequence` by `ratio` of lengths. .. container:: example **Example 1.** Partitions sequence by ``1:1:1`` ratio: :: >>> sequence = list(range(10)) >>> sequencetools.partition_sequence_by_ratio_of_lengths( ... sequence, ... [1, 1, 1], ... ) [[0, 1, 2], [3, 4, 5, 6], [7, 8, 9]] Returns list of lists. .. container:: example **Example 2.** Partitions sequence by ``1:1:2`` ratio: :: >>> sequence = tuple(range(10)) >>> sequencetools.partition_sequence_by_ratio_of_lengths( ... sequence, ... [1, 1, 2], ... ) [(0, 1, 2), (3, 4), (5, 6, 7, 8, 9)] Returns list of tuples. Uses the rounding magic implemented in ``mathtools.partition_integer_by_ratio()`` to avoid fractional part lengths. Returns list of `sequence` objects. ''' from abjad.tools import sequencetools if sequence is None: callback = sequencetools.PartitionByRatioOfLengthsCallback( ratio=ratio, ) return callback ratio = mathtools.Ratio(ratio) counts = mathtools.partition_integer_by_ratio(len(sequence), ratio) return sequencetools.partition_sequence_by_counts( sequence, counts, cyclic=False, overhang=Exact, )
def __init__( self, prefix_talea=None, prefix_counts=None, suffix_talea=None, suffix_counts=None, talea_denominator=None, body_ratio=None, fill_with_notes=True, outer_divisions_only=None, ): prefix_talea = prefix_talea or () prefix_talea = tuple(prefix_talea) assert self._is_integer_tuple(prefix_talea) self._prefix_talea = prefix_talea prefix_counts = prefix_counts or () prefix_counts = tuple(prefix_counts) assert self._is_length_tuple(prefix_counts) self._prefix_counts = prefix_counts if prefix_counts and prefix_counts != (0, ): assert prefix_talea if prefix_talea: assert prefix_counts suffix_talea = suffix_talea or () suffix_talea = tuple(suffix_talea) assert self._is_integer_tuple(suffix_talea) self._suffix_talea = suffix_talea assert self._is_length_tuple(suffix_counts) suffix_counts = suffix_counts or () suffix_counts = tuple(suffix_counts) self._suffix_counts = suffix_counts if suffix_counts and suffix_counts != (0, ): assert suffix_talea if suffix_talea: assert suffix_counts if talea_denominator is not None: if not mathtools.is_nonnegative_integer_power_of_two( talea_denominator): message = 'talea denominator {!r} must be nonnegative' message += ' integer power of 2.' message = message.format(talea_denominator) raise Exception(message) self._talea_denominator = talea_denominator if prefix_talea or suffix_talea: assert talea_denominator is not None if body_ratio is not None: body_ratio = mathtools.Ratio(body_ratio) self._body_ratio = body_ratio assert isinstance(fill_with_notes, bool) self._fill_with_notes = fill_with_notes assert isinstance(outer_divisions_only, (bool, type(None))) self._outer_divisions_only = outer_divisions_only
def partition_by_ratio_of_durations(self, ratio): r'''Partition payload by `ratio` of durations. Returns tuple of newly constructed expressions with callbacks. ''' result = [] ratio = mathtools.Ratio(ratio) for part in range(len(ratio)): callback = \ 'result = self._partition_by_ratio_of_durations(payload_expression, {!r}, {!r})' callback = callback.format(ratio, part) result.append(self._copy_and_append_callback(callback)) return tuple(result)
def __init__( self, prefix_talea=None, prefix_counts=None, suffix_talea=None, suffix_counts=None, talea_denominator=None, body_ratio=None, fill_with_notes=True, outer_divisions_only=False, ): prefix_talea = prefix_talea or () prefix_talea = tuple(prefix_talea) assert self._is_integer_tuple(prefix_talea) self._prefix_talea = prefix_talea prefix_counts = prefix_counts or () prefix_counts = tuple(prefix_counts) assert self._is_length_tuple(prefix_counts) self._prefix_counts = prefix_counts if prefix_counts and prefix_counts != (0, ): assert prefix_talea if prefix_talea: assert prefix_counts suffix_talea = suffix_talea or () suffix_talea = tuple(suffix_talea) assert self._is_integer_tuple(suffix_talea) self._suffix_talea = suffix_talea assert self._is_length_tuple(suffix_counts) suffix_counts = suffix_counts or () suffix_counts = tuple(suffix_counts) self._suffix_counts = suffix_counts if suffix_counts and suffix_counts != (0, ): assert suffix_talea if suffix_talea: assert suffix_counts if talea_denominator is not None: assert mathtools.is_nonnegative_integer_power_of_two( talea_denominator) self._talea_denominator = talea_denominator if prefix_talea or suffix_talea: assert talea_denominator is not None if body_ratio is not None: body_ratio = mathtools.Ratio(body_ratio) self._body_ratio = body_ratio assert isinstance(fill_with_notes, bool) self._fill_with_notes = fill_with_notes assert isinstance(outer_divisions_only, bool) self._outer_divisions_only = outer_divisions_only
def divide_number_by_ratio(number, ratio): r'''Divides integer by `ratio`. :: >>> mathtools.divide_number_by_ratio(1, [1, 1, 3]) [Fraction(1, 5), Fraction(1, 5), Fraction(3, 5)] Divides fraction by `ratio`: :: >>> mathtools.divide_number_by_ratio(Fraction(1), [1, 1, 3]) [Fraction(1, 5), Fraction(1, 5), Fraction(3, 5)] Divides float by ratio: :: >>> mathtools.divide_number_by_ratio(1.0, [1, 1, 3]) # doctest: +SKIP [0.20000000000000001, 0.20000000000000001, 0.60000000000000009] Raises type error on nonnumeric `number`. Raises type error on noninteger in `ratio`. Returns list of fractions or list of floats. ''' from abjad.tools import mathtools # check input assert isinstance(number, numbers.Number) ratio = mathtools.Ratio(ratio) # find factors and multiply by factors factors = [ fractions.Fraction(p, sum(ratio.numbers)) for p in ratio.numbers ] result = [factor * number for factor in factors] # return result return result
def ratio(self): r'''Gets ratio of metric modulation. .. container:: example :: >>> metric_modulation = indicatortools.MetricModulation( ... left_rhythm=Tuplet((2, 3), [Note("c'4")]), ... right_rhythm=Note("c'4"), ... ) >>> metric_modulation.ratio Ratio((2, 3)) Returns ratio. ''' left_duration = self.left_rhythm.get_duration() right_duration = self.right_rhythm.get_duration() duration = left_duration / right_duration ratio = mathtools.Ratio(duration.pair) return ratio
def _to_tuplet_with_ratio(self, proportions, is_diminution=True): from abjad.tools import scoretools # check input proportions = mathtools.Ratio(proportions) # find target duration of fixed-duration tuplet target_duration = self.written_duration # find basic duration of note in tuplet basic_prolated_duration = target_duration / sum(proportions.numbers) # find basic written duration of note in tuplet basic_written_duration = \ basic_prolated_duration.equal_or_greater_assignable # find written duration of each note in tuplet written_durations = [ _ * basic_written_duration for _ in proportions.numbers ] # make tuplet notes try: notes = [scoretools.Note(0, x) for x in written_durations] except AssignabilityError: denominator = target_duration._denominator note_durations = [ durationtools.Duration(_, denominator) for _ in proportions.numbers ] notes = scoretools.make_notes(0, note_durations) # make tuplet tuplet = scoretools.FixedDurationTuplet(target_duration, notes) # fix tuplet contents if necessary tuplet._fix() # change prolation if necessary if not tuplet.multiplier == 1: if is_diminution: if not tuplet.is_diminution: tuplet.toggle_prolation() else: if tuplet.is_diminution: tuplet.toggle_prolation() # return tuplet return tuplet
def tessalate_by_ratio( self, ratio, invert_on_negative=False, reflect_on_negative=False, y_center=None, ): r'''Concatenate copies of a BreakPointFunction, stretched by the weights in `ratio`: :: >>> bpf = interpolationtools.BreakPointFunction( ... {0.: 0., 0.25: 0.9, 1.: 1.}) :: >>> bpf.tessalate_by_ratio((1, 2, 3)) BreakPointFunction({ 0.0: (0.0,), 0.25: (0.9,), 1.0: (1.0, 0.0), 1.5: (0.9,), 3.0: (1.0, 0.0), 3.75: (0.9,), 6.0: (1.0,) }) Negative ratio values are still treated as weights. If `invert_on_negative` is True, copies corresponding to negative ratio values will be inverted: :: >>> bpf.tessalate_by_ratio((1, -2, 3), invert_on_negative=True) BreakPointFunction({ 0.0: (0.0,), 0.25: (0.9,), 1.0: (1.0,), 1.5: (0.09999999999999998,), 3.0: (0.0,), 3.75: (0.9,), 6.0: (1.0,) }) If `y_center` is not None, inversion will take `y_center` as the axis of inversion: :: >>> bpf.tessalate_by_ratio((1, -2, 3), ... invert_on_negative=True, y_center=0) BreakPointFunction({ 0.0: (0.0,), 0.25: (0.9,), 1.0: (1.0, 0.0), 1.5: (-0.9,), 3.0: (-1.0, 0.0), 3.75: (0.9,), 6.0: (1.0,) }) If `reflect_on_negative` is True, copies corresponding to negative ratio values will be reflected: :: >>> bpf.tessalate_by_ratio((1, -2, 3), reflect_on_negative=True) BreakPointFunction({ 0.0: (0.0,), 0.25: (0.9,), 1.0: (1.0,), 2.5: (0.9,), 3.0: (0.0,), 3.75: (0.9,), 6.0: (1.0,) }) Inversion may be combined reflecting. Emit new `BreakPointFunction` instance. ''' ratio = mathtools.Ratio(ratio) tessalated_bpf = None for i, pair in enumerate( mathtools.cumulative_sums_pairwise( [abs(x) for x in ratio.numbers])): sign = mathtools.sign(ratio.numbers[i]) start, stop = pair bpf = self.scale_x_axis(start, stop) if sign < 0: if invert_on_negative: bpf = bpf.invert(y_center) if reflect_on_negative: bpf = bpf.reflect() if i == 0: tessalated_bpf = bpf else: tessalated_bpf = tessalated_bpf.concatenate(bpf) return tessalated_bpf
def test_mathtools_Ratio___eq___02(): r'''Comparison works with tuples. ''' assert mathtools.Ratio((1, 2, 1)) == (1, 2, 1)
def partition_integer_by_ratio(n, ratio): r'''Partitions positive integer-equivalent `n` by `ratio`. .. container:: example >>> abjad.mathtools.partition_integer_by_ratio(10, [1, 2]) [3, 7] .. container:: example Partitions positive integer-equivalent `n` by `ratio` with negative parts: >>> abjad.mathtools.partition_integer_by_ratio(10, [1, -2]) [3, -7] .. container:: example Partitions negative integer-equivalent `n` by `ratio`: >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 2]) [-3, -7] .. container:: example Partitions negative integer-equivalent `n` by `ratio` with negative parts: >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, -2]) [-3, 7] .. container:: example More examples: >>> abjad.mathtools.partition_integer_by_ratio(10, [1]) [10] >>> abjad.mathtools.partition_integer_by_ratio(10, [1, 1]) [5, 5] >>> abjad.mathtools.partition_integer_by_ratio(10, [1, -1, -1]) [3, -4, -3] >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 1, 1, 1]) [-3, -2, -3, -2] >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 1, 1, 1, 1]) [-2, -2, -2, -2, -2] Returns result with weight equal to absolute value of `n`. Returns list of integers. ''' from abjad.tools import mathtools if not mathtools.is_integer_equivalent_number(n): message = 'is not integer-equivalent number: {!r}.' message = message.format(n) raise TypeError(message) ratio = mathtools.Ratio(ratio).numbers if not all(mathtools.is_integer_equivalent_number(part) for part in ratio): message = 'some parts in {!r} not integer-equivalent numbers.' message = message.format(ratio) raise TypeError(message) result = [0] divisions = [ float(abs(n)) * abs(part) / mathtools.weight(ratio) for part in ratio ] cumulative_divisions = mathtools.cumulative_sums(divisions, start=None) for division in cumulative_divisions: rounded_division = int(round(division)) - sum(result) if division - round(division) == 0.5: rounded_division += 1 result.append(rounded_division) result = result[1:] if mathtools.sign(n) == -1: result = [-x for x in result] ratio_signs = [mathtools.sign(x) for x in ratio] result = [pair[0] * pair[1] for pair in zip(ratio_signs, result)] return result
def __init__(self, ratio=None): ratio = ratio or mathtools.Ratio((1, )) ratio = mathtools.Ratio(ratio) self._ratio = ratio
def to_tuplet( self, proportions, dotted=False, is_diminution=True, ): r'''Change logical tie to tuplet. .. container:: example **Example 1.** Change logical tie to diminished tuplet: :: >>> staff = Staff(r"c'8 ~ c'16 cqs''4") >>> crescendo = spannertools.Hairpin(descriptor='p < f') >>> attach(crescendo, staff[:]) >>> override(staff).dynamic_line_spanner.staff_padding = 3 >>> time_signature = TimeSignature((7, 16)) >>> attach(time_signature, staff) .. doctest:: >>> print(format(staff)) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 c'8 ~ \< \p c'16 cqs''4 \f } :: >>> show(staff) # doctest: +SKIP :: >>> logical_tie = inspect_(staff[0]).get_logical_tie() >>> logical_tie.to_tuplet([2, 1, 1, 1], is_diminution=True) FixedDurationTuplet(Duration(3, 16), "c'8 c'16 c'16 c'16") .. doctest:: >>> print(format(staff)) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 \tweak #'text #tuplet-number::calc-fraction-text \times 3/5 { c'8 \< \p c'16 c'16 c'16 } cqs''4 \f } :: >>> show(staff) # doctest: +SKIP .. container:: example **Example 2.** Change logical tie to augmented tuplet: :: >>> staff = Staff(r"c'8 ~ c'16 cqs''4") >>> crescendo = spannertools.Hairpin(descriptor='p < f') >>> attach(crescendo, staff[:]) >>> override(staff).dynamic_line_spanner.staff_padding = 3 >>> time_signature = TimeSignature((7, 16)) >>> attach(time_signature, staff) .. doctest:: >>> print(format(staff)) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 c'8 ~ \< \p c'16 cqs''4 \f } :: >>> show(staff) # doctest: +SKIP :: >>> logical_tie = inspect_(staff[0]).get_logical_tie() >>> logical_tie.to_tuplet([2, 1, 1, 1], is_diminution=False) FixedDurationTuplet(Duration(3, 16), "c'16 c'32 c'32 c'32") .. doctest:: >>> print(format(staff)) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 \tweak #'text #tuplet-number::calc-fraction-text \times 6/5 { c'16 \< \p c'32 c'32 c'32 } cqs''4 \f } :: >>> show(staff) # doctest: +SKIP Returns tuplet. ''' from abjad.tools import scoretools from abjad.tools import mathtools from abjad.tools import agenttools from abjad.tools import scoretools from abjad.tools import spannertools from abjad.tools import scoretools # coerce input proportions = mathtools.Ratio(proportions) # find target duration of fixed-duration tuplet target_duration = self._preprolated_duration # find duration of each note in tuplet prolated_duration = target_duration / sum(proportions) # find written duration of each notes in tuplet if is_diminution: if dotted: basic_written_duration = \ prolated_duration.equal_or_greater_assignable else: basic_written_duration = \ prolated_duration.equal_or_greater_power_of_two else: if dotted: basic_written_duration = \ prolated_duration.equal_or_lesser_assignable else: basic_written_duration = \ prolated_duration.equal_or_lesser_power_of_two # find written duration of each note in tuplet written_durations = [x * basic_written_duration for x in proportions] # make tuplet notes try: notes = [scoretools.Note(0, x) for x in written_durations] except AssignabilityError: denominator = target_duration._denominator note_durations = [durationtools.Duration(x, denominator) for x in proportions] notes = scoretools.make_notes(0, note_durations) # make tuplet tuplet = scoretools.FixedDurationTuplet(target_duration, notes) # replace logical tie with tuplet mutate(self).replace(tuplet) # untie tuplet for spanner in tuplet._get_spanners(spannertools.Tie): spanner._sever_all_components() #detach(spannertools.Tie, tuplet) # return tuplet return tuplet
def partition_integer_by_ratio(n, ratio): r'''Partitions positive integer-equivalent `n` by `ratio`. :: >>> mathtools.partition_integer_by_ratio(10, [1, 2]) [3, 7] Partitions positive integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(10, [1, -2]) [3, -7] Partitions negative integer-equivalent `n` by `ratio`: :: >>> mathtools.partition_integer_by_ratio(-10, [1, 2]) [-3, -7] Partitions negative integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(-10, [1, -2]) [-3, 7] Returns result with weight equal to absolute value of `n`. Raises type error on noninteger `n`. Returns list of integers. ''' from abjad.tools import mathtools if not mathtools.is_integer_equivalent_number(n): message = 'is not integer-equivalent number: {!r}.' message = message.format(n) raise TypeError(message) ratio = mathtools.Ratio(ratio).numbers if not all(mathtools.is_integer_equivalent_number(part) for part in ratio): message = 'some parts in {!r} not integer-equivalent numbers.' message = message.format(ratio) raise TypeError(message) result = [0] divisions = [ float(abs(n)) * abs(part) / mathtools.weight(ratio) for part in ratio ] cumulative_divisions = mathtools.cumulative_sums(divisions, start=None) for division in cumulative_divisions: rounded_division = int(round(division)) - sum(result) #This makes rounding behave like python 2. Would be good to remove # in the long run if sys.version_info[0] == 3: if division - round(division) == 0.5: rounded_division += 1 result.append(rounded_division) result = result[1:] # adjust signs of output elements if mathtools.sign(n) == -1: result = [-x for x in result] ratio_signs = [mathtools.sign(x) for x in ratio] result = [pair[0] * pair[1] for pair in zip(ratio_signs, result)] # return result return result
def list_related_tempos( self, maximum_numerator=None, maximum_denominator=None, ): r'''Lists tempos related to this tempo. Returns list of tempo / ratio pairs. Each new tempo equals not less than half of this tempo and not more than twice this tempo. .. container:: example Rewrites tempo ``58`` MM by ratios of the form ``n:d`` such that ``1 <= n <= 8`` and ``1 <= d <= 8``: ... :: >>> tempo = Tempo(Duration(1, 4), 58) >>> pairs = tempo.list_related_tempos( ... maximum_numerator=8, ... maximum_denominator=8, ... ) :: >>> for tempo, ratio in pairs: ... string = '{!s}\t{!s}'.format(tempo, ratio) ... print(string) 4=29 1:2 4=58 1:1 4=87 3:2 4=116 2:1 .. container:: example Rewrites tempo ``58`` MM by ratios of the form ``n:d`` such that ``1 <= n <= 30`` and ``1 <= d <= 30``: :: >>> tempo = Tempo(Duration(1, 4), 58) >>> pairs = tempo.list_related_tempos( ... maximum_numerator=30, ... maximum_denominator=30, ... ) :: >>> for tempo, ratio in pairs: ... string = '{!s}\t{!s}'.format(tempo, ratio) ... print(string) ... 4=30 15:29 4=32 16:29 4=34 17:29 4=36 18:29 4=38 19:29 4=40 20:29 4=42 21:29 4=44 22:29 4=46 23:29 4=48 24:29 4=50 25:29 4=52 26:29 4=54 27:29 4=56 28:29 4=58 1:1 4=60 30:29 Returns list. ''' # assert integer tempo assert isinstance(self.units_per_minute, int), repr(self) # find divisors divisors = mathtools.divisors(self.units_per_minute) if maximum_denominator is not None: divisors = [x for x in divisors if x <= maximum_denominator] # make pairs pairs = [] for divisor in divisors: start = int(math.ceil(divisor / 2.0)) stop = 2 * divisor numerators = range(start, stop + 1) if maximum_numerator is not None: numerators = [ x for x in numerators if x <= maximum_numerator ] for numerator in numerators: ratio = mathtools.Ratio(numerator, divisor) multiplier = durationtools.Multiplier(*ratio) new_units_per_minute = multiplier * self.units_per_minute assert mathtools.is_integer_equivalent_expr( new_units_per_minute) new_units_per_minute = int(new_units_per_minute) new_tempo = type(self)( duration=self.duration, units_per_minute=new_units_per_minute, ) pair = (new_tempo, ratio) if pair not in pairs: pairs.append(pair) # sort pairs pairs.sort() # return pairs return pairs