4 #include "flame/base.h"
8 #define TRY PyMachine *machine = reinterpret_cast<PyMachine*>(raw); try
20 int PyMachine_init(PyObject *raw, PyObject *args, PyObject *kws)
23 assert(!machine->weak);
25 std::auto_ptr<Config> C(PyGLPSParse2Config(raw, args, kws));
27 machine->machine =
new Machine(*C);
30 } CATCH3(key_error, KeyError, -1)
31 CATCH3(
std::invalid_argument, ValueError, -1)
32 CATCH3(
std::exception, RuntimeError, -1)
36 void PyMachine_free(PyObject *raw)
39 std::auto_ptr<Machine> S(machine->machine);
40 machine->machine = NULL;
43 PyObject_ClearWeakRefs(raw);
45 Py_TYPE(raw)->tp_free(raw);
46 } CATCH2V(std::exception, RuntimeError)
50 PyObject *PyMachine_str(PyObject *raw)
53 std::ostringstream strm;
54 strm << *(machine->machine);
55 return PyString_FromString(strm.str().c_str());
60 PyObject *PyMachine_conf(PyObject *raw, PyObject *args, PyObject *kws)
63 PyObject *pyindex = Py_None;
64 const char *pnames[] = {
"index", NULL};
65 if(!PyArg_ParseTupleAndKeywords(args, kws,
"|O", (
char**)pnames, &pyindex))
69 if(pyindex==Py_None) {
70 C = machine->machine->conf();
71 }
else if(PyNumber_Check(pyindex)) {
72 PyRef<> pylong(PyNumber_Long(pyindex));
73 long index = PyLong_AsLong(pylong.py());
74 if(index<0 || (
unsigned long)index>=machine->machine->size())
75 return PyErr_Format(PyExc_IndexError,
"Element index out of range");
76 C = (*machine->machine)[index]->conf();
78 return PyErr_Format(PyExc_ValueError,
"'index' must be an integer or None");
87 PyObject *PyMachine_allocState(PyObject *raw, PyObject *args, PyObject *kws)
90 PyObject *d = Py_None, *W = Py_False;
91 const char *pnames[] = {
"config",
"inherit", NULL};
92 if(!PyArg_ParseTupleAndKeywords(args, kws,
"|OO", (
char**)pnames, &d, &W))
97 C = machine->machine->conf();
98 }
else if(PyDict_Check(d)) {
99 if(PyObject_IsTrue(W)) {
100 C = machine->machine->conf();
103 PyRef<> list(PyMapping_Items(d));
104 List2Config(C, list.py());
106 return PyErr_Format(PyExc_ValueError,
"allocState() needs config=None or {}");
108 std::auto_ptr<StateBase> state(machine->machine->allocState(C));
109 PyObject *ret = wrapstate(state.get());
115 struct PyStoreObserver :
public Observer
121 virtual ~PyStoreObserver() {}
124 PyRef<> tuple(PyTuple_New(2));
125 std::auto_ptr<StateBase> tmpstate(state->
clone());
126 PyRef<> statecopy(wrapstate(tmpstate.get()));
129 PyTuple_SET_ITEM(tuple.py(), 0, PyInt_FromSize_t(elem->
index));
130 PyTuple_SET_ITEM(tuple.py(), 1, statecopy.release());
131 if(PyList_Append(list.py(), tuple.py()))
132 throw std::runtime_error(
"");
136 struct PyScopedObserver
139 std::vector<size_t> observed;
140 PyScopedObserver(
Machine *m) : machine(m) {}
141 ~PyScopedObserver() {
142 for(
size_t i=0; i<observed.size(); i++) {
143 (*machine)[i]->set_observer(NULL);
148 if(i>=machine->
size())
149 throw std::runtime_error(
"element index out of range");
150 if((*machine)[i]->observer())
151 throw std::runtime_error(
"element already observed");
152 observed.push_back(i);
153 (*machine)[i]->set_observer(o);
158 PyObject *PyMachine_propagate(PyObject *raw, PyObject *args, PyObject *kws)
162 PyObject *state, *toobserv = Py_None;
163 unsigned long start = 0, max = (
unsigned long)-1;
164 const char *pnames[] = {
"state",
"start",
"max",
"observe", NULL};
165 if(!PyArg_ParseTupleAndKeywords(args, kws,
"O|kkO", (
char**)pnames, &state, &start, &max, &toobserv))
168 PyStoreObserver observer;
169 PyScopedObserver observing(machine->machine);
171 if(toobserv!=Py_None) {
172 PyRef<> iter(PyObject_GetIter(toobserv)), item;
174 while(item.reset(PyIter_Next(iter.py()), PyRef<>::allow_null())) {
175 Py_ssize_t num = PyNumber_AsSsize_t(item.py(), PyExc_ValueError);
177 throw std::runtime_error(
"");
179 observing.observe(num, &observer);
184 machine->machine->
propagate(unwrapstate(state), start, max);
186 return observer.list.release();
190 } CATCH2(std::invalid_argument, ValueError)
195 PyObject *PyMachine_reconfigure(PyObject *raw, PyObject *args, PyObject *kws)
199 PyObject *conf, *replace = Py_False;
200 const char *pnames[] = {
"index",
"config",
"replace", NULL};
201 if(!PyArg_ParseTupleAndKeywords(args, kws,
"kO!|O", (
char**)pnames, &idx, &PyDict_Type, &conf, &replace))
204 if(idx>=machine->machine->
size())
205 return PyErr_Format(PyExc_ValueError,
"invalid element index %lu", idx);
208 if(!PyObject_IsTrue(replace))
209 newconf = (*machine->machine)[idx]->conf();
211 PyRef<> list(PyMapping_Items(conf));
212 List2Config(newconf, list.py(), 3);
217 } CATCH2(std::invalid_argument, ValueError)
222 PyObject *PyMachine_find(PyObject *raw, PyObject *args, PyObject *kws)
225 const char *ename = NULL, *etype = NULL;
226 const char *pnames[] = {
"name",
"type", NULL};
227 if(!PyArg_ParseTupleAndKeywords(args, kws,
"|zz", (
char**)pnames, &ename, &etype))
230 PyRef<> ret(PyList_New(0));
232 std::pair<Machine::lookup_iterator, Machine::lookup_iterator> range;
235 return PyErr_Format(PyExc_ValueError,
"only one of 'ename' or 'etype' may be given");
241 range = machine->machine->all_range();
244 for(; range.first!=range.second; ++range.first) {
247 PyRef<> pyidx(PyInt_FromLong(elem->
index));
249 if(PyList_Append(ret.py(), pyidx.py()))
253 return ret.release();
258 Py_ssize_t PyMachine_len(PyObject *raw)
261 return machine->machine->
size();
265 static PyMethodDef PyMachine_methods[] = {
266 {
"conf", (PyCFunction)&PyMachine_conf, METH_VARARGS|METH_KEYWORDS,
267 "conf() -> {} Machine config\n"
268 "conf(index) -> {} Element config"},
269 {
"allocState", (PyCFunction)&PyMachine_allocState, METH_VARARGS|METH_KEYWORDS,
270 "allocState() -> State\n"
271 "allocState({'variable':int|str}) -> State\n"
272 "Allocate a new State based on this Machine's configuration."
273 " Optionally provide additional configuration"},
274 {
"propagate", (PyCFunction)&PyMachine_propagate, METH_VARARGS|METH_KEYWORDS,
275 "propagate(State, start=0, max=-1, observe=None)\n"
276 "propagate(State, start=0, max=-1, observe=[1,4,...]) -> [(index,State), ...]\n"
277 "Propagate the provided State through the simulation.\n"
279 "start and max selects through which element the State will be passed.\n"
281 "observe may be None or an iterable yielding element indicies.\n"
282 "In the second form propagate() returns a list of tuples with the output State of the selected elements."
284 {
"reconfigure", (PyCFunction)&PyMachine_reconfigure, METH_VARARGS|METH_KEYWORDS,
285 "reconfigure(index, {'variable':int|str})\n"
286 "Change the configuration of an element."},
287 {
"find", (PyCFunction)&PyMachine_find, METH_VARARGS|METH_KEYWORDS,
288 "find(ename=None, etype=None) -> [int]\n"
289 "Return a list of element indices for element name or type matching the given string."},
290 {NULL, NULL, 0, NULL}
293 static PySequenceMethods PyMachine_seq = {
297 static PyTypeObject PyMachineType = {
298 #if PY_MAJOR_VERSION >= 3
299 PyVarObject_HEAD_INIT(NULL, 0)
301 PyObject_HEAD_INIT(NULL)
304 "flame._internal.Machine",
310 static const char pymdoc[] =
311 "Machine(config, path=None, extra=None)\n"
312 "Machine(config, path='/directry/', extra={'variable':float|str}})\n"
314 "A Machine() the primary interface to the FLAME simulation engine.\n"
316 "The 'config' argument may be a file-like object (with read())"
317 " or a buffer which will be parsed with the GLPS parser (see GLPSParser::parse).\n"
318 " Or it may be a dictionary.\n"
320 ">>> with open('some.lat', 'rb') as F:\n"
325 int registerModMachine(PyObject *mod)
327 PyMachineType.tp_doc = pymdoc;
328 PyMachineType.tp_str = &PyMachine_str;
330 PyMachineType.tp_new = &PyType_GenericNew;
331 PyMachineType.tp_init = &PyMachine_init;
332 PyMachineType.tp_dealloc = &PyMachine_free;
334 PyMachineType.tp_weaklistoffset = offsetof(PyMachine, weak);
336 PyMachineType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
337 PyMachineType.tp_methods = PyMachine_methods;
338 PyMachineType.tp_as_sequence = &PyMachine_seq;
340 if(PyType_Ready(&PyMachineType))
343 Py_INCREF((PyObject*)&PyMachineType);
344 if(PyModule_AddObject(mod,
"Machine", (PyObject*)&PyMachineType)) {
345 Py_DECREF((PyObject*)&PyMachineType);
void propagate(StateBase *S, size_t start=0, size_t max=-1) const
Pass the given bunch State through this Machine.
Base class for all simulated elements.
virtual void view(const ElementVoid *elem, const StateBase *state)=0
Called from within Machine::propagate()
The core simulate Machine engine.
virtual StateBase * clone() const =0
The abstract base class for all simulation state objects.
std::pair< lookup_iterator, lookup_iterator > equal_range_type(const std::string &name)
Associative configuration container.
Allow inspection of intermediate State.
void reconfigure(size_t idx, const Config &c)
Change the configuration of a single element.
const size_t index
Index of this element (unique in its Machine)
std::pair< lookup_iterator, lookup_iterator > equal_range(const std::string &name)