1use std::rc::Rc;
4
5use crate::dbl::{model::*, theory::*};
6use crate::one::{Path, QualifiedPath};
7use crate::zero::{QualifiedName, name};
8
9pub fn positive_loop(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
14 loop_of_type(th, name("Object"), Path::Id(name("Object")))
15}
16
17pub fn negative_loop(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
22 loop_of_type(th, name("Object"), name("Negative").into())
23}
24
25pub fn delayed_positive_loop(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
29 loop_of_type(th, name("Object"), name("Slow").into())
30}
31
32pub fn delayed_negative_loop(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
36 loop_of_type(th, name("Object"), Path::pair(name("Negative"), name("Slow")))
37}
38
39fn loop_of_type(
41 th: Rc<DiscreteDblTheory>,
42 ob_type: QualifiedName,
43 mor_type: QualifiedPath,
44) -> DiscreteDblModel {
45 let mut model = DiscreteDblModel::new(th);
46 model.add_ob(name("x"), ob_type);
47 model.add_mor(name("loop"), name("x"), name("x"), mor_type);
48 model
49}
50
51pub fn positive_feedback(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
55 let mut model = DiscreteDblModel::new(th);
56 model.add_ob(name("x"), name("Object"));
57 model.add_ob(name("y"), name("Object"));
58 model.add_mor(name("positive1"), name("x"), name("y"), Path::Id(name("Object")));
59 model.add_mor(name("positive2"), name("y"), name("x"), Path::Id(name("Object")));
60 model
61}
62
63pub fn negative_feedback(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
67 let mut model = DiscreteDblModel::new(th);
68 model.add_ob(name("x"), name("Object"));
69 model.add_ob(name("y"), name("Object"));
70 model.add_mor(name("positive"), name("x"), name("y"), Path::Id(name("Object")));
71 model.add_mor(name("negative"), name("y"), name("x"), name("Negative").into());
72 model
73}
74
75pub fn walking_attr(th: Rc<DiscreteDblTheory>) -> DiscreteDblModel {
79 let mut model = DiscreteDblModel::new(th);
80 model.add_ob(name("entity"), name("Entity"));
81 model.add_ob(name("type"), name("AttrType"));
82 model.add_mor(name("attr"), name("entity"), name("type"), name("Attr").into());
83 model
84}
85
86pub fn backward_link(th: Rc<DiscreteTabTheory>) -> DiscreteTabModel {
97 backward_link_of_type(th, TabMorType::Basic(name("Link")))
98}
99
100pub fn positive_backward_link(th: Rc<DiscreteTabTheory>) -> DiscreteTabModel {
105 backward_link_of_type(th, TabMorType::Basic(name("Link")))
107}
108
109pub fn negative_backward_link(th: Rc<DiscreteTabTheory>) -> DiscreteTabModel {
114 backward_link_of_type(th, TabMorType::Basic(name("NegativeLink")))
115}
116
117fn backward_link_of_type(th: Rc<DiscreteTabTheory>, link_type: TabMorType) -> DiscreteTabModel {
118 let ob_type = TabObType::Basic(name("Object"));
119 let mut model = DiscreteTabModel::new(th.clone());
120 model.add_ob(name("x"), ob_type.clone());
121 model.add_ob(name("y"), ob_type.clone());
122 model.add_mor(name("f"), name("x").into(), name("y").into(), th.hom_type(ob_type));
123 model.add_mor(name("link"), name("y").into(), model.tabulated_gen(name("f")), link_type);
124 model
125}
126
127pub fn catalyzed_reaction(th: Rc<ModalDblTheory<Unital>>) -> ModalDblModel<Unital> {
131 let (ob_type, op) = (ModalObType::new(name("Object")), name("tensor"));
132 let mut model = ModalDblModel::new(th);
133 model.add_ob(name("x"), ob_type.clone());
134 model.add_ob(name("y"), ob_type.clone());
135 model.add_ob(name("c"), ob_type.clone());
136 let [x, y, c] = [name("x"), name("y"), name("c")].map(ModalOb::from);
137 model.add_mor(
138 name("f"),
139 ModalOb::App(ModalOb::List(List::Symmetric, vec![x, c.clone()]).into(), op.clone()),
140 ModalOb::App(ModalOb::List(List::Symmetric, vec![y, c]).into(), op),
141 ModalMorType::Zero(ob_type),
142 );
143 model
144}
145
146pub fn sir_petri(th: Rc<ModalDblTheory<Unital>>) -> ModalDblModel<Unital> {
148 let (ob_type, op) = (ModalObType::new(name("Object")), name("tensor"));
149 let mut model = ModalDblModel::new(th);
150 let (s, i, r) = (name("S"), name("I"), name("R"));
151 model.add_ob(s.clone(), ob_type.clone());
152 model.add_ob(i.clone(), ob_type.clone());
153 model.add_ob(r.clone(), ob_type.clone());
154 model.add_mor(
155 name("infect"),
156 ModalOb::App(
157 ModalOb::List(List::Symmetric, vec![s.into(), i.clone().into()]).into(),
158 op.clone(),
159 ),
160 ModalOb::App(
161 ModalOb::List(List::Symmetric, vec![i.clone().into(), i.clone().into()]).into(),
162 op.clone(),
163 ),
164 ModalMorType::Zero(ob_type.clone()),
165 );
166 model.add_mor(name("recover"), i.into(), r.into(), ModalMorType::Zero(ob_type));
167 model
168}
169
170pub fn lotka_volterra_dynamics(th: Rc<ModalDblTheory<NonUnital>>) -> ModalDblModel<NonUnital> {
172 let ob_type = ModalObType::new(name("State"));
173 let mor_type: ModalMorType = ModeApp::new(name("Contribution")).into();
174
175 let mut model = ModalDblModel::new(th);
176 let (a, b, c) = (name("A"), name("B"), name("C"));
179
180 model.add_ob(a.clone(), ob_type.clone());
181 model.add_ob(b.clone(), ob_type.clone());
182 model.add_ob(c.clone(), ob_type.clone());
183 model.add_mor(
188 name("A_growth"),
189 ModalOb::List(List::Symmetric, vec![a.clone().into()]),
190 a.clone().into(),
191 mor_type.clone(),
192 );
193 model.add_mor(
194 name("B_growth"),
195 ModalOb::List(List::Symmetric, vec![b.clone().into()]),
196 b.clone().into(),
197 mor_type.clone(),
198 );
199 model.add_mor(
200 name("C_growth"),
201 ModalOb::List(List::Symmetric, vec![c.clone().into()]),
202 c.clone().into(),
203 mor_type.clone(),
204 );
205 model.add_mor(
211 name("AB_interaction"),
212 ModalOb::List(List::Symmetric, vec![a.clone().into(), b.clone().into()]),
213 b.clone().into(),
214 mor_type.clone(),
215 );
216 model.add_mor(
217 name("BA_interaction"),
218 ModalOb::List(List::Symmetric, vec![a.clone().into(), b.clone().into()]),
219 a.clone().into(),
220 mor_type.clone(),
221 );
222 model.add_mor(
223 name("BC_interaction"),
224 ModalOb::List(List::Symmetric, vec![b.clone().into(), c.clone().into()]),
225 c.clone().into(),
226 mor_type.clone(),
227 );
228 model.add_mor(
229 name("CB_interaction"),
230 ModalOb::List(List::Symmetric, vec![b.clone().into(), c.clone().into()]),
231 b.clone().into(),
232 mor_type,
233 );
234
235 model
236}
237
238#[cfg(test)]
239mod tests {
240 use super::super::theories::*;
241 use super::*;
242 use crate::validate::Validate;
243
244 #[test]
245 fn signed_categories() {
246 let th = Rc::new(th_signed_category());
247 assert!(positive_loop(th.clone()).validate().is_ok());
248 assert!(negative_loop(th.clone()).validate().is_ok());
249 assert!(positive_feedback(th.clone()).validate().is_ok());
250 assert!(negative_feedback(th.clone()).validate().is_ok());
251 }
252
253 #[test]
254 fn delayable_signed_categories() {
255 let th = Rc::new(th_delayable_signed_category());
256 assert!(positive_loop(th.clone()).validate().is_ok());
257 assert!(negative_loop(th.clone()).validate().is_ok());
258 assert!(delayed_positive_loop(th.clone()).validate().is_ok());
259 assert!(delayed_negative_loop(th.clone()).validate().is_ok());
260 }
261
262 #[test]
263 fn schemas() {
264 let th = Rc::new(th_schema());
265 assert!(walking_attr(th).validate().is_ok());
266 }
267
268 #[test]
269 fn categories_with_links() {
270 let th = Rc::new(th_category_links());
271 assert!(backward_link(th).validate().is_ok());
272 }
273
274 #[test]
275 fn categories_with_signed_links() {
276 let th = Rc::new(th_category_signed_links());
277 assert!(positive_backward_link(th.clone()).validate().is_ok());
278 assert!(negative_backward_link(th.clone()).validate().is_ok());
279 }
280
281 #[test]
282 fn sym_monoidal_categories() {
283 let th = Rc::new(th_sym_monoidal_category());
284 assert!(catalyzed_reaction(th.clone()).validate().is_ok());
285 assert!(sir_petri(th).validate().is_ok());
286 }
287
288 #[test]
289 fn polynomial_ode_systems() {
290 let th = Rc::new(th_polynomial_ode_system());
291 assert!(lotka_volterra_dynamics(th.clone()).validate().is_ok());
292 }
293}