gen_count_term.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2021 by
  4. * The Salk Institute for Biological Studies
  5. *
  6. * Use of this source code is governed by an MIT-style
  7. * license that can be found in the LICENSE file or at
  8. * https://opensource.org/licenses/MIT.
  9. *
  10. ******************************************************************************/
  11. #include <sstream>
  12. #include "api/pybind11_stl_include.h"
  13. #include "api/python_export_utils.h"
  14. #include "gen_count_term.h"
  15. #include "api/count_term.h"
  16. #include "api/complex.h"
  17. #include "api/count_term.h"
  18. #include "api/reaction_rule.h"
  19. #include "api/region.h"
  20. namespace MCell {
  21. namespace API {
  22. void GenCountTerm::check_semantics() const {
  23. }
  24. void GenCountTerm::set_initialized() {
  25. if (is_set(species_pattern)) {
  26. species_pattern->set_initialized();
  27. }
  28. if (is_set(molecules_pattern)) {
  29. molecules_pattern->set_initialized();
  30. }
  31. if (is_set(reaction_rule)) {
  32. reaction_rule->set_initialized();
  33. }
  34. if (is_set(region)) {
  35. region->set_initialized();
  36. }
  37. if (is_set(left_node)) {
  38. left_node->set_initialized();
  39. }
  40. if (is_set(right_node)) {
  41. right_node->set_initialized();
  42. }
  43. initialized = true;
  44. }
  45. void GenCountTerm::set_all_attributes_as_default_or_unset() {
  46. class_name = "CountTerm";
  47. species_pattern = nullptr;
  48. molecules_pattern = nullptr;
  49. reaction_rule = nullptr;
  50. region = nullptr;
  51. node_type = ExprNodeType::LEAF;
  52. left_node = nullptr;
  53. right_node = nullptr;
  54. initial_reactions_count = 0;
  55. }
  56. std::shared_ptr<CountTerm> GenCountTerm::copy_count_term() const {
  57. std::shared_ptr<CountTerm> res = std::make_shared<CountTerm>(DefaultCtorArgType());
  58. res->class_name = class_name;
  59. res->species_pattern = species_pattern;
  60. res->molecules_pattern = molecules_pattern;
  61. res->reaction_rule = reaction_rule;
  62. res->region = region;
  63. res->node_type = node_type;
  64. res->left_node = left_node;
  65. res->right_node = right_node;
  66. res->initial_reactions_count = initial_reactions_count;
  67. return res;
  68. }
  69. std::shared_ptr<CountTerm> GenCountTerm::deepcopy_count_term(py::dict) const {
  70. std::shared_ptr<CountTerm> res = std::make_shared<CountTerm>(DefaultCtorArgType());
  71. res->class_name = class_name;
  72. res->species_pattern = is_set(species_pattern) ? species_pattern->deepcopy_complex() : nullptr;
  73. res->molecules_pattern = is_set(molecules_pattern) ? molecules_pattern->deepcopy_complex() : nullptr;
  74. res->reaction_rule = is_set(reaction_rule) ? reaction_rule->deepcopy_reaction_rule() : nullptr;
  75. res->region = is_set(region) ? region->deepcopy_region() : nullptr;
  76. res->node_type = node_type;
  77. res->left_node = is_set(left_node) ? left_node->deepcopy_count_term() : nullptr;
  78. res->right_node = is_set(right_node) ? right_node->deepcopy_count_term() : nullptr;
  79. res->initial_reactions_count = initial_reactions_count;
  80. return res;
  81. }
  82. bool GenCountTerm::__eq__(const CountTerm& other) const {
  83. return
  84. (
  85. (is_set(species_pattern)) ?
  86. (is_set(other.species_pattern) ?
  87. (species_pattern->__eq__(*other.species_pattern)) :
  88. false
  89. ) :
  90. (is_set(other.species_pattern) ?
  91. false :
  92. true
  93. )
  94. ) &&
  95. (
  96. (is_set(molecules_pattern)) ?
  97. (is_set(other.molecules_pattern) ?
  98. (molecules_pattern->__eq__(*other.molecules_pattern)) :
  99. false
  100. ) :
  101. (is_set(other.molecules_pattern) ?
  102. false :
  103. true
  104. )
  105. ) &&
  106. (
  107. (is_set(reaction_rule)) ?
  108. (is_set(other.reaction_rule) ?
  109. (reaction_rule->__eq__(*other.reaction_rule)) :
  110. false
  111. ) :
  112. (is_set(other.reaction_rule) ?
  113. false :
  114. true
  115. )
  116. ) &&
  117. (
  118. (is_set(region)) ?
  119. (is_set(other.region) ?
  120. (region->__eq__(*other.region)) :
  121. false
  122. ) :
  123. (is_set(other.region) ?
  124. false :
  125. true
  126. )
  127. ) &&
  128. node_type == other.node_type &&
  129. (
  130. (is_set(left_node)) ?
  131. (is_set(other.left_node) ?
  132. (left_node->__eq__(*other.left_node)) :
  133. false
  134. ) :
  135. (is_set(other.left_node) ?
  136. false :
  137. true
  138. )
  139. ) &&
  140. (
  141. (is_set(right_node)) ?
  142. (is_set(other.right_node) ?
  143. (right_node->__eq__(*other.right_node)) :
  144. false
  145. ) :
  146. (is_set(other.right_node) ?
  147. false :
  148. true
  149. )
  150. ) &&
  151. initial_reactions_count == other.initial_reactions_count;
  152. }
  153. bool GenCountTerm::eq_nonarray_attributes(const CountTerm& other, const bool ignore_name) const {
  154. return
  155. (
  156. (is_set(species_pattern)) ?
  157. (is_set(other.species_pattern) ?
  158. (species_pattern->__eq__(*other.species_pattern)) :
  159. false
  160. ) :
  161. (is_set(other.species_pattern) ?
  162. false :
  163. true
  164. )
  165. ) &&
  166. (
  167. (is_set(molecules_pattern)) ?
  168. (is_set(other.molecules_pattern) ?
  169. (molecules_pattern->__eq__(*other.molecules_pattern)) :
  170. false
  171. ) :
  172. (is_set(other.molecules_pattern) ?
  173. false :
  174. true
  175. )
  176. ) &&
  177. (
  178. (is_set(reaction_rule)) ?
  179. (is_set(other.reaction_rule) ?
  180. (reaction_rule->__eq__(*other.reaction_rule)) :
  181. false
  182. ) :
  183. (is_set(other.reaction_rule) ?
  184. false :
  185. true
  186. )
  187. ) &&
  188. (
  189. (is_set(region)) ?
  190. (is_set(other.region) ?
  191. (region->__eq__(*other.region)) :
  192. false
  193. ) :
  194. (is_set(other.region) ?
  195. false :
  196. true
  197. )
  198. ) &&
  199. node_type == other.node_type &&
  200. (
  201. (is_set(left_node)) ?
  202. (is_set(other.left_node) ?
  203. (left_node->__eq__(*other.left_node)) :
  204. false
  205. ) :
  206. (is_set(other.left_node) ?
  207. false :
  208. true
  209. )
  210. ) &&
  211. (
  212. (is_set(right_node)) ?
  213. (is_set(other.right_node) ?
  214. (right_node->__eq__(*other.right_node)) :
  215. false
  216. ) :
  217. (is_set(other.right_node) ?
  218. false :
  219. true
  220. )
  221. ) &&
  222. initial_reactions_count == other.initial_reactions_count;
  223. }
  224. std::string GenCountTerm::to_str(const bool all_details, const std::string ind) const {
  225. std::stringstream ss;
  226. ss << get_object_name() << ": " <<
  227. "\n" << ind + " " << "species_pattern=" << "(" << ((species_pattern != nullptr) ? species_pattern->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  228. "molecules_pattern=" << "(" << ((molecules_pattern != nullptr) ? molecules_pattern->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  229. "reaction_rule=" << "(" << ((reaction_rule != nullptr) ? reaction_rule->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  230. "region=" << "(" << ((region != nullptr) ? region->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  231. "node_type=" << node_type << ", " <<
  232. "\n" << ind + " " << "left_node=" << "(" << ((left_node != nullptr) ? left_node->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  233. "right_node=" << "(" << ((right_node != nullptr) ? right_node->to_str(all_details, ind + " ") : "null" ) << ")" << ", " << "\n" << ind + " " <<
  234. "initial_reactions_count=" << initial_reactions_count;
  235. return ss.str();
  236. }
  237. py::class_<CountTerm> define_pybinding_CountTerm(py::module& m) {
  238. return py::class_<CountTerm, std::shared_ptr<CountTerm>>(m, "CountTerm", "A count observable can be defined as an expression composed of addition\nor subtraction individual count terms. This class represents one count term\nin this expression.\n \n")
  239. .def(
  240. py::init<
  241. std::shared_ptr<Complex>,
  242. std::shared_ptr<Complex>,
  243. std::shared_ptr<ReactionRule>,
  244. std::shared_ptr<Region>,
  245. const ExprNodeType,
  246. std::shared_ptr<CountTerm>,
  247. std::shared_ptr<CountTerm>,
  248. const uint64_t
  249. >(),
  250. py::arg("species_pattern") = nullptr,
  251. py::arg("molecules_pattern") = nullptr,
  252. py::arg("reaction_rule") = nullptr,
  253. py::arg("region") = nullptr,
  254. py::arg("node_type") = ExprNodeType::LEAF,
  255. py::arg("left_node") = nullptr,
  256. py::arg("right_node") = nullptr,
  257. py::arg("initial_reactions_count") = 0
  258. )
  259. .def("check_semantics", &CountTerm::check_semantics)
  260. .def("__copy__", &CountTerm::copy_count_term)
  261. .def("__deepcopy__", &CountTerm::deepcopy_count_term, py::arg("memo"))
  262. .def("__str__", &CountTerm::to_str, py::arg("all_details") = false, py::arg("ind") = std::string(""))
  263. .def("__eq__", &CountTerm::__eq__, py::arg("other"))
  264. .def("__add__", &CountTerm::__add__, py::arg("op2"), "Create a new CountTerm that represents addition of two count terms.\nUsually used through operator '+' such as in ct1 + ct2. \n\n- op2\n")
  265. .def("__sub__", &CountTerm::__sub__, py::arg("op2"), "Create a new CountTerm that represents subtraction of two count terms.\nUsually used through operator '-' such as in ct1 - ct2. \n\n- op2\n")
  266. .def("dump", &CountTerm::dump)
  267. .def_property("species_pattern", &CountTerm::get_species_pattern, &CountTerm::set_species_pattern, "Count the number of molecules that match the given complex instance pattern.\nThis corresponds to the BNGL 'Species' specifier in the BNGL seed species section.\nCounts each molecule exactly once. \nIf the pattern has a compartment set, this specifies the counted region.\nExactly one of species_pattern, molecules_pattern, and reaction_rule must be set. \n")
  268. .def_property("molecules_pattern", &CountTerm::get_molecules_pattern, &CountTerm::set_molecules_pattern, "Count the number of matches of the given pattern on molecules.\nThis corresponds to the BNGL 'Molecules' specifier in the BNGL seed species section.\nThe observable will increment the count every time the pattern matches the molecule.\nFor instance, pattern A will match a complex A(a!1).B(a!1,a!2).A(b!2) twice. \nWhen the pattern is symmetric, e.g. as in A(a!1).A(a!1) then a \nmolecule A(b.a!1).A(a!1,b!2).B(a!2) will be counted twice because the \npattern may match in two different ways. \nIf the pattern has a compartment set, the compartment is used to filter out the molecules. \nExactly one of species_pattern, molecules_pattern, and reaction_rule must be set.\n")
  269. .def_property("reaction_rule", &CountTerm::get_reaction_rule, &CountTerm::set_reaction_rule, "Count the number of applications of this specific reactions that occurred since the\nstart of the simulation.\nExactly one of species_pattern, molecules_pattern, and reaction_rule must be set.\n \n")
  270. .def_property("region", &CountTerm::get_region, &CountTerm::set_region, "Only a GeometryObject or SurfaceRegion can be passed as the region argument, \ncompound regions (created with +, -, *) are not supproted yet. \nCan be combined with a compartment specified in the species_pattern or molecules_pattern.\nIf compartment in species_pattern or molecules_pattern is not specified and \nregion is left unset, counting is done in the whole world.\n")
  271. .def_property("node_type", &CountTerm::get_node_type, &CountTerm::set_node_type, "Internal, used to specify what type of count expression node this object represents.")
  272. .def_property("left_node", &CountTerm::get_left_node, &CountTerm::set_left_node, "Internal, when node_type is not Leaf, this is the left operand.")
  273. .def_property("right_node", &CountTerm::get_right_node, &CountTerm::set_right_node, "Internal, when node_type is not Leaf, this is the right operand.")
  274. .def_property("initial_reactions_count", &CountTerm::get_initial_reactions_count, &CountTerm::set_initial_reactions_count, "Used for checkpointing, allows to set initial count of reactions that occurred.\nIgnored when molecules are counted.\n")
  275. ;
  276. }
  277. std::string GenCountTerm::export_to_python(std::ostream& out, PythonExportContext& ctx) {
  278. if (!export_even_if_already_exported() && ctx.already_exported(this)) {
  279. return ctx.get_exported_name(this);
  280. }
  281. std::string exported_name = "count_term_" + std::to_string(ctx.postinc_counter("count_term"));
  282. if (!export_even_if_already_exported()) {
  283. ctx.add_exported(this, exported_name);
  284. }
  285. bool str_export = export_as_string_without_newlines();
  286. std::string nl = "";
  287. std::string ind = " ";
  288. std::stringstream ss;
  289. if (!str_export) {
  290. nl = "\n";
  291. ind = " ";
  292. ss << exported_name << " = ";
  293. }
  294. ss << "m.CountTerm(" << nl;
  295. if (is_set(species_pattern)) {
  296. ss << ind << "species_pattern = " << species_pattern->export_to_python(out, ctx) << "," << nl;
  297. }
  298. if (is_set(molecules_pattern)) {
  299. ss << ind << "molecules_pattern = " << molecules_pattern->export_to_python(out, ctx) << "," << nl;
  300. }
  301. if (is_set(reaction_rule)) {
  302. ss << ind << "reaction_rule = " << reaction_rule->export_to_python(out, ctx) << "," << nl;
  303. }
  304. if (is_set(region)) {
  305. ss << ind << "region = " << region->export_to_python(out, ctx) << "," << nl;
  306. }
  307. if (node_type != ExprNodeType::LEAF) {
  308. ss << ind << "node_type = " << node_type << "," << nl;
  309. }
  310. if (is_set(left_node)) {
  311. ss << ind << "left_node = " << left_node->export_to_python(out, ctx) << "," << nl;
  312. }
  313. if (is_set(right_node)) {
  314. ss << ind << "right_node = " << right_node->export_to_python(out, ctx) << "," << nl;
  315. }
  316. if (initial_reactions_count != 0) {
  317. ss << ind << "initial_reactions_count = " << initial_reactions_count << "," << nl;
  318. }
  319. ss << ")" << nl << nl;
  320. if (!str_export) {
  321. out << ss.str();
  322. return exported_name;
  323. }
  324. else {
  325. return ss.str();
  326. }
  327. }
  328. } // namespace API
  329. } // namespace MCell