Minsky
schema3.cc
Go to the documentation of this file.
1  /*
2  @copyright Steve Keen 2017
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "dataOp.h"
20 #include "schema3.h"
21 #include "sheet.h"
22 #include "userFunction.h"
23 #include "minsky_epilogue.h"
24 
25 using namespace std;
26 
27 namespace classdesc {template <> Factory<minsky::Item,string>::Factory() {}}
28 
29 
30 namespace classdesc_access
31 {
32 }
33 
34 namespace schema3
35 {
36 
37  // binary serialisation used to serialise the tensorInit field of
38  // variableValues into the minsky schema, fixed off here, rather
39  // than classdesc generated to ensure backward compatibility
40  void pack(classdesc::pack_t& b, const civita::XVector& a)
41  {
42  b<<a.name<<a.dimension<<uint64_t(a.size());
43  for (const auto& i: a)
44  b<<civita::str(i,a.dimension.units);
45  }
46 
47  void unpack(classdesc::pack_t& b, civita::XVector& a)
48  {
49  uint64_t size;
50  std::string x;
51  a.clear();
52  b>>a.name>>a.dimension>>size;
53  for (size_t i=0; i<size; ++i)
54  {
55  b>>x;
56  a.push_back(x);
57  }
58  }
59 
60  void pack(classdesc::pack_t& b, const civita::TensorVal& a)
61  {
62  b<<uint64_t(a.size());
63  for (auto i: a)
64  b<<i;
65  b<<uint64_t(a.index().size());
66  for (auto i: a.index())
67  b<<uint64_t(i);
68 
69  b<<uint64_t(a.hypercube().xvectors.size());
70  for (const auto& i: a.hypercube().xvectors)
71  pack(b, i);
72  }
73 
74 
75  void unpack(classdesc::pack_t& b, civita::TensorVal& a)
76  {
77  uint64_t sz;
78  b>>sz;
79  vector<double> data;
80  for (size_t i=0; i<sz; ++i)
81  {
82  data.emplace_back();
83  b>>data.back();
84  }
85  b>>sz;
86  set<size_t> index;
87  for (size_t i=0; i<sz; ++i)
88  {
89  uint64_t x;
90  b>>x;
91  index.insert(x);
92  }
93 
94  b>>sz;
95  civita::Hypercube hc;
96 
97  for (size_t i=0; i<sz; ++i)
98  {
99  civita::XVector xv;
100  unpack(b,xv);
101  hc.xvectors.push_back(xv);
102  }
103  assert(std::find_if(index.begin(),index.end(),[&](size_t i){return i>=hc.numElements();})==index.end());
104  a.index(std::move(index)); //NOLINT
105  a.hypercube(std::move(hc)); //dimension data
106  assert(a.size()==data.size());
107  memcpy(a.begin(),data.data(),data.size()*sizeof(data[0]));
108  }
109 
110  Optional<classdesc::CDATA> Item::convertTensorDataFromSchema2(const Optional<classdesc::CDATA>& x)
111  {
113  if (x)
114  {
115  auto buf=minsky::decode(*x);
116  civita::TensorVal tmp;
117  schema2::unpack(buf,tmp);
118  buf.reseti();
119  pack(buf,tmp);
120  r=minsky::encode(buf);
121  }
122  return r;
123  }
124 
125  // map of object to ID, that allocates a new ID on objects not seen before
126  struct IdMap: public map<const void*,int>
127  {
128  int nextId=0;
129  set<minsky::RavelLockGroup*> lockGroups;
130  int at(const void* o) {
131  auto i=find(o);
132  if (i==end())
133  return emplace(o,nextId++).first->second;
134  return i->second;
135  }
136  int operator[](const void* o) {return at(o);}
137  vector<int> at(const minsky::Item& item) {
138  vector<int> r;
139  for (size_t i=0; i<item.portsSize(); ++i)
140  r.push_back(at(item.ports(i).lock().get()));
141  return r;
142  }
143 
144  template <class T>
145  bool emplaceIf(vector<Item>& items, const minsky::Item* i)
146  {
147  auto* j=dynamic_cast<const T*>(i);
148  if (j)
149  {
150  // do not write invisible unwired GodleyIcon variables to the schema. For #1759.
151  if (auto v=i->variableCast())
152  if (auto g=dynamic_cast<minsky::GodleyIcon*>(v->controller.lock().get()))
153  for (size_t i=0; !g->variableDisplay() && i<2; ++i)
154  if (auto p=v->ports(i).lock())
155  if (p->wires().empty())
156  return j;
157 
158  items.emplace_back(at(i), *j, at(*j));
159  if (auto* g=dynamic_cast<const minsky::GodleyIcon*>(i))
160  {
161  // insert port references from flow/stock vars
162  items.back().ports.clear();
163  for (const auto& v: g->flowVars())
164  items.back().ports.push_back(at(v->ports(1).lock().get()));
165  for (const auto& v: g->stockVars())
166  items.back().ports.push_back(at(v->ports(0).lock().get()));
167  }
168  if (auto* d=dynamic_cast<const minsky::DataOp*>(i))
169  {
170  items.back().dataOpData=d->data;
171  items.back().name=d->description();
172  }
173  if (auto* s=dynamic_cast<const minsky::Sheet*>(i))
174  {
175  items.back().showSlice=s->showRowSlice;
176  items.back().showColSlice=s->showColSlice;
177  }
178  if (auto* d=dynamic_cast<const minsky::UserFunction*>(i))
179  {
180  items.back().expression=d->expression;
181  items.back().name=d->description();
182  }
183  if (auto* r=dynamic_cast<const minsky::Ravel*>(i))
184  {
185  if (r->lockGroup)
186  lockGroups.insert(r->lockGroup.get());
187  auto s=r->getState();
188  if (!s.handleStates.empty())
189  {
190  items.back().ravelState=s;
191  items.back().dimensions=r->axisDimensions;
192  items.back().editorMode=r->editorMode();
193  }
194  if (r->flipped) items.back().rotation=180;
195  }
196  if (auto* l=dynamic_cast<const minsky::Lock*>(i))
197  if (l->locked())
198  items.back().ravelState=l->lockedState;
199  }
200  return j;
201  }
202  };
203 
204  namespace
205  {
206  inline bool matchesStart(const string& x, const string& y)
207  {
208  const size_t n=min(x.length(),y.length());
209  return x.substr(0,n)==y.substr(0,n);
210  }
211  }
212 
213  struct MinskyItemFactory: public classdesc::Factory<minsky::Item,string>
214  {
215  template <class T>
217  auto s=typeName<T>();
218  // remove minsky namespace
219  static const char* ns="minsky::";
220  static const int eop=strlen(ns);
221  if (s.substr(0,eop)==ns)
222  s=s.substr(eop);
223  registerType<T>(s);
224  }
226  {
227  registerClassType<minsky::Item>();
228  registerClassType<minsky::IntOp>();
229  registerClassType<minsky::DataOp>();
230  registerClassType<minsky::UserFunction>();
231  registerClassType<minsky::Ravel>();
232  registerClassType<minsky::Lock>();
233  registerClassType<minsky::Sheet>();
234  registerClassType<minsky::VarConstant>();
235  registerClassType<minsky::GodleyIcon>();
236  registerClassType<minsky::PlotWidget>();
237  registerClassType<minsky::SwitchIcon>();
238  }
239 
240  // override here for special handling of Operations and Variables
241  minsky::Item* create(const string& t) const
242  {
243  if (t=="Operation:rho") // handle legacy names after operation rename
245  if (matchesStart(t,"Operation:"))
247  (enum_keys<minsky::OperationType::Type>()
248  (t.substr(t.find(':')+1)));
249  if (matchesStart(t,"Variable:"))
251  (enum_keys<minsky::VariableType::Type>()
252  (t.substr(t.find(':')+1)));
253  try
254  {
255  return classdesc::Factory<minsky::Item,string>::create("::minsky::"+t);
256  }
257  catch (...)
258  {
259  assert(!"item type not registered");
260  return nullptr;
261  }
262  }
263  };
264 
266  {
267  map<int,schema1::UnionLayout> layout;
268  Schema1Layout(const vector<shared_ptr<schema1::Layout>>& x) {
269  for (const auto& i: x)
270  {
271  // serialise to json, then deserialise to a UnionLayout
272  json_pack_t jbuf;
273  i->json_pack(jbuf,"");
274  json_unpack(jbuf,"",layout[i->id]);
275  }
276  }
277  template <class V, class O>
278  void addItem(V& vec, const O& item) {
279  vec.emplace_back(item);
280  if (layout.count(item.id))
281  vec.back().addLayout(layout[item.id]);
282  }
283  };
284 
285  void Item::packTensorInit(const minsky::VariableBase& v)
286  {
287  if (auto val=v.vValue())
288  if (val->tensorInit.rank())
289  {
290  pack_t buf;
291  pack(buf,val->tensorInit);
292  tensorData=minsky::encode(buf);
293  }
294  }
295 
296  struct MinskyImpl
297  {
298  IdMap itemMap, pubItemMap; // for serialisation
299  map<int, minsky::ItemPtr> reverseItemMap; // for deserialisation
300  };
301 
302  void Minsky::makeImpl()
303  {
304  impl=make_shared<MinskyImpl>();
305  }
306 
307  Minsky::~Minsky()=default; // required because of Pimpl pattern
308 
309  Minsky::Minsky(const minsky::Group& g, bool packTensorData)
310  {
311  makeImpl();
312  auto& itemMap=impl->itemMap;
313 
314  g.recursiveDo(&minsky::GroupItems::items,[&](const minsky::Items&,minsky::Items::const_iterator i) {
315  itemMap.emplaceIf<minsky::Ravel>(items, i->get()) ||
316  itemMap.emplaceIf<minsky::OperationBase>(items, i->get()) ||
317  itemMap.emplaceIf<minsky::VariableBase>(items, i->get()) ||
318  itemMap.emplaceIf<minsky::GodleyIcon>(items, i->get()) ||
319  itemMap.emplaceIf<minsky::PlotWidget>(items, i->get()) ||
320  itemMap.emplaceIf<minsky::SwitchIcon>(items, i->get()) ||
321  itemMap.emplaceIf<minsky::Sheet>(items, i->get()) ||
322  itemMap.emplaceIf<minsky::Item>(items, i->get());
323  if (packTensorData) //pack tensor data
324  if (auto* v=(*i)->variableCast())
325  if (!items.back().tensorData)
326  items.back().packTensorInit(*v);
327 
328  return false;
329  });
330 
331  // add any I/O variables
332  vector<int> inVars, outVars;
333  for (auto& i: g.inVariables)
334  inVars.push_back(itemMap[i.get()]);
335  for (auto& i: g.outVariables)
336  outVars.push_back(itemMap[i.get()]);
337  inVariables=inVars;
338  outVariables=outVars;
339 
340  // search for and link up integrals to their variables, and Godley table ports
341  g.recursiveDo(&minsky::GroupItems::items,[&](const minsky::Items&,minsky::Items::const_iterator i) {
342  if (auto* integ=dynamic_cast<minsky::IntOp*>(i->get()))
343  {
344  const int id=itemMap[i->get()];
345  for (auto& j: items)
346  if (j.id==id)
347  {
348  // nb conversion to Item* essential here, as
349  // conversion of derived class to void* may not be
350  // equivalent
351  assert(itemMap.count(static_cast<minsky::Item*>(integ->intVar.get())));
352  j.intVar.reset(new int(itemMap[static_cast<minsky::Item*>(integ->intVar.get())]));
353  break;
354  }
355  }
356  return false;
357  });
358 
360  [&](const minsky::Wires&,minsky::Wires::const_iterator i) {
361  wires.emplace_back(itemMap[i->get()], **i);
362  assert(itemMap.count((*i)->from().get()) && itemMap.count((*i)->to().get()));
363  wires.back().from=itemMap[(*i)->from().get()];
364  wires.back().to=itemMap[(*i)->to().get()];
365  return false;
366  });
367 
369  [&](const minsky::Groups&,minsky::Groups::const_iterator i) {
370  groups.emplace_back(itemMap[i->get()], **i);
371  for (auto& j: (*i)->items)
372  {
373  // some invisible items are excluded from the schema
374  assert(!j->visible() || itemMap.count(j.get()));
375  groups.back().items.push_back(itemMap[j.get()]);
376  if (j==(*i)->displayPlot)
377  groups.back().displayPlot=itemMap[j.get()];
378  }
379  for (auto& j: (*i)->groups)
380  groups.back().items.push_back(itemMap[j.get()]);
381  for (auto& v: (*i)->inVariables)
382  {
383  assert(itemMap.count(v.get()));
384  groups.back().inVariables->push_back(itemMap[v.get()]);
385  }
386  for (auto& v: (*i)->outVariables)
387  {
388  assert(itemMap.count(v.get()));
389  groups.back().outVariables->push_back(itemMap[v.get()]);
390  }
391  return false;
392  });
393 
394 
395 
396  // process lock groups
397  for (auto lg: itemMap.lockGroups)
398  {
399  lockGroups.emplace_back();
400  auto& slg=lockGroups.back();
401  for (auto& wr: lg->ravels())
402  if (auto r=wr.lock())
403  slg.ravels.push_back(itemMap.at(static_cast<minsky::Item*>(r.get())));
404  else
405  slg.ravels.push_back(-1); // indicate invalidity
406  for (auto& hli: lg->handleLockInfo)
407  slg.handleLockInfo.emplace_back(hli);
408  }
409  }
410 
411  PhillipsDiagram::PhillipsDiagram(const minsky::PhillipsDiagram& pd)
412  {
413  IdMap itemMap;
414  for (auto& [key,stock]: pd.stocks)
415  itemMap.emplaceIf<minsky::VariableBase>(stocks, &stock);
416 
417  for (auto& [key,flow]: pd.flows)
418  {
419  flows.emplace_back(itemMap[&flow], flow);
420  assert(itemMap.count(flow.from().get()) && itemMap.count(flow.to().get()));
421  flows.back().from=itemMap[flow.from().get()];
422  flows.back().to=itemMap[flow.to().get()];
423  for (auto& term: flow.terms)
424  flows.back().terms.emplace_back(term.first, Item(-1,term.second,{}));
425  }
426  }
427 
428  void Minsky::populateSchemaPublicationTabs(const std::vector<minsky::PubTab>& pubTabs)
429  {
430  assert(impl.get());
431  auto& itemMap=impl->itemMap;
432  publicationTabs.clear();
433  if (pubTabs.size()==1 && pubTabs.front().items.empty()) return; // don't bother adding a single empty pub tab
434  for (auto& i: pubTabs)
435  {
436  publicationTabs.emplace_back();
437  publicationTabs.back().name=i.name;
438  for (auto& j: i.items)
439  {
440  // add locally added notes on publication tab to items list in schema
441  if (!itemMap.count(j.itemRef.get()))
442  itemMap.emplaceIf<minsky::Item>(publicationItems,j.itemRef.get());
443  publicationTabs.back().items.emplace_back(itemMap[j.itemRef.get()], j);
444  }
445  }
446  }
447 
448  void Minsky::populateMinsky(minsky::Minsky& m) const
449  {
450  const minsky::LocalMinsky lm(m);
451  m.model->clear();
452  populateGroup(*m.model);
453  m.canvas.model=m.model;
454 
455  m.model->setZoom(zoomFactor);
456  m.model->bookmarks.insert(bookmarks.begin(), bookmarks.end());
457  m.dimensions=dimensions;
458  m.conversions=conversions;
459  m.fileVersion=minskyVersion;
460 
461  static_cast<minsky::Simulation&>(m)=rungeKutta;
462 
463  phillipsDiagram.populatePhillipsDiagram(m.phillipsDiagram);
464  populatePublicationTabs(m.publicationTabs);
465  }
466 
467  void populateNote(minsky::NoteBase& x, const Note& y)
468  {
469  if (y.detailedText && !y.detailedText->empty())
471  if (y.tooltip && !y.tooltip->empty())
472  x.tooltip(*y.tooltip);
473  }
474 
475  void populateItem(minsky::Item& x, const Item& y)
476  {
477  populateNote(x,y);
478  x.m_x=y.x;
479  x.m_y=y.y;
480  x.m_sf=y.scaleFactor;
481  x.rotation(y.rotation);
482  x.iWidth(y.width);
483  x.iHeight(y.height);
484  x.bookmark=y.bookmark;
485  if (auto* x1=dynamic_cast<minsky::DataOp*>(&x))
486  {
487  if (y.name)
488  x1->description(*y.name);
489  if (y.dataOpData)
490  x1->data=*y.dataOpData;
491  }
492  if (auto* x1=dynamic_cast<minsky::UserFunction*>(&x))
493  {
494  if (y.name)
495  x1->description(*y.name);
496  if (y.expression)
497  x1->expression=*y.expression;
498  }
499 
500  if (auto* x1=dynamic_cast<minsky::Ravel*>(&x))
501  {
502  if (y.ravelState)
503  {
504  x1->applyState(y.ravelState->toRavelRavelState());
505  x1->redistributeHandles();
506  SchemaHelper::initHandleState(*x1,y.ravelState->toRavelRavelState());
507  }
508 
509  if (y.dimensions)
510  x1->axisDimensions=*y.dimensions;
511  if (y.editorMode && *y.editorMode!=x1->editorMode())
512  x1->toggleEditorMode();
513  x1->flipped=minsky::flipped(y.rotation);
514  }
515  if (auto* x1=dynamic_cast<minsky::Lock*>(&x))
516  {
517  if (y.ravelState)
518  {
519  x1->lockedState=y.ravelState->toRavelRavelState();
520  x1->tooltip(ravel::Ravel::description(x1->lockedState));
521  }
522  }
523  if (auto* x1=dynamic_cast<minsky::VariableBase*>(&x))
524  {
525  if (y.name)
526  x1->name(*y.name);
527  if (y.slider)
528  {
529  x1->sliderStepRel(y.slider->stepRel);
530  x1->enableSlider(y.slider->visible);
531  x1->sliderMin(y.slider->min);
532  x1->sliderMax(y.slider->max);
533  x1->sliderStep(y.slider->step);
534  }
535  x1->miniPlotEnabled(y.miniPlot);
536  // variableValue attributes populated later once variable is homed in its group
537  }
538  if (auto* x1=dynamic_cast<minsky::OperationBase*>(&x))
539  {
540  if (y.axis) x1->axis=*y.axis;
541  if (y.arg) x1->arg=*y.arg;
542  }
543  if (auto* x1=dynamic_cast<minsky::GodleyIcon*>(&x))
544  {
545  std::vector<std::vector<std::string>> data;
546  std::vector<minsky::GodleyAssetClass::AssetClass> assetClasses;
547  if (y.data) data=*y.data;
548  if (y.assetClasses) assetClasses=*y.assetClasses;
549  SchemaHelper::setPrivates(*x1,data,assetClasses);
550  try
551  {
552  x1->table.orderAssetClasses();
553  }
554  catch (const std::exception&) {}
555  if (y.name) x1->table.title=*y.name;
556  if (y.editorMode && *y.editorMode!=x1->editorMode())
557  x1->toggleEditorMode();
558  if (y.variableDisplay)
559  SchemaHelper::setVariableDisplay(*x1, *y.variableDisplay);
560  if (y.buttonDisplay && *y.buttonDisplay!=x1->buttonDisplay())
561  x1->toggleButtons();
562  if (y.currency) x1->currency=*y.currency;
563  }
564  if (auto* x1=dynamic_cast<minsky::PlotWidget*>(&x))
565  {
566  x1->bb.update(*x1);
567  if (y.name) x1->title=*y.name;
568  y.applyPlotOptions(*x1);
569  if (y.palette) x1->palette=*y.palette;
570  if (y.ports.size()>x1->nBoundsPorts)
571  x1->numLines((y.ports.size()-x1->nBoundsPorts)/4);
572  }
573  if (auto* x1=dynamic_cast<minsky::Sheet*>(&x))
574  {
575  if (y.showSlice)
576  x1->showRowSlice=*y.showSlice;
577  if (y.showColSlice)
578  x1->showColSlice=*y.showColSlice;
579  }
580  if (auto* x1=dynamic_cast<minsky::SwitchIcon*>(&x))
581  {
582  x1->flipped=minsky::flipped(y.rotation);
583  if (y.ports.size()>=2)
584  x1->setNumCases(y.ports.size()-2);
585  }
586  if (auto* x1=dynamic_cast<minsky::Group*>(&x))
587  {
588  x1->bb.update(*x1);
589  if (y.name) x1->title=*y.name;
590  if (y.bookmarks)
591  {
592  x1->bookmarks.clear();
593  x1->bookmarks.insert(y.bookmarks->begin(), y.bookmarks->end());
594  }
595  }
596  }
597 
598  void populateWire(minsky::Wire& x, const Wire& y)
599  {
600  populateNote(x,y);
601  if (y.coords)
602  x.coords(*y.coords);
603  }
604 
605  struct LockGroupFactory: public shared_ptr<minsky::RavelLockGroup>
606  {
607  LockGroupFactory(): shared_ptr<minsky::RavelLockGroup>(new minsky::RavelLockGroup) {}
608  };
609 
610  void Minsky::populatePublicationTabs(std::vector<minsky::PubTab>& pubTabs) const
611  {
612  assert(impl.get());
613  auto& itemMap=impl->reverseItemMap;
614 
615  // add in publication tab only items
617  for (auto& i: publicationItems)
618  if (auto newItem=itemMap[i.id]=minsky::ItemPtr(factory.create(i.type)))
619  populateItem(*newItem,i);
620 
621  pubTabs.clear();
622  for (auto& pub: publicationTabs)
623  {
624  pubTabs.emplace_back(pub.name);
625  pubTabs.back().offsx=pub.x;
626  pubTabs.back().offsy=pub.y;
627  pubTabs.back().m_zoomFactor=pub.zoomFactor;
628 
629  for (auto& item: pub.items)
630  if (itemMap.contains(item.item))
631  pubTabs.back().items.emplace_back(itemMap[item.item], item);
632  }
633  if (pubTabs.empty()) pubTabs.emplace_back("Publication");
634  }
635 
636  void Minsky::populateGroup(minsky::Group& g) const {
637  assert(impl.get());
638  auto& itemMap=impl->reverseItemMap;
639  map<int, weak_ptr<minsky::Port>> portMap;
640  map<int, schema3::Item> schema3VarMap;
642  map<int,LockGroupFactory> lockGroups;
643 
644  for (const auto& i: items)
645  if (auto newItem=itemMap[i.id]=g.addItem(factory.create(i.type)))
646  {
647  populateItem(*newItem,i);
648  for (size_t j=0; j<min(newItem->portsSize(), i.ports.size()); ++j)
649  portMap[i.ports[j]]=newItem->ports(j);
650  if (newItem->variableCast())
651  schema3VarMap[i.id]=i;
652  }
653 
654  if (inVariables)
655  for (auto i: *inVariables)
656  g.inVariables.push_back(itemMap[i]);
657  if (outVariables)
658  for (auto i: *outVariables)
659  g.outVariables.push_back(itemMap[i]);
660 
661  // second loop over items to wire up integrals, and populate Godley table variables
662  for (const auto& i: items)
663  {
664  if ((i.type=="IntOp" || i.type=="Operation:integrate") && i.intVar)
665  {
666  assert(itemMap.count(i.id));
667  assert(dynamic_pointer_cast<minsky::IntOp>(itemMap[i.id]));
668  if (auto* integ=dynamic_cast<minsky::IntOp*>(itemMap[i.id].get()))
669  {
670  assert(integ->intVar);
671  assert(integ->intVar->type()==minsky::VariableType::integral);
672  if (itemMap.contains(*i.intVar))
673  {
674  if (integ->coupled()) integ->toggleCoupled();
675  g.removeItem(*integ->intVar);
676  integ->intVar=itemMap[*i.intVar];
677  if (!integ->intVar || integ->intVar->type()!=minsky::VariableType::integral)
678  // input mky file is corrupted at this point
679  integ->description(integ->description());
680  }
681  auto iv=schema3VarMap.find(*i.intVar);
682  if (iv!=schema3VarMap.end())
683  if ((!i.ports.empty() && !iv->second.ports.empty() && i.ports[0]==iv->second.ports[0]) != integ->coupled())
684  integ->toggleCoupled();
685  // ensure that the correct port is inserted (may have been the deleted intVar)
686  if (!i.ports.empty())
687  portMap[i.ports[0]]=integ->coupled()? integ->intVar->ports(0): integ->ports(0);
688  }
689  }
690  if (i.type=="GodleyIcon")
691  {
692  assert(itemMap.count(i.id));
693  if (auto* godley=dynamic_cast<minsky::GodleyIcon*>(itemMap[i.id].get()))
694  {
695  minsky::GodleyIcon::Variables flowVars, stockVars;
696  for (auto p: i.ports)
697  {
698  auto newP=portMap.find(p);
699  if (newP!=portMap.end())
700  if (auto ip=g.findItem(newP->second.lock()->item()))
701  if (auto v=dynamic_pointer_cast<minsky::VariableBase>(ip))
702  switch (v->type())
703  {
705  stockVars.push_back(v);
706  break;
708  flowVars.push_back(v);
709  break;
710  default:
711  break;
712  }
713  }
714  SchemaHelper::setStockAndFlow(*godley, flowVars, stockVars);
715  try
716  {
717  godley->update();
718  }
719  catch (...) {} //ignore exceptions: ticket #1045
720  }
721  }
722  if (i.type=="Ravel" && i.lockGroup)
723  if (auto r=dynamic_pointer_cast<minsky::Ravel>(itemMap[i.id]))
724  {
725  // note: legacy lock group format handling
726  r->lockGroup=lockGroups[*i.lockGroup];
727  r->lockGroup->addRavel(r);
728  if (i.lockGroupHandles)
729  r->lockGroup->setLockHandles({i.lockGroupHandles->begin(), i.lockGroupHandles->end()});
730  }
731  }
732 
733  // add in new lockGroup info
734  for (auto& lgi: this->lockGroups)
735  {
736  auto lockGroup=make_shared<minsky::RavelLockGroup>();
737  for (auto i: lgi.ravels)
738  if (auto r=dynamic_pointer_cast<minsky::Ravel>(itemMap[i]))
739  {
740  lockGroup->addRavel(r);
741  r->lockGroup=lockGroup;
742  }
743  else
744  lockGroup->addRavel({});
745  lockGroup->handleLockInfo=lgi.handleLockInfo;
746  }
747 
748  for (const auto& w: wires)
749  if (portMap.contains(w.to) && portMap.contains(w.from))
750  {
752  (*g.addWire(new minsky::Wire(portMap[w.from],portMap[w.to])),w);
753  }
754 
755  for (const auto& i: groups)
756  populateItem(*(itemMap[i.id]=g.addGroup(new minsky::Group)),i);
757 
758  // second loop over groups, because groups can contain other groups
759  for (const auto& i: groups)
760  {
761  assert(itemMap.count(i.id));
762  auto newG=dynamic_pointer_cast<minsky::Group>(itemMap[i.id]);
763  if (newG)
764  {
765  for (auto j: i.items)
766  {
767  auto it=itemMap.find(j);
768  if (it!=itemMap.end())
769  {
770  newG->addItem(it->second, true/*inSchema*/);
771  }
772  }
773  if (i.displayPlot>=0)
774  {
775  auto it=itemMap.find(i.displayPlot);
776  if (it!=itemMap.end())
777  newG->displayPlot=dynamic_pointer_cast<minsky::PlotWidget>(it->second);
778  }
779  if (i.inVariables)
780  for (auto j: *i.inVariables)
781  {
782  auto it=itemMap.find(j);
783  if (it!=itemMap.end())
784  if (auto v=dynamic_pointer_cast<minsky::VariableBase>(it->second))
785  {
786  newG->addItem(it->second);
787  newG->inVariables.push_back(v);
788  v->controller=newG;
789  }
790  }
791  if (i.outVariables)
792  for (auto j: *i.outVariables)
793  {
794  auto it=itemMap.find(j);
795  if (it!=itemMap.end())
796  if (auto v=dynamic_pointer_cast<minsky::VariableBase>(it->second))
797  {
798  newG->addItem(it->second);
799  newG->outVariables.push_back(v);
800  v->controller=newG;
801  }
802  }
803  }
804  }
805  // now that variables have been homed in their groups, set the variableValue stuff
806  for (auto& i: schema3VarMap)
807  {
808  auto it=itemMap.find(i.first);
809  if (!it->second) continue;
810  if (auto* v=it->second->variableCast())
811  {
812  if (i.second.init)
813  v->init(*i.second.init);
814  if (i.second.units)
815  v->setUnits(*i.second.units);
816  populateNote(*v,i.second);
817  if (auto val=v->vValue())
818  {
819  if (i.second.csvDataSpec)
820  val->csvDialog.spec=*i.second.csvDataSpec;
821  if (i.second.url)
822  val->csvDialog.url=*i.second.url;
823  if (i.second.tensorData)
824  {
825  auto buf=minsky::decode(*i.second.tensorData);
826  try
827  {
828  civita::TensorVal tmp;
829  unpack(buf, tmp);
830  *val=tmp;
831  val->tensorInit=std::move(tmp);
832  assert(val->idxInRange());
833  }
834  catch (const std::exception& ex) {
835  val->tensorInit.hypercube({});
836 #if !defined(NDEBUG) || !defined(_WIN32)
837  cout<<ex.what()<<endl;
838 #endif
839  }
840  catch (...) {
841  val->tensorInit.hypercube({});
842  assert(val->idxInRange());
843  } // absorb for now - maybe log later
844  }
845  }
846  }
847  }
848  }
849 
850  void PhillipsDiagram::populatePhillipsDiagram(minsky::PhillipsDiagram& pd) const
851  {
852  static const MinskyItemFactory itemFactory;
853  map<int, weak_ptr<minsky::Port>> portMap;
854  for (auto& i: stocks)
855  {
856  minsky::PhillipsStock stock;
857  populateItem(stock, i);
858  auto& item=pd.stocks[stock.valueId()]=stock;
859  for (size_t j=0; j<std::min(i.ports.size(), stock.numPorts()); ++j)
860  portMap[i.ports[j]]=item.ports(j);
861  }
862 
863  for (auto& i: flows)
864  {
865  assert(portMap[i.from].lock() && portMap[i.to].lock());
866  minsky::PhillipsFlow flow(portMap[i.from],portMap[i.to]);
867  populateWire(flow, i);
868  for (auto& j: i.terms)
869  {
870  flow.terms.emplace_back(j.first, minsky::FlowVar{});
871  populateItem(flow.terms.back().second, j.second);
872  }
873  auto fromId=flow.from()->item().variableCast()->valueId();
874  auto toId=flow.to()->item().variableCast()->valueId();
875  auto success=pd.flows.emplace(make_pair(fromId, toId), flow).second; //NOLINT
876  assert(success);
877  }
878  }
879 
880 }
881 
882 
std::size_t numPorts() const override
Optional< std::map< double, double > > dataOpData
Definition: schema3.h:114
std::vector< WirePtr > Wires
Definition: wire.h:103
Optional< minsky::ShowSlice > showSlice
Definition: schema3.h:130
int at(const void *o)
Definition: schema3.cc:130
std::vector< VariablePtr > inVariables
Definition: group.h:82
void pack(classdesc::pack_t &, const classdesc::string &, classdesc::ref< ecolab::urand > &)
Optional< std::string > name
Definition: plotOptions.h:49
std::size_t portsSize() const
number of ports
Definition: item.h:184
Optional< std::string > axis
Definition: schema3.h:122
map< int, schema1::UnionLayout > layout
Definition: schema3.cc:267
void populateWire(minsky::Wire &x, const Wire &y)
Definition: schema3.cc:598
void addItem(V &vec, const O &item)
Definition: schema3.cc:278
classdesc::pack_t decode(const classdesc::CDATA &data)
decode ascii-encoded representation to binary data
Definition: schemaHelper.cc:34
Optional< std::string > expression
Definition: schema3.h:115
ItemPtr addItem(const std::shared_ptr< Item > &it, bool inSchema=false) override
Definition: group.h:262
void unpack(classdesc::pack_t &, const classdesc::string &, classdesc::ref< ecolab::urand > &)
int operator[](const void *o)
Definition: schema3.cc:136
std::vector< int > ports
Definition: schema3.h:75
Optional< bool > editorMode
Definition: schema3.h:127
float iHeight() const
Definition: item.h:224
map< int, minsky::ItemPtr > reverseItemMap
Definition: schema3.cc:299
ravel::RavelState toRavelRavelState() const
Optional< string > currency
Definition: schema3.h:128
float m_sf
scale factor of item on canvas, or within group
Definition: item.h:174
STL namespace.
void populateNote(minsky::NoteBase &x, const Note &y)
Definition: schema3.cc:467
std::shared_ptr< Item > ItemPtr
Definition: item.h:57
Optional< Slider > slider
Definition: schema3.h:109
Optional< minsky::ShowSlice > showColSlice
Definition: schema3.h:131
Optional< std::vector< ecolab::Plot::LineStyle > > palette
Definition: schema3.h:135
bool recursiveDo(M GroupItems::*map, O op) const
Perform action heirarchically on elements of map map. If op returns true, the operation terminates...
Definition: group.h:111
Model model
Definition: canvas.h:103
convenience class to omit writing XML records when data absent or empty
Definition: optional.h:39
virtual std::string const & tooltip() const
Definition: noteBase.h:36
bool flipped(double rotation)
returns if the angle (in degrees) is in the second or third quadrant
Definition: geometry.h:102
Optional< schema2::RavelState > ravelState
Definition: schema3.h:117
static VariableBase * create(Type type)
Definition: variable.cc:116
std::vector< VariablePtr > outVariables
Definition: group.h:82
Optional< std::vector< minsky::Bookmark > > bookmarks
Definition: schema3.h:133
std::vector< float > coords() const
display coordinates
Definition: wire.cc:45
Optional< std::vector< std::vector< std::string > > > data
Definition: schema3.h:125
ItemPtr findItem(const Item &it) const
finds item within this group or subgroups. Returns null if not found
Definition: group.cc:291
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
GroupPtr addGroup(const std::shared_ptr< Group > &)
Definition: group.cc:659
Optional< std::string > detailedText
Definition: schema3.h:59
float iWidth() const
Definition: item.h:217
Optional< bool > variableDisplay
Definition: schema3.h:127
std::vector< ItemPtr > Items
Definition: item.h:366
CDATA encode(const pack_t &buf)
Definition: schemaHelper.cc:51
Optional< std::vector< float > > coords
Definition: schema3.h:197
std::vector< PubTab > publicationTabs
Definition: minsky.h:156
virtual std::string valueId() const
string used to link to the VariableValue associated with this
Definition: variable.cc:186
Canvas canvas
Definition: minsky.h:256
float scaleFactor
scale factor of item on canvas, or within group
Definition: schema3.h:72
Optional< std::vector< minsky::GodleyAssetClass::AssetClass > > assetClasses
Definition: schema3.h:126
bool bookmark
Is this item also a bookmark?
Definition: noteBase.h:33
static OperationBase * create(Type type)
factory method.
Definition: operation.cc:545
void applyPlotOptions(PlotWidget &plot) const
Definition: plotOptions.h:90
std::vector< GroupPtr > Groups
Definition: group.h:54
std::map< std::pair< std::string, std::string >, PhillipsFlow > flows
Optional< minsky::Dimensions > dimensions
Definition: schema3.h:120
std::map< std::string, PhillipsStock > stocks
std::string str(T x)
utility function to create a string representation of a numeric type
Definition: str.h:33
Optional< std::string > tooltip
Definition: schema3.h:59
void unpack(classdesc::pack_t &b, civita::XVector &a)
Definition: schema2.cc:26
ItemFactory itemFactory
Definition: schema1.cc:176
std::unique_ptr< T > factory(const std::string &)
double rotation
rotation of icon, in degrees
Definition: schema3.h:73
vector< int > at(const minsky::Item &item)
Definition: schema3.cc:137
set< minsky::RavelLockGroup * > lockGroups
Definition: schema3.cc:129
std::vector< VariablePtr > Variables
Definition: godleyIcon.h:111
Groups groups
Definition: group.h:79
WirePtr addWire(const Item &from, const Item &to, unsigned toPortIdx, const std::vector< float > &coords)
add a wire from item from, to item to, connecting to the toIdx port of to, with coordinates ...
Definition: group.h:63
void populateItem(minsky::Item &x, const Item &y)
Definition: schema3.cc:475
bool matchesStart(const string &x, const string &y)
Definition: schema3.cc:206
PhillipsDiagram phillipsDiagram
Definition: minsky.h:155
Optional< double > arg
Definition: schema3.h:123
RAII set the minsky object to a different one for the current scope.
Definition: minsky.h:551
GroupPtr model
Definition: minsky.h:255
virtual std::weak_ptr< Port > ports(std::size_t i) const
callback to be run when item deleted from group
Definition: item.h:180
minsky::Item * create(const string &t) const
Definition: schema3.cc:241
float m_y
position in canvas, or within group
Definition: item.h:173
a container item for a plot widget
Definition: plotWidget.h:46
bool miniPlot
Definition: schema3.h:110
float m_x
Definition: item.h:173
Optional< bool > buttonDisplay
Definition: schema3.h:127
Conversions conversions
Definition: minsky.h:202
std::shared_ptr< VariableValue > vValue() const
variableValue associated with this. nullptr if not associated with a variableValue ...
Definition: variable.cc:161
Schema1Layout(const vector< shared_ptr< schema1::Layout >> &x)
Definition: schema3.cc:268
Dimensions dimensions
Definition: minsky.h:201
virtual std::string const & detailedText() const
Definition: noteBase.h:34
std::string fileVersion
Minsky version file was saved under.
Definition: minsky.h:351
float y
position in canvas, or within group
Definition: schema3.h:70
double rotation() const
Definition: item.h:211
bool emplaceIf(vector< Item > &items, const minsky::Item *i)
Definition: schema3.cc:145
ItemPtr removeItem(const Item &)
Definition: group.cc:212