Quantifier.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /**
  2. * @file kernel/qss/Quantifier.hpp
  3. * @author The ARTIS Development Team
  4. * See the AUTHORS or Authors.txt file
  5. */
  6. /*
  7. * ARTIS - the multimodeling and simulation environment
  8. * This file is a part of the ARTIS environment
  9. *
  10. * Copyright (C) 2013-2019 ULCO http://www.univ-littoral.fr
  11. *
  12. * This program is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation, either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. #ifndef QSS_QUANTIFIER
  26. #define QSS_QUANTIFIER
  27. #include <artis-star/kernel/pdevs/Dynamics.hpp>
  28. #include <artis-star/kernel/qss/Data.hpp>
  29. #include <cmath>
  30. namespace artis {
  31. namespace qss {
  32. struct QuantifierParameters
  33. {
  34. bool allow_offsets;
  35. bool zero_init_offset;
  36. double quantum;
  37. unsigned int archive_length;
  38. };
  39. template<class Time>
  40. class Quantifier
  41. : public artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters>
  42. {
  43. public:
  44. struct input
  45. {
  46. enum values
  47. {
  48. IN, RESET
  49. };
  50. };
  51. struct output
  52. {
  53. enum values
  54. {
  55. OUT
  56. };
  57. };
  58. Quantifier(const std::string &name,
  59. const artis::pdevs::Context<Time, Quantifier<Time>, QuantifierParameters> &context)
  60. :
  61. artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters>(name, context)
  62. {
  63. DECLARE_STATES(int,
  64. ((state::PHASE, &Quantifier<Time>::_phase),
  65. (state::ADAPTIVE_STATE, &Quantifier<Time>::_adaptive_state)));
  66. DECLARE_STATES(unsigned int,
  67. ((state::STEP_NUMBER, &Quantifier<Time>::_step_number)));
  68. DECLARE_STATES(double,
  69. ((state::OFFSET, &Quantifier<Time>::_offset),
  70. (state::UP_THRESHOLD, &Quantifier<Time>::_up_threshold),
  71. (state::DOWN_THRESHOLD, &Quantifier<Time>::_down_threshold)));
  72. this->input_ports({{input::IN, "in"},
  73. {input::RESET, "reset"}});
  74. this->output_port({output::OUT, "out"});
  75. this->observables({{var::UP, "up"},
  76. {var::DOWN, "down"},
  77. {var::VALUE, "value"}});
  78. _adaptive = context.parameters().allow_offsets;
  79. _adaptive_state = _adaptive ? adaptive_state::POSSIBLE : adaptive_state::IMPOSSIBLE;
  80. _zero_init_offset = context.parameters().zero_init_offset;
  81. _step_size = context.parameters().quantum;
  82. assert(_step_size > 0);
  83. _past_length = context.parameters().archive_length;
  84. assert(_past_length > 2);
  85. }
  86. virtual ~Quantifier()
  87. {}
  88. virtual void dconf(const typename Time::type &t, const typename Time::type &e,
  89. const common::Bag<Time> &bag)
  90. {
  91. dint(t);
  92. dext(t, e, bag);
  93. }
  94. virtual void dint(const typename Time::type & /* t */)
  95. {
  96. switch (_phase) {
  97. case phase::INIT:break;
  98. case phase::IDLE:break;
  99. case phase::RESPONSE:_phase = phase::IDLE;
  100. break;
  101. }
  102. }
  103. virtual void dext(const typename Time::type &t, const typename Time::type &e,
  104. const common::Bag<Time> &bag)
  105. {
  106. bool reset = false;
  107. std::for_each(bag.begin(), bag.end(),
  108. [this, t, e, &reset](const common::ExternalEvent<Time> &event) {
  109. if (event.on_port(input::IN)) {
  110. IntegratorData data;
  111. double shifting_factor;
  112. double value;
  113. int cnt;
  114. event.data()(data);
  115. value = data.value;
  116. if (_phase == phase::INIT) {
  117. init_step_number_and_offset(value);
  118. update_thresholds();
  119. _phase = phase::RESPONSE;
  120. } else {
  121. cnt = 0;
  122. while (value >= _up_threshold or value <= _down_threshold) {
  123. cnt++;
  124. if (value >= _up_threshold) {
  125. _step_number++;
  126. } else {
  127. _step_number--;
  128. }
  129. switch (_adaptive_state) {
  130. case adaptive_state::IMPOSSIBLE:update_thresholds();
  131. break;
  132. case adaptive_state::POSSIBLE:
  133. if (value >= _up_threshold) {
  134. store_change(_step_size, t);
  135. } else {
  136. store_change(-_step_size, t);
  137. }
  138. shifting_factor = shift_quanta();
  139. assert(shifting_factor >= 0
  140. and shifting_factor <= 1);
  141. if (shifting_factor != 0 and shifting_factor != 1) {
  142. if (value >= _up_threshold) {
  143. update_thresholds(shifting_factor,
  144. direction::DIRECTION_DOWN);
  145. } else {
  146. update_thresholds(shifting_factor,
  147. direction::DIRECTION_UP);
  148. }
  149. _adaptive_state = adaptive_state::DONE;
  150. } else {
  151. update_thresholds();
  152. }
  153. break;
  154. case adaptive_state::DONE:init_step_number_and_offset(value);
  155. _adaptive_state = adaptive_state::POSSIBLE;
  156. update_thresholds();
  157. break;
  158. }
  159. }
  160. }
  161. } else if (event.on_port(input::RESET)) {
  162. _offset = 0;
  163. reset = true;
  164. _archive.clear();
  165. }
  166. });
  167. if (reset) {
  168. _phase = phase::INIT;
  169. } else {
  170. _phase = phase::RESPONSE;
  171. }
  172. }
  173. virtual void start(const typename Time::type & /* time */)
  174. {
  175. _offset = 0;
  176. _phase = phase::INIT;
  177. }
  178. virtual typename Time::type ta(const typename Time::type & /* time */)
  179. {
  180. switch (_phase) {
  181. case phase::INIT:
  182. case phase::IDLE:return Time::infinity;
  183. case phase::RESPONSE:return 0.0;
  184. }
  185. return Time::infinity;
  186. }
  187. virtual common::Bag<Time> lambda(const typename Time::type & /* time */) const
  188. {
  189. common::Bag<Time> msgs;
  190. const QuantifierData data = {_up_threshold, _down_threshold};
  191. msgs.push_back(common::ExternalEvent<Time>(output::OUT, data));
  192. return msgs;
  193. }
  194. virtual common::Value observe(const typename Time::type & /* t */,
  195. unsigned int index) const
  196. {
  197. switch (index) {
  198. case var::UP:return (double) _up_threshold;
  199. case var::DOWN:return (double) _down_threshold;
  200. case var::VALUE:return (double) (_up_threshold - _down_threshold);
  201. default:return common::Value();
  202. }
  203. }
  204. private:
  205. void init_step_number_and_offset(double value)
  206. {
  207. _step_number = static_cast<long int>(std::floor(value / _step_size));
  208. if (_zero_init_offset) {
  209. _offset = 0;
  210. } else {
  211. _offset = value - static_cast<double>(_step_number) * _step_size;
  212. }
  213. }
  214. bool monotonous(unsigned int range)
  215. {
  216. if ((range + 1) > _archive.size()) {
  217. return false;
  218. }
  219. for (size_t i = 0; i < range; i++) {
  220. if (_archive[i].value * _archive[i + 1].value < 0) {
  221. return false;
  222. }
  223. }
  224. return true;
  225. }
  226. bool oscillating(unsigned int range)
  227. {
  228. if ((range + 1) > _archive.size()) {
  229. return false;
  230. }
  231. for (size_t i = _archive.size() - range; i < _archive.size() - 1; i++) {
  232. if (_archive[i].value * _archive[i + 1].value > 0) {
  233. return false;
  234. }
  235. }
  236. return true;
  237. }
  238. double shift_quanta()
  239. {
  240. double factor = 0;
  241. if (oscillating(_past_length - 1) and
  242. _archive.back().date - _archive.front().date != 0) {
  243. double acc;
  244. double local_estim;
  245. int cnt;
  246. acc = 0;
  247. cnt = 0;
  248. for (size_t i = 0; i < _archive.size() - 2; ++i) {
  249. if (0 != (_archive[i + 2].date - _archive[i].date)) {
  250. if ((_archive.back().value * _archive[i + 1].value) > 0) {
  251. local_estim =
  252. 1 - (_archive[i + 1].date - _archive[i].date) /
  253. (_archive[i + 2].date - _archive[i].date);
  254. } else {
  255. local_estim = (_archive[i + 1].date - _archive[i].date) /
  256. (_archive[i + 2].date - _archive[i].date);
  257. }
  258. acc += local_estim;
  259. cnt++;
  260. }
  261. }
  262. acc = acc / cnt;
  263. factor = acc;
  264. _archive.resize(0);
  265. }
  266. return factor;
  267. }
  268. void store_change(double val, const typename Time::type &time)
  269. {
  270. record_t record;
  271. record.date = time;
  272. record.value = val;
  273. _archive.push_back(record);
  274. while (_archive.size() > _past_length) {
  275. _archive.pop_front();
  276. }
  277. }
  278. void update_thresholds()
  279. {
  280. auto step_number = static_cast<double>(_step_number);
  281. _up_threshold = _offset + _step_size * (step_number + 1);
  282. _down_threshold = _offset + _step_size * (step_number - 1);
  283. }
  284. void update_thresholds(double factor)
  285. {
  286. auto step_number = static_cast<double>(_step_number);
  287. _up_threshold = _offset + _step_size * (step_number + (1 - factor));
  288. _down_threshold = _offset + _step_size * (step_number - (1 - factor));
  289. }
  290. struct direction
  291. {
  292. enum values
  293. {
  294. DIRECTION_UP, DIRECTION_DOWN
  295. };
  296. };
  297. void update_thresholds(double factor, const typename direction::values &d)
  298. {
  299. auto step_number = static_cast<double>(_step_number);
  300. if (d == direction::DIRECTION_UP) {
  301. _up_threshold = _offset + _step_size * (step_number + (1 - factor));
  302. _down_threshold = _offset + _step_size * (step_number - 1);
  303. } else {
  304. _up_threshold = _offset + _step_size * (step_number + 1);
  305. _down_threshold = _offset + _step_size * (step_number - (1 - factor));
  306. }
  307. }
  308. struct state
  309. {
  310. enum values
  311. {
  312. PHASE, ADAPTIVE_STATE, STEP_NUMBER, OFFSET, UP_THRESHOLD, DOWN_THRESHOLD
  313. };
  314. };
  315. struct var
  316. {
  317. enum values
  318. {
  319. UP, DOWN, VALUE
  320. };
  321. };
  322. struct phase
  323. {
  324. enum values
  325. {
  326. INIT, IDLE, RESPONSE
  327. };
  328. };
  329. struct adaptive_state
  330. {
  331. enum values
  332. {
  333. IMPOSSIBLE, POSSIBLE, DONE
  334. };
  335. };
  336. struct record_t
  337. {
  338. double value;
  339. typename Time::type date;
  340. };
  341. // parameters
  342. bool _adaptive;
  343. bool _zero_init_offset;
  344. unsigned int _past_length;
  345. double _step_size;
  346. // state
  347. int _phase;
  348. int _adaptive_state;
  349. unsigned int _step_number; // long int
  350. double _offset;
  351. double _up_threshold;
  352. double _down_threshold;
  353. std::deque<record_t> _archive;
  354. };
  355. }
  356. }
  357. #endif