1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use sim_kernel::Expr;
use crate::runtime::{integer, map, span_expr, strings, symbol, time_expr, violation_expr};
use crate::{ContrapuntalForm, StrettoGraph};
pub(crate) fn stretto_graph_expr(graph: &StrettoGraph) -> Expr {
map(vec![
("mode", symbol("analysis")),
("generation", Expr::Bool(false)),
("provenance", strings(&graph.provenance)),
(
"entries",
Expr::Vector(
graph
.compatibility
.nodes
.iter()
.map(|entry| {
map(vec![
("id", integer(entry.id)),
("delay", time_expr(entry.delay)),
("form", symbol(&form_name(entry.transform.form))),
("transposition", integer(entry.transform.transposition)),
(
"duration-factor",
time_expr(entry.transform.duration_factor),
),
])
})
.collect(),
),
),
(
"couples",
Expr::Vector(
graph
.couples
.iter()
.map(|couple| {
map(vec![
("leader", integer(couple.leader)),
("follower", integer(couple.follower)),
("span", span_expr(&couple.compatibility.overlap.span)),
(
"simultaneous-windows",
integer(couple.compatibility.overlap.simultaneous_windows),
),
(
"interval-classes",
Expr::Vector(
couple
.compatibility
.overlap
.interval_classes
.iter()
.map(|(class, count)| {
Expr::Vector(vec![integer(*class), integer(*count)])
})
.collect(),
),
),
])
})
.collect(),
),
),
(
"components",
Expr::Vector(
graph
.components
.iter()
.map(|component| Expr::Vector(component.iter().copied().map(integer).collect()))
.collect(),
),
),
(
"cliques",
Expr::Vector(
graph
.clusters
.iter()
.map(|cluster| {
map(vec![
(
"entries",
Expr::Vector(
cluster.entries.iter().copied().map(integer).collect(),
),
),
(
"edge-ids",
Expr::Vector(
cluster.edge_ids.iter().copied().map(integer).collect(),
),
),
("fusion-mode", Expr::String(cluster.fusion.mode.clone())),
])
})
.collect(),
),
),
(
"chains",
Expr::Vector(
graph
.chains
.iter()
.map(|chain| {
map(vec![
(
"clusters",
Expr::Vector(chain.clusters.iter().copied().map(integer).collect()),
),
(
"overlaps",
Expr::Vector(chain.overlaps.iter().copied().map(integer).collect()),
),
(
"fused-entries",
Expr::Vector(
chain.fused_entries.iter().copied().map(integer).collect(),
),
),
])
})
.collect(),
),
),
(
"rejections",
Expr::Vector(
graph
.rejections
.iter()
.map(|rejection| {
map(vec![
("first", integer(rejection.first)),
("second", integer(rejection.second)),
("span", span_expr(&rejection.overlap.span)),
(
"violations",
Expr::Vector(
rejection.violations.iter().map(violation_expr).collect(),
),
),
])
})
.collect(),
),
),
])
}
fn form_name(form: ContrapuntalForm) -> String {
match form {
ContrapuntalForm::Original => "original".to_owned(),
ContrapuntalForm::Retrograde => "retrograde".to_owned(),
ContrapuntalForm::Inversion { axis } => format!("inversion-{}", axis.semitone()),
ContrapuntalForm::RetrogradeInversion { axis } => {
format!("retrograde-inversion-{}", axis.semitone())
}
}
}