def alpha(self): r"""Morris alpha transform of pitch-class segment: :: >>> pitch_class_segment = pitchtools.PitchClassSegment( ... tokens=[-2, -1.5, 6, 7, -1.5, 7], ... ) >>> pitch_class_segment.alpha() PitchClassSegment([11, 11.5, 7, 6, 11.5, 6]) Returns new pitch-class segment. """ from abjad.tools import mathtools numbers = [] for pc in self: pc = abs(float(pc)) is_integer = True if not mathtools.is_integer_equivalent_number(pc): is_integer = False fraction_part = pc - int(pc) pc = int(pc) if abs(pc) % 2 == 0: number = (abs(pc) + 1) % 12 else: number = abs(pc) - 1 if not is_integer: number += fraction_part else: number = int(number) numbers.append(number) return new(self, tokens=numbers)
def alpha(self): r'''Morris alpha transform of pitch-class segment: :: >>> pitch_class_segment = pitchtools.PitchClassSegment( ... items=[-2, -1.5, 6, 7, -1.5, 7], ... ) >>> pitch_class_segment.alpha() PitchClassSegment([11, 11.5, 7, 6, 11.5, 6]) Returns new pitch-class segment. ''' from abjad.tools import mathtools numbers = [] for pc in self: pc = abs(float(pc)) is_integer = True if not mathtools.is_integer_equivalent_number(pc): is_integer = False fraction_part = pc - int(pc) pc = int(pc) if abs(pc) % 2 == 0: number = (abs(pc) + 1) % 12 else: number = abs(pc) - 1 if not is_integer: number += fraction_part else: number = int(number) numbers.append(number) return new(self, items=numbers)
def is_integer_equivalent_expr(expr): '''Is true when `expr` is an integer-equivalent number. :: >>> mathtools.is_integer_equivalent_expr(12.0) True Is true when `expr` evaluates to an integer: :: >>> mathtools.is_integer_equivalent_expr('12') True Otherwise false: :: >>> mathtools.is_integer_equivalent_expr('foo') False Returns true or false. ''' from abjad.tools import mathtools if isinstance(expr, numbers.Number): return mathtools.is_integer_equivalent_number(expr) try: int(expr) return True except (TypeError, ValueError): return False
def integer_equivalent_number_to_integer(number): '''Integer-equivalent `number` to integer. :: >>> mathtools.integer_equivalent_number_to_integer(17.0) 17 Returns noninteger-equivalent number unchanged: :: >>> mathtools.integer_equivalent_number_to_integer(17.5) 17.5 Raises type error on nonnumber input. Returns number. ''' from abjad.tools import mathtools if not isinstance(number, numbers.Number): message = 'must be number: {!r}.' message = message.format(number) raise TypeError(message) if mathtools.is_integer_equivalent_number(number): return int(number) else: return number
def integer_equivalent_number_to_integer(number): '''Integer-equivalent `number` to integer. :: >>> mathtools.integer_equivalent_number_to_integer(17.0) 17 Returns noninteger-equivalent number unchanged: :: >>> mathtools.integer_equivalent_number_to_integer(17.5) 17.5 Raises type error on nonnumber input. Returns number. ''' from abjad.tools import mathtools if not isinstance(number, numbers.Number): message = 'must be number: {!r}.' message = message.format(number) raise TypeError(message) if mathtools.is_integer_equivalent_number(number): return int(number) else: return number
def integer_equivalent_number_to_integer(number): '''Changes integer-equivalent `number` to integer. .. container:: example Returns integer-equivalent number as integer: >>> abjad.mathtools.integer_equivalent_number_to_integer(17.0) 17 .. container:: example Returns noninteger-equivalent number unchanged: >>> abjad.mathtools.integer_equivalent_number_to_integer(17.5) 17.5 Returns number. ''' from abjad.tools import mathtools if not isinstance(number, numbers.Number): message = 'must be number: {!r}.' message = message.format(number) raise TypeError(message) if mathtools.is_integer_equivalent_number(number): return int(number) else: return number
def is_integer_equivalent(argument): '''Is true when `argument` is an integer-equivalent number. Otherwise false. .. container:: example >>> abjad.mathtools.is_integer_equivalent(12.0) True >>> abjad.mathtools.is_integer_equivalent('12') True >>> abjad.mathtools.is_integer_equivalent('foo') False Returns true or false. ''' from abjad.tools import mathtools if isinstance(argument, numbers.Number): return mathtools.is_integer_equivalent_number(argument) try: int(argument) return True except (TypeError, ValueError): return False
def __int__(self): r'''Changes named pitch to integer. :: >>> int(pitch) 13 Returns integer. ''' if not mathtools.is_integer_equivalent_number(self.pitch_number): raise TypeError return int(self.pitch_number)
def __int__(self): r'''Changes named pitch to integer. :: >>> int(pitch) 13 Returns integer. ''' if not mathtools.is_integer_equivalent_number(self.pitch_number): raise TypeError return int(self.pitch_number)
def is_positive_integer_equivalent_number(expr): '''Is true when `expr` is a positive integer-equivalent number. Otherwise false: :: >>> mathtools.is_positive_integer_equivalent_number(Duration(4, 2)) True Returns boolean. ''' from abjad.tools import mathtools return 0 < expr and mathtools.is_integer_equivalent_number(expr)
def is_nonnegative_integer_equivalent_number(expr): '''Is true when `expr` is a nonnegative integer-equivalent number. Otherwise false: :: >>> mathtools.is_nonnegative_integer_equivalent_number(Duration(4, 2)) True Returns true or false. ''' from abjad.tools import mathtools return mathtools.is_integer_equivalent_number(expr) and 0 <= expr
def rewrite_integer_tempo(integer_tempo, maximum_numerator=None, maximum_denominator=None): r'''Rewrite `integer_tempo`. Allow no tempo less than half `integer_tempo` or greater than double `integer_tempo`: :: >>> pairs = tempotools.rewrite_integer_tempo( ... 58, maximum_numerator=8, maximum_denominator=8) :: >>> for pair in pairs: ... pair ... (Multiplier(1, 2), 29) (Multiplier(1, 1), 58) (Multiplier(3, 2), 87) (Multiplier(2, 1), 116) Returns list. ''' # find divisors divisors = mathtools.divisors(integer_tempo) 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: multiplier = durationtools.Multiplier(numerator, divisor) new_tempo = fractions.Fraction(multiplier * integer_tempo) assert mathtools.is_integer_equivalent_number(new_tempo) new_tempo = int(new_tempo) pair = (multiplier, new_tempo) if pair not in pairs: pairs.append(pair) # sort pairs pairs.sort() # return pairs return pairs
def is_nonnegative_integer_equivalent_number(argument): '''Is true when `argument` is a nonnegative integer-equivalent number. Otherwise false. .. container:: example >>> duration = abjad.Duration(4, 2) >>> abjad.mathtools.is_nonnegative_integer_equivalent_number(duration) True Returns true or false. ''' from abjad.tools import mathtools return mathtools.is_integer_equivalent_number(argument) and 0 <= argument
def is_positive_integer_equivalent_number(expr): """Is true when `expr` is a positive integer-equivalent number. Otherwise false: :: >>> mathtools.is_positive_integer_equivalent_number(Duration(4, 2)) True Returns boolean. """ from abjad.tools import mathtools try: return 0 < expr and mathtools.is_integer_equivalent_number(expr) except TypeError: # Python 3 comparisons with non-numbers return False
def is_positive_integer_equivalent_number(expr): '''Is true when `expr` is a positive integer-equivalent number. Otherwise false: :: >>> mathtools.is_positive_integer_equivalent_number(Duration(4, 2)) True Returns boolean. ''' from abjad.tools import mathtools try: return 0 < expr and mathtools.is_integer_equivalent_number(expr) except TypeError: # Python 3 comparisons with non-numbers return False
def all_are_integer_equivalent_numbers(argument): '''Is true when `argument` is an iterable collection with integer-equivalent items. Otherwise false. .. container:: example >>> items = [1, 2, 3.0, abjad.Fraction(4, 1)] >>> abjad.mathtools.all_are_integer_equivalent_numbers(items) True >>> abjad.mathtools.all_are_integer_equivalent_numbers([1, 2, 3.5, 4]) False Returns true or false. ''' from abjad.tools import mathtools try: return all(mathtools.is_integer_equivalent_number(_) for _ in argument) except TypeError: return False
def all_are_integer_equivalent_numbers(expr): '''True when `expr` is a sequence and all elements in `expr` are integer-equivalent numbers: :: >>> sequencetools.all_are_integer_equivalent_numbers([1, 2, 3.0, Fraction(4, 1)]) True Otherwise false: :: >>> sequencetools.all_are_integer_equivalent_numbers([1, 2, 3.5, 4]) False Returns boolean. ''' try: return all(mathtools.is_integer_equivalent_number(x) for x in expr) except TypeError: return False
def all_are_integer_equivalent_numbers(expr): '''Is true when `expr` is a sequence and all elements in `expr` are integer-equivalent numbers. :: >>> mathtools.all_are_integer_equivalent_numbers([1, 2, 3.0, Fraction(4, 1)]) True Otherwise false: :: >>> mathtools.all_are_integer_equivalent_numbers([1, 2, 3.5, 4]) False Returns true or false. ''' from abjad.tools import mathtools try: return all(mathtools.is_integer_equivalent_number(x) for x in expr) except TypeError: return False
def test_mathtools_is_integer_equivalent_number_01(): assert mathtools.is_integer_equivalent_number(2) assert mathtools.is_integer_equivalent_number(2.0) assert mathtools.is_integer_equivalent_number(Duration(2, 1))
def test_mathtools_is_integer_equivalent_number_02(): assert not mathtools.is_integer_equivalent_number(2.1) assert not mathtools.is_integer_equivalent_number(Duration(2, 3)) assert not mathtools.is_integer_equivalent_number('foo')
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 __int__(self): if not mathtools.is_integer_equivalent_number(self.pitch_number): raise TypeError return int(self.pitch_number)
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 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