Refactor: Rename sustain/last_visited fields for consistency
This commit is contained in:
parent
861d012a95
commit
482f2b0df5
24
src/path.py
24
src/path.py
|
|
@ -23,10 +23,10 @@ class PathStep:
|
|||
movements: dict[int, int] = field(default_factory=dict)
|
||||
scores: dict[str, float] = field(default_factory=dict)
|
||||
weight: float = 0.0 # computed later by _compute_weights
|
||||
last_visited_count_before: dict | None = None
|
||||
last_visited_count_after: dict | None = None
|
||||
sustain_count_before: tuple[int, ...] | None = None
|
||||
sustain_count_after: tuple[int, ...] | None = None
|
||||
last_visited_counts_before: dict | None = None
|
||||
last_visited_counts_after: dict | None = None
|
||||
sustain_counts_before: tuple[int, ...] | None = None
|
||||
sustain_counts_after: tuple[int, ...] | None = None
|
||||
|
||||
|
||||
class Path:
|
||||
|
|
@ -60,8 +60,8 @@ class Path:
|
|||
"""Get last visited counts from the last step, or initialize fresh."""
|
||||
if self.steps:
|
||||
last_step = self.steps[-1]
|
||||
if last_step.last_visited_count_after is not None:
|
||||
return dict(last_step.last_visited_count_after)
|
||||
if last_step.last_visited_counts_after is not None:
|
||||
return dict(last_step.last_visited_counts_after)
|
||||
|
||||
# Initialize fresh: all nodes start at 0 (except initial which we set to 0 explicitly)
|
||||
return {node: 0 for node in self._graph_nodes}
|
||||
|
|
@ -70,8 +70,8 @@ class Path:
|
|||
"""Get sustain counts from the last step, or initialize fresh."""
|
||||
if self.steps:
|
||||
last_step = self.steps[-1]
|
||||
if last_step.sustain_count_after is not None:
|
||||
return last_step.sustain_count_after
|
||||
if last_step.sustain_counts_after is not None:
|
||||
return last_step.sustain_counts_after
|
||||
|
||||
# Initialize fresh: all voices start at 0
|
||||
return tuple(0 for _ in range(self._num_voices))
|
||||
|
|
@ -114,10 +114,10 @@ class Path:
|
|||
sustain_after[voice_idx] = 0
|
||||
|
||||
# Update step with computed state
|
||||
step.last_visited_count_before = last_visited_before
|
||||
step.last_visited_count_after = last_visited_after
|
||||
step.sustain_count_before = sustain_before
|
||||
step.sustain_count_after = tuple(sustain_after)
|
||||
step.last_visited_counts_before = last_visited_before
|
||||
step.last_visited_counts_after = last_visited_after
|
||||
step.sustain_counts_before = sustain_before
|
||||
step.sustain_counts_after = tuple(sustain_after)
|
||||
|
||||
self.steps.append(step)
|
||||
return step
|
||||
|
|
|
|||
|
|
@ -57,22 +57,22 @@ class PathFinder:
|
|||
# Derive state from last step (or initialize fresh for step 0)
|
||||
if path_obj.steps:
|
||||
last_step = path_obj.steps[-1]
|
||||
voice_stay_count = last_step.sustain_count_after
|
||||
node_visit_counts = last_step.last_visited_count_after
|
||||
sustain_counts = last_step.sustain_counts_after
|
||||
last_visited_counts = last_step.last_visited_counts_after
|
||||
else:
|
||||
# First step - derive from path object's current state
|
||||
voice_stay_count = tuple(0 for _ in range(len(path_obj._voice_map)))
|
||||
node_visit_counts = {node: 0 for node in set(self.graph.nodes())}
|
||||
sustain_counts = tuple(0 for _ in range(len(path_obj._voice_map)))
|
||||
last_visited_counts = {node: 0 for node in set(self.graph.nodes())}
|
||||
|
||||
# Build candidates with raw scores
|
||||
candidates = self._build_candidates(
|
||||
out_edges,
|
||||
path_obj.output_chords,
|
||||
weights_config,
|
||||
voice_stay_count,
|
||||
sustain_counts,
|
||||
path_obj.graph_chords,
|
||||
path_obj._cumulative_trans,
|
||||
node_visit_counts,
|
||||
last_visited_counts,
|
||||
)
|
||||
|
||||
# Compute weights from raw scores
|
||||
|
|
@ -105,10 +105,10 @@ class PathFinder:
|
|||
out_edges: list,
|
||||
path: list["Chord"],
|
||||
config: dict,
|
||||
voice_stay_count: tuple[int, ...] | None,
|
||||
sustain_counts: tuple[int, ...] | None,
|
||||
graph_path: list["Chord"] | None,
|
||||
cumulative_trans: "Pitch | None",
|
||||
node_visit_counts: dict | None,
|
||||
last_visited_counts: dict | None,
|
||||
) -> list[PathStep]:
|
||||
"""Build hypothetical path steps with raw factor scores."""
|
||||
if not out_edges:
|
||||
|
|
@ -151,9 +151,11 @@ class PathFinder:
|
|||
voice_crossing = self._factor_voice_crossing(edge_data, config)
|
||||
melodic = self._factor_melodic_threshold(edge_data, config)
|
||||
contrary = self._factor_contrary_motion(edge_data, config)
|
||||
hamiltonian = self._factor_dca_hamiltonian(edge, node_visit_counts, config)
|
||||
hamiltonian = self._factor_dca_hamiltonian(
|
||||
edge, last_visited_counts, config
|
||||
)
|
||||
dca_voice = self._factor_dca_voice_movement(
|
||||
edge, path, voice_stay_count, config, cumulative_trans
|
||||
edge, path, sustain_counts, config, cumulative_trans
|
||||
)
|
||||
target = self._factor_target_range(edge, path, config, cumulative_trans)
|
||||
|
||||
|
|
@ -373,7 +375,7 @@ class PathFinder:
|
|||
return max(0.0, 1.0 - (distance / ideal_up))
|
||||
|
||||
def _factor_dca_hamiltonian(
|
||||
self, edge: tuple, node_visit_counts: dict | None, config: dict
|
||||
self, edge: tuple, last_visited_counts: dict | None, config: dict
|
||||
) -> float:
|
||||
"""Returns score based on how long since node was last visited.
|
||||
|
||||
|
|
@ -382,11 +384,11 @@ class PathFinder:
|
|||
if config.get("weight_dca_hamiltonian", 1) == 0:
|
||||
return 1.0
|
||||
|
||||
if node_visit_counts is None:
|
||||
if last_visited_counts is None:
|
||||
return 0.0
|
||||
|
||||
destination = edge[1]
|
||||
visit_count = node_visit_counts.get(destination, 0)
|
||||
visit_count = last_visited_counts.get(destination, 0)
|
||||
|
||||
# Return the visit count - higher is better (more steps since last visit)
|
||||
return float(visit_count)
|
||||
|
|
@ -395,27 +397,27 @@ class PathFinder:
|
|||
self,
|
||||
edge: tuple,
|
||||
path: list,
|
||||
voice_stay_count: tuple[int, ...] | None,
|
||||
sustain_counts: tuple[int, ...] | None,
|
||||
config: dict,
|
||||
cumulative_trans: "Pitch | None",
|
||||
) -> float:
|
||||
"""Returns probability that voices will change.
|
||||
|
||||
DCA = Dissonant Counterpoint Algorithm
|
||||
Probability = (sum of stay_counts for changing voices) / (sum of ALL stay_counts)
|
||||
Probability = (sum of sustain_counts for changing voices) / (sum of ALL sustain_counts)
|
||||
|
||||
Higher probability = more likely to choose edge where long-staying voices change.
|
||||
"""
|
||||
if config.get("weight_dca_voice_movement", 1) == 0:
|
||||
return 1.0
|
||||
|
||||
if voice_stay_count is None or len(path) == 0:
|
||||
if sustain_counts is None or len(path) == 0:
|
||||
return 1.0
|
||||
|
||||
if cumulative_trans is None:
|
||||
return 1.0
|
||||
|
||||
num_voices = len(voice_stay_count)
|
||||
num_voices = len(sustain_counts)
|
||||
if num_voices == 0:
|
||||
return 1.0
|
||||
|
||||
|
|
@ -434,14 +436,14 @@ class PathFinder:
|
|||
candidate_cents = [p.to_cents() for p in candidate_transposed.pitches]
|
||||
|
||||
sum_changing = 0
|
||||
sum_all = sum(voice_stay_count)
|
||||
sum_all = sum(sustain_counts)
|
||||
|
||||
if sum_all == 0:
|
||||
return 1.0
|
||||
|
||||
for voice_idx in range(num_voices):
|
||||
if current_cents[voice_idx] != candidate_cents[voice_idx]:
|
||||
sum_changing += voice_stay_count[voice_idx]
|
||||
sum_changing += sustain_counts[voice_idx]
|
||||
|
||||
return sum_changing / sum_all
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue