from pathlib import Path from composer_ans.hopfield import HopfieldParams, generate_next_note, run_hopfield_network from composer_ans.io.legacy_files import extract_active_hopfield_submatrix, load_hopfield_weight_matrix THES = Path(__file__).resolve().parents[1] / "THES" def deterministic_noise(mean: float, variance: float) -> float: return mean def test_hopfield_zero_matrix_converges_to_first_note_for_blank_column() -> None: zero_matrix = tuple(tuple(0.0 for _ in range(40)) for _ in range(40)) result = generate_next_note( [1, 2, 3, 4, 0], zero_matrix, noise=deterministic_noise, ) assert result.output_notes[:4] == (1, 2, 3, 4) assert result.candidate_note == 1 assert result.iterations > 0 def test_generic_hopfield_core_runs_on_arbitrary_grid_shape() -> None: inputs = ( (0.8, 0.2), (0.1, 0.9), (0.4, 0.3), ) size = len(inputs) * len(inputs[0]) weights = tuple(tuple(0.0 for _ in range(size)) for _ in range(size)) result = run_hopfield_network(inputs, weights) assert result.iterations > 0 assert len(result.state.outputs) == 3 assert len(result.state.outputs[0]) == 2 def test_hopfield_legacy_matrix_runs_with_deterministic_noise() -> None: matrix = extract_active_hopfield_submatrix(load_hopfield_weight_matrix(THES / "HTN.DAT")) result = generate_next_note( [1, 4, 5, 1, 0], matrix, params=HopfieldParams(), noise=deterministic_noise, ) assert len(result.output_notes) == 5 assert all(1 <= note <= 8 for note in result.output_notes) assert 1 <= result.candidate_note <= 8 assert result.iterations > 0 assert len(result.outputs) == 8 assert len(result.outputs[0]) == 5