search

Search algorithms.

exception decitala.search.SearchException[source]

Bases: Exception

class decitala.search.Extraction(fragment: decitala.fragment.GeneralFragment, onset_range: tuple, retrograde: bool, factor: float, difference: float, mod_hierarchy_val: int, pitch_content: list, is_spanned_by_slur: bool, slur_count: int, slur_start_end_count: int, id_: int, contiguous_summation: bool = False)[source]

Bases: object

split(split_dict, all_res)[source]

NOTE: this will fail when using contiguous summation. be warned…

decitala.search.frame_to_ql_array(frame)[source]
Parameters

frame (list) – Frame of data from get_object_indices.

Returns

A numpy array holding the associated quarter length of a given window.

Return type

numpy.array

>>> from music21 import note
>>> my_frame = [
...     (note.Note("B-", quarterLength=0.125), (4.125, 4.25)),
...             (note.Note("A", quarterLength=0.25), (4.25, 4.5)),
...             (note.Note("B", quarterLength=0.125), (4.5, 4.625)),
...             (note.Note("B-", quarterLength=0.125), (4.625, 4.75)),
...             (note.Note("A", quarterLength=0.25), (4.75, 5.0)),
...             (note.Note("G", quarterLength=0.25), (5.0, 5.25)),
...             (note.Note("G", quarterLength=0.25), (5.25, 5.5)),
...     ]
>>> frame_to_ql_array(my_frame)
array([0.125, 0.25 , 0.125, 0.125, 0.25 , 0.25 , 0.25 ])
decitala.search.frame_to_midi(frame, ignore_graces=True)[source]
Parameters

frame (list) – Frame of data from get_object_indices.

Returns

A numpy array holding the pitches within the frame.

Return type

numpy.array

>>> from music21 import note
>>> my_frame = [
...     (note.Note("B-", quarterLength=0.125), (4.125, 4.25)),
...             (note.Note("A", quarterLength=0.25), (4.25, 4.5)),
...             (note.Note("B", quarterLength=0.125), (4.5, 4.625)),
...             (note.Note("B-", quarterLength=0.125), (4.625, 4.75)),
...             (note.Note("A", quarterLength=0.25), (4.75, 5.0)),
...             (note.Note("G", quarterLength=0.25), (5.0, 5.25)),
...             (note.Note("G", quarterLength=0.25), (5.25, 5.5)),
...     ]
>>> frame_to_midi(my_frame)
[(70,), (69,), (71,), (70,), (69,), (67,), (67,)]
decitala.search.frame_is_spanned_by_slur(frame)[source]
Parameters

frame (list) – frame from get_object_indices.

Returns

whether or not the frame is spanned by a music21.spanner.Slur object.

Return type

bool

decitala.search.frame_slur_count(frame, allow_overlap=False)[source]
Parameters
  • frame (list) – frame from get_object_indices.

  • allow_overlap (bool) – whether to allow overlaps in the appearing slurs. If False, all the appearing slurs must start and end within the frame’s boundaries.

Returns

The number of slurs in a frame.

Return type

int

decitala.search.frame_slur_start_end_count(frame)[source]

Don’t love this, but let’s see if it works:

Returns 0 if neither the first nor last onset ends with a slur. Returns 1 if first or last onset ends with a slur. Returns 2 if the first and last onset ends with a slur(i.e. frame_is_spanned_by_slur=True).

Function for searching a score for rhythmic fragments and modifications of rhythmic fragments. This function is faster and simpler than decitala.search.rolling_tree_search().

Parameters
  • filepath (str) – Path to file to be searched.

  • part_num (int) – Part in the file to be searched (0-indexed).

  • table (decitala.hash_table.FragmentHashTable) – A decitala.hash_table.FragmentHashTable # noqa object or one of its subclasses.

  • windows (list) – The allowed window sizes for search. Default is all integers in range 2-19.

  • allow_subdivision (bool) – Whether to check for subdivisions of a frame in the search.

decitala.search.path_finder(filepath, part_num, table, windows=[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], allow_subdivision=False, allow_contiguous_summation=False, algorithm='dijkstra', cost_function_class=<decitala.path_finding.path_finding_utils.CostFunction3D object>, split_dict=None, slur_constraint=False, enforce_earliest_start=False, save_filepath=None, verbose=False)[source]

This function combines a number of tools for effectively finding a path of fragments through a provided composition and part number. It first runs decitala.search.rolling_hash_search to extract all fragments from the provided table and then runs the Floyd-Warshall algorithm to get the best path.

Parameters
  • filepath (str) – Path to file to be searched.

  • part_num (int) – Part in the file to be searched (0-indexed).

  • table (decitala.hash_table.FragmentHashTable) – A decitala.hash_table.FragmentHashTable # noqa object or one of its subclasses.

  • windows (list) – The allowed window sizes for search. Default is all integers in range 2-19.

  • allow_subdivision (bool) – Whether to check for subdivisions of a frame in the search.

  • algorithm (str) – Path-finding algorithm used. Options are "floyd_warshall" and "dijkstra". Default is "dijkstra".

  • slur_constraint (bool) – Whether to force slurred fragments to appear in the final path. Only possible if algorithm=”floyd-warshall”.

  • save_filepath (str) – An optional path to a JSON file for saving search results. This file can then be loaded with the decitala.utils.loader().

  • verbose (bool) – Whether to log messages. Default is False.

decitala.search.rolling_search_on_array(ql_array, table, windows=[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18])[source]

A very light function for rhythmic search on an array. This is primarily useful for quick checks in a score. It does not support all possible modification types, etc…

Parameters
Returns

A list holding fragments in the array that were detected in the table.

Return type

list

>>> ght = FragmentHashTable(
...     datasets=["greek_foot"]
... )
>>> ght.load()
>>> example_fragment = np.array([0.25, 0.5, 0.25, 0.5])
>>> for x in rolling_search_on_array(ql_array=example_fragment, table=ght):
...     print(x["fragment"])
<fragment.GreekFoot Iamb>
<fragment.GreekFoot Trochee>
<fragment.GreekFoot Iamb>
<fragment.GreekFoot Amphibrach>
<fragment.GreekFoot Amphimacer>
<fragment.GreekFoot Diiamb>
decitala.search.get_by_ql_array(ql_array, ratio_tree=None, difference_tree=None, allowed_modifications=['r', 'rr', 'd', 'rd', 'sr', 'rsr'], allow_unnamed=False)[source]

Searches a given ratio and/or difference tree for a given fragment. Allows grace notes.

Parameters
  • ql_array (numpy.array) – fragment to be searched.

  • ratio_tree (FragmentTree) – tree storing ratio representations.

  • difference_tree (FragmentTree) – tree storing difference representations.

  • allowed_modifications (list) – possible ways for a fragment to be modified. Current possibilities are r, rr, d, rd, sr, and rsr. NOTE: the order of allowed_modifications is the order of the search.

  • allow_unnamed (bool) – whether or not to allow the retrieval of unnamed paths. The default is False.

>>> from decitala.trees import FragmentTree
>>> fragment = np.array([3.0, 1.5, 1.5, 3.0])
>>> ratio_tree = FragmentTree.from_frag_type(frag_type='greek_foot', rep_type='ratio')
>>> difference_tree = FragmentTree.from_frag_type(frag_type='greek_foot', rep_type='difference')
>>> allowed_modifications = ["r", "rr"]
>>> get_by_ql_array(fragment, ratio_tree, difference_tree, allowed_modifications)
(<fragment.GreekFoot Choriamb>, ('r', 1.5))

Rolling rhythmic search on a music21-readable file on a given part. For search types, see documentation for get_by_ql_array(). The default window lengths are the lengths of fragments in the decitala dataset.

Parameters
  • filepath (str) – path to file to be searched.

  • part_num (int) – part in the file to be searched (0-indexed).

  • ratio_tree (FragmentTree) – tree storing ratio representations.

  • difference_tree (FragmentTree) – tree storing difference representations.

  • allowed_modifications (list) – see get_by_ql_array.

  • try_contiguous_summation (bool) – ties together all elements of equal pitch and duration and searches. See contiguous_summation.

  • windows (list) – possible lengths of the search frames.

  • allow_unnamed (bool) – whether or not to include unnamed fragments (in the fragment tree(s)) in the return.

  • logger (bool) – logger object (see get_logger).

Returns

list holding dictionaries, each of which holds fragment, modifiation, onset-range, and spanning data.

Return type

list

>>> from decitala.trees import FragmentTree
>>> ratio_tree = FragmentTree.from_frag_type(frag_type='greek_foot', rep_type='ratio')
>>> difference_tree = FragmentTree.from_frag_type(frag_type='greek_foot', rep_type='difference') # noqa
>>> ex = "./tests/static/Shuffled_Transcription_2.xml"
>>> for tala_data in rolling_tree_search(ex, 0, ratio_tree, difference_tree, allowed_modifications=["r"])[0:5]:
...     print(tala_data)
{'fragment': <fragment.GreekFoot Trochee>, 'mod': ('r', 0.125), 'onset_range': (0.0, 0.375), 'is_spanned_by_slur': False, 'pitch_content': [(72,), (87,)], 'id': 1}
{'fragment': <fragment.GreekFoot Dactyl>, 'mod': ('r', 0.125), 'onset_range': (0.0, 0.5), 'is_spanned_by_slur': False, 'pitch_content': [(72,), (87,), (79,)], 'id': 39}
{'fragment': <fragment.GreekFoot Spondee>, 'mod': ('r', 0.0625), 'onset_range': (0.25, 0.5), 'is_spanned_by_slur': False, 'pitch_content': [(87,), (79,)], 'id': 2}
{'fragment': <fragment.GreekFoot Trochee>, 'mod': ('r', 0.125), 'onset_range': (1.25, 1.625), 'is_spanned_by_slur': False, 'pitch_content': [(85,), (80,)], 'id': 3}
{'fragment': <fragment.GreekFoot Dactyl>, 'mod': ('r', 0.125), 'onset_range': (1.25, 1.75), 'is_spanned_by_slur': False, 'pitch_content': [(85,), (80,), (80,)], 'id': 40}