def test_weighted_choice_as_tuple(self): options = [(1, 0), (5, -1), (10, 5), (19, 1)] for i in range(25): result = rand.weighted_choice(options, True) expected_index = next(i for i, option in enumerate(options) if option[0] == result[1]) self.assertEqual(expected_index, result[0])
def populate_item_list(self, item_count): """ Fill ``self.item_list`` with Node instances. Args: item_count (int): Number of items to create Returns: None """ graph_weights = [(network, 1) for network in self.word_graphs] # Pick a random network to start on current_network = random.choice(self.word_graphs) # Main item population loop for i in range(item_count): # Determine if we should change networks (crude) if rand.prob_bool(0.01): old_network = current_network while current_network == old_network: current_network = rand.weighted_choice(graph_weights) # Determine with self.pause_or_write_network whether to append a # blank line or a word to self.item_list if self.pause_or_write_network.pick().get_value() == 0: self.item_list.append(custom_nodes.BlankLine()) else: new_node = current_network.pick() self.item_list.append(new_node)
def pick(self, starting_node=None): """ Pick a node on the graph based on the links in a starting node. Additionally, set ``self.current_node`` to the newly picked node. * if ``starting_node`` is specified, start from there * if ``starting_node`` is ``None``, start from ``self.current_node`` * if ``starting_node`` is ``None`` and ``self.current_node`` is ``None``, pick a uniformally random node in ``self.node_list`` Args: starting_node (Optional[Node]): ``Node`` to pick from. Returns: Node """ if starting_node is None: if self.current_node is None: random_node = random.choice(self.node_list) self.current_node = random_node return random_node else: starting_node = self.current_node # Use weighted_choice on start_node.link_list self.current_node = weighted_choice( [(link.target, link.weight) for link in starting_node.link_list]) return self.current_node
def test_weighted_choice_as_tuple(self): options = [(1, 0), (5, -1), (10, 5), (19, 1)] for i in range(25): result = rand.weighted_choice(options, True) expected_index = next( i for i, option in enumerate(options) if option[0] == result[1]) self.assertEqual(expected_index, result[0])
def get(self): """ Get one of the options within the probability space of the object. Returns: Any: An item from ``self.options``. """ return rand.weighted_choice(self.options)
def get(self): """ Get one of the options within the probability space of the object. Returns: Any: An item from ``self.options``. """ return rand.weighted_choice(self.options)
def get_hexagram(method='THREE COIN'): """ Return one or two hexagrams using any of a variety of divination methods. The ``NAIVE`` method simply returns a uniformally random ``int`` between ``1`` and ``64``. All other methods return a ``tuple`` of two ``int`` where the first represents the starting hexagram and the second represents the 'moving to' hexagram. Args: method (Optional[str]): THREE COIN, YARROW, NAIVE Returns: tuple(int) or int Raises: ValueError if ``method`` is invalid """ if method == 'THREE COIN': weights = [('MOVING YANG', 2), ('MOVING YIN', 2), ('STATIC YANG', 6), ('STATIC YIN', 6)] elif method == 'YARROW': weights = [('MOVING YANG', 8), ('MOVING YIN', 2), ('STATIC YANG', 11), ('STATIC YIN', 17)] elif method == 'NAIVE': return random.randint(1, 64) else: raise ValueError hexagram_1 = [] hexagram_2 = [] for i in range(6): roll = weighted_choice(weights) if roll == 'MOVING YANG': hexagram_1.append(1) hexagram_2.append(0) elif roll == 'MOVING YIN': hexagram_1.append(0) hexagram_2.append(1) elif roll == 'STATIC YANG': hexagram_1.append(1) hexagram_2.append(1) else: # roll == 'STATIC YIN' hexagram_1.append(0) hexagram_2.append(0) # Convert hexagrams lists into tuples hexagram_1 = tuple(hexagram_1) hexagram_2 = tuple(hexagram_2) return (_hexagram_dict[hexagram_1], _hexagram_dict[hexagram_2])
def pick_random_alignment(self): """ Randomly pick a text alignment according to predefined weights. Returns: None """ self.alignment = rand.weighted_choice( [('LEFT', 70), ('RIGHT', 5), ('JUSTIFY', 15) ])
def weighted_choice_preferring_later(select_list): """ Randomly choose an item, picking higher index items. Args: select_list (list): A list of Returns: Any: Any one of the items in ``select_list`` """ weight_list = [] for i in range(0, len(select_list)): weight_list.append((select_list[i], (i + 5) / 2)) return rand.weighted_choice(weight_list)
def test_weighted_choice(self): options = [(0, 1), (5, 2), (10, 5)] zero_count = 0 five_count = 0 ten_count = 0 for i in range(1000): result = rand.weighted_choice(options) if result == 0: zero_count += 1 elif result == 5: five_count += 1 elif result == 10: ten_count += 1 else: self.fail('Unexpected weighted_choice' 'result {0}'.format(result)) self.assertTrue(25 <= zero_count <= 250) self.assertTrue(50 <= five_count <= 600) self.assertTrue(300 <= ten_count <= 900)
def test_weighted_choice(self): options = [(0, 1), (5, 2), (10, 5)] zero_count = 0 five_count = 0 ten_count = 0 for i in range(1000): result = rand.weighted_choice(options) if result == 0: zero_count += 1 elif result == 5: five_count += 1 elif result == 10: ten_count += 1 else: self.fail('Unexpected weighted_choice' 'result {0}'.format(result)) self.assertTrue(25 <= zero_count <= 250) self.assertTrue(50 <= five_count <= 600) self.assertTrue(300 <= ten_count <= 900)
def pick(self, starting_node=None): """ Pick a node on the graph based on the links in a starting node. Additionally, set ``self.current_node`` to the newly picked node. * if ``starting_node`` is specified, start from there * if ``starting_node`` is ``None``, start from ``self.current_node`` * if ``starting_node`` is ``None`` and ``self.current_node`` is ``None``, pick a uniformally random node in ``self.node_list`` Args: starting_node (Node): ``Node`` to pick from. Returns: Node Example: >>> from blur.markov.node import Node >>> node_1 = Node('One') >>> node_2 = Node('Two') >>> node_1.add_link(node_1, 5) >>> node_1.add_link(node_2, 2) >>> node_2.add_link(node_1, 1) >>> graph = Graph([node_1, node_2]) >>> [graph.pick().get_value() for i in range(5)] # doctest: +SKIP ['One', 'One', 'Two', 'One', 'One'] """ if starting_node is None: if self.current_node is None: random_node = random.choice(self.node_list) self.current_node = random_node return random_node else: starting_node = self.current_node # Use weighted_choice on start_node.link_list self.current_node = weighted_choice([ (link.target, link.weight) for link in starting_node.link_list ]) return self.current_node
def pick(self, starting_node=None): """ Pick a node on the graph based on the links in a starting node. Additionally, set ``self.current_node`` to the newly picked node. * if ``starting_node`` is specified, start from there * if ``starting_node`` is ``None``, start from ``self.current_node`` * if ``starting_node`` is ``None`` and ``self.current_node`` is ``None``, pick a uniformally random node in ``self.node_list`` Args: starting_node (Node): ``Node`` to pick from. Returns: Node Example: >>> from blur.markov.node import Node >>> node_1 = Node('One') >>> node_2 = Node('Two') >>> node_1.add_link(node_1, 5) >>> node_1.add_link(node_2, 2) >>> node_2.add_link(node_1, 1) >>> graph = Graph([node_1, node_2]) >>> [graph.pick().get_value() for i in range(5)] # doctest: +SKIP ['One', 'One', 'Two', 'One', 'One'] """ if starting_node is None: if self.current_node is None: random_node = random.choice(self.node_list) self.current_node = random_node return random_node else: starting_node = self.current_node # Use weighted_choice on start_node.link_list self.current_node = weighted_choice( [(link.target, link.weight) for link in starting_node.link_list]) return self.current_node
def test_weighted_choice_with_all_non_pos_weights(self): with self.assertRaises(rand.ProbabilityUndefinedError): foo = rand.weighted_choice([(1, 0), (5, 0), (10, 0)])
def test_weighted_choice_with_empty_list(self): with self.assertRaises(ValueError): foo = rand.weighted_choice([])
(-1, 1), (0.02, 6), (0.2, 5), (0.3, 1), (0.4, 0) ]))) # Initialize softer oscillators slightly out of tune with consonant pitches detune_weights = rand.normal_distribution(0, 20) detune_base_pitches_weights = [(frequency_map[10], 50), (frequency_map[0], 1), (frequency_map[2], 30), (frequency_map[3], 40), (frequency_map[5], 80), (frequency_map[7], 30), (frequency_map[9], 20)] octave_choice_weights = [(1 / 8, 20), (1 / 4, 15), (1 / 2, 10), (1, 5), (2, 5), (4, 5)] # Find detuned pitches pitches = [ (( rand.weighted_choice(detune_base_pitches_weights) + # Base pitch rand.weighted_rand(detune_weights)) * # Detune rand.weighted_choice(octave_choice_weights)) # Set Octave for i in range(50) ] amp_multiplier_weights = [(0.05, 10), (0.2, 2), (0.7, 1)] for pitch in pitches: osc_list.append( oscillator.Oscillator( pitch, amplitude.AmplitudeHandler( init_value=0, drift_target_weights=[(-2, 30), (0.02, 8), (0.05, 2), (0.1, 0.1), (0.3, 0)], change_rate_weights=[(0.00001, 12000), (0.0001, 100),
def test_weighted_choice_with_all_non_pos_weights(self): with self.assertRaises(rand.ProbabilityUndefinedError): foo = rand.weighted_choice([(1, 0), (5, 0), (10, 0)])
def test_weighted_choice_with_mixed_pos_neg_weights(self): options = [(1, 0), (5, -1), (10, 5), (19, 1)] for i in range(25): self.assertIn(rand.weighted_choice(options), [10, 19])
def test_weighted_choice_with_one_weight_returns_it(self): weight_list = [('The Only Weight', 2)] expected_result = weight_list[0][0] self.assertEqual(rand.weighted_choice(weight_list), expected_result)
def test_weighted_rand_and_choice_with_one_weight_equivalent(self): weight_list = [('The Only Weight', 2)] self.assertEqual(rand.weighted_rand(weight_list), rand.weighted_choice(weight_list))
def get_hexagram(method='THREE COIN'): """ Return one or two hexagrams using any of a variety of divination methods. The ``NAIVE`` method simply returns a uniformally random ``int`` between ``1`` and ``64``. All other methods return a 2-tuple where the first value represents the starting hexagram and the second represents the 'moving to' hexagram. To find the name and unicode glyph for a found hexagram, look it up in the module-level `hexagrams` dict. Args: method (str): ``'THREE COIN'``, ``'YARROW'``, or ``'NAIVE'``, the divination method model to use. Note that the three coin and yarrow methods are not actually literally simulated, but rather statistical models reflecting the methods are passed to `blur.rand` functions to accurately approximate them. Returns: int: If ``method == 'NAIVE'``, the ``int`` key of the found hexagram. Otherwise a `tuple` will be returned. tuple: A 2-tuple of form ``(int, int)`` where the first value is key of the starting hexagram and the second is that of the 'moving-to' hexagram. Raises: ValueError if ``method`` is invalid Examples: The function being used alone: :: >>> get_hexagram(method='THREE COIN') # doctest: +SKIP # Might be... (55, 2) >>> get_hexagram(method='YARROW') # doctest: +SKIP # Might be... (41, 27) >>> get_hexagram(method='NAIVE') # doctest: +SKIP # Might be... 26 Usage in combination with hexagram lookup: :: >>> grams = get_hexagram() >>> grams # doctest: +SKIP (47, 42) # unpack hexagrams for convenient reference >>> initial, moving_to = grams >>> hexagrams[initial] # doctest: +SKIP ('䷮', '困', 'Confining') >>> hexagrams[moving_to] # doctest: +SKIP ('䷩', '益', 'Augmenting') >>> print('{} moving to {}'.format( ... hexagrams[initial][2], ... hexagrams[moving_to][2]) ... ) # doctest: +SKIP Confining moving to Augmenting """ if method == 'THREE COIN': weights = [('MOVING YANG', 2), ('MOVING YIN', 2), ('STATIC YANG', 6), ('STATIC YIN', 6)] elif method == 'YARROW': weights = [('MOVING YANG', 8), ('MOVING YIN', 2), ('STATIC YANG', 11), ('STATIC YIN', 17)] elif method == 'NAIVE': return random.randint(1, 64) else: raise ValueError('`method` value of "{}" is invalid') hexagram_1 = [] hexagram_2 = [] for i in range(6): roll = weighted_choice(weights) if roll == 'MOVING YANG': hexagram_1.append(1) hexagram_2.append(0) elif roll == 'MOVING YIN': hexagram_1.append(0) hexagram_2.append(1) elif roll == 'STATIC YANG': hexagram_1.append(1) hexagram_2.append(1) else: # if roll == 'STATIC YIN' hexagram_1.append(0) hexagram_2.append(0) # Convert hexagrams lists into tuples hexagram_1 = tuple(hexagram_1) hexagram_2 = tuple(hexagram_2) return (_hexagram_dict[hexagram_1], _hexagram_dict[hexagram_2])
def test_weighted_choice_with_empty_list(self): with self.assertRaises(ValueError): foo = rand.weighted_choice([])
def test_weighted_choice_with_all_zero_weights(self): options = [(1, 0), (5, 0), (10, 0)] self.assertIn(rand.weighted_choice(options), [1, 5, 10])
def test_weighted_choice_with_mixed_pos_neg_weights(self): options = [(1, 0), (5, -1), (10, 5), (19, 1)] for i in range(25): self.assertIn(rand.weighted_choice(options), [10, 19])
def test_weighted_choice_with_one_weight_returns_it(self): weight_list = [('The Only Weight', 2)] expected_result = weight_list[0][0] self.assertEqual(rand.weighted_choice(weight_list), expected_result)
detune_weights = rand.normal_distribution(0, 20) detune_base_pitches_weights = [(frequency_map[10], 50), (frequency_map[0], 1), (frequency_map[2], 30), (frequency_map[3], 40), (frequency_map[5], 80), (frequency_map[7], 30), (frequency_map[9], 20)] octave_choice_weights = [(1/8, 20), (1/4, 15), (1/2, 10), (1, 5), (2, 5), (4, 5)] # Find detuned pitches pitches = [((rand.weighted_choice(detune_base_pitches_weights) + # Base pitch rand.weighted_rand(detune_weights)) * # Detune rand.weighted_choice(octave_choice_weights)) # Set Octave for i in range(50)] amp_multiplier_weights = [(0.05, 10), (0.2, 2), (0.7, 1)] for pitch in pitches: osc_list.append( oscillator.Oscillator( pitch, amplitude.AmplitudeHandler( init_value=0, drift_target_weights=[ (-2, 30), (0.02, 8), (0.05, 2), (0.1, 0.1), (0.3, 0)], change_rate_weights=[ (0.00001, 12000),
def test_weighted_rand_and_choice_with_one_weight_equivalent(self): weight_list = [('The Only Weight', 2)] self.assertEqual(rand.weighted_rand(weight_list), rand.weighted_choice(weight_list))