First usable IFS implementation
Implements borrowed if and other needed stuff + tests & benchamrk
This commit is contained in:
parent
48b8f3fbad
commit
7c335fcff0
13 changed files with 723 additions and 131 deletions
10
Makefile
10
Makefile
|
@ -9,7 +9,7 @@ ifeq ($(DEBUG), 1)
|
|||
#PYTHON=python3dm
|
||||
PYTHON=python3-dbg
|
||||
else
|
||||
CFLAGS=-fPIC -Wall -Werror
|
||||
CFLAGS=-fPIC -Wall -Werror -DNDEBUG
|
||||
LDFLAGS=-s
|
||||
NASMCFLAGS=-f elf64
|
||||
PYTHON=python3
|
||||
|
@ -75,8 +75,12 @@ doc/.doxygen.stamp: $(wildcard *.c) $(wildcard *.h) Doxyfile
|
|||
checks: runtest unittest
|
||||
|
||||
benchmark: $(LIB)
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py 0x500 0x2000; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py 0x500 0x4000;
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x2000 -s 0x50; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x2000 -s 0xa0; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x2000 -s 0x100; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x5000 -s 0x50; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x5000 -s 0xa0; \
|
||||
PYTHONPATH=`pwd` $(PYTHON) tests/benchmark.py -c 0x500 -i 0x5000 -s 0x100; \
|
||||
|
||||
|
||||
unittest: $(LIB_COV)
|
||||
|
|
32
benchplot.sh
Executable file
32
benchplot.sh
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
gpdat=/tmp/bench.dat
|
||||
|
||||
e=500
|
||||
|
||||
min_i=10000
|
||||
max_i=100000
|
||||
it_i=1
|
||||
|
||||
min_s=10
|
||||
max_s=10000
|
||||
it_s=30
|
||||
|
||||
if [ $it_i -eq 1 ]
|
||||
then
|
||||
inc_i=$max_i
|
||||
else
|
||||
inc_i=$(expr $(expr $max_i - $min_i) / $(expr $it_i - 1))
|
||||
fi
|
||||
inc_s=$(expr $(expr $max_s - $min_s) / $(expr $it_s - 1))
|
||||
|
||||
|
||||
for i in $(seq $min_i $inc_i $max_i)
|
||||
do
|
||||
for s in $(seq $min_s $inc_s $max_s)
|
||||
do
|
||||
echo "GO $e $i $s"
|
||||
PYTHONPATH=./ python3 tests/benchmark.py -c $e -i $i -s $s -G $gpdat
|
||||
done
|
||||
echo "" >> $gpdat
|
||||
done
|
290
python_if.c
290
python_if.c
|
@ -190,6 +190,8 @@ PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
|
|||
}
|
||||
expr = (PyRPNIterExpr_t*)ret;
|
||||
expr->rif = NULL;
|
||||
expr->rif_params = NULL;
|
||||
expr->borrowed_if = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -219,6 +221,7 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
|
||||
rpn_if_param_t *rif_params = _rpnif_get_params(pos_flag, res_flag,
|
||||
lim_obj, const_values_obj, stack_size);
|
||||
expr_self->rif_params = rif_params;
|
||||
|
||||
if(!rif_params)
|
||||
{
|
||||
|
@ -228,6 +231,11 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
expr_self->ndim = ((rpn_if_default_data_t*)(rif_params->data))->ndim;
|
||||
|
||||
const Py_ssize_t expt_sz = rif_params->mem_sz * rif_params->value_sz;
|
||||
if(mmap_obj == Py_None)
|
||||
{
|
||||
Py_DECREF(mmap_obj);
|
||||
mmap_obj = NULL;
|
||||
}
|
||||
if(!mmap_obj)
|
||||
{
|
||||
PyObject *fileno = PyLong_FromLong(-1);
|
||||
|
@ -282,6 +290,102 @@ of mmap.mmap");
|
|||
return _rpnif_init_expr_tuple(expr_self);
|
||||
}
|
||||
|
||||
|
||||
PyObject* rpnif_init_borrowed(rpn_if_t *borrowed_if, PyObject *mmap_obj)
|
||||
{
|
||||
PyObject *sz_lim, *const_val;
|
||||
PyObject *args, *ret;
|
||||
|
||||
|
||||
rpn_if_default_data_t *params;
|
||||
params = (rpn_if_default_data_t*)(borrowed_if->params->data);
|
||||
|
||||
const size_t nsz = params->ndim + (params->pos_flag == RPN_IF_POSITION_XDIM?1:0);
|
||||
sz_lim = PyTuple_New(nsz);
|
||||
for(size_t i=0; i<nsz; i++)
|
||||
{
|
||||
PyObject *v = PyLong_FromLong(params->size_lim[i]);
|
||||
PyTuple_SET_ITEM(sz_lim, i, v);
|
||||
}
|
||||
|
||||
const size_t const_val_sz = params->res_flag == RPN_IF_RES_CONST ? 1 : \
|
||||
(params->res_flag == RPN_IF_RES_CONST_RGBA ? 4 : 0);
|
||||
|
||||
if(const_val_sz)
|
||||
{
|
||||
const_val = PyTuple_New(const_val_sz);
|
||||
for(size_t i=0; i<const_val_sz; i++)
|
||||
{
|
||||
PyObject *v = PyLong_FromLong(params->const_val[i]);
|
||||
PyTuple_SET_ITEM(const_val, i, v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_val = Py_None;
|
||||
Py_INCREF(const_val);
|
||||
}
|
||||
|
||||
// no mmap :/
|
||||
// It seems there is no elegant solutions for the moment
|
||||
// if we give None a new mmap is created
|
||||
// if we give a dummy mmap it has to have the expected size...
|
||||
// using None for the moment...
|
||||
/**@todo find a solution */
|
||||
PyObject *mmap_arg = Py_None;
|
||||
if(mmap_obj)
|
||||
{
|
||||
mmap_arg = mmap_obj;
|
||||
}
|
||||
|
||||
args = Py_BuildValue("hhOOBO", params->pos_flag, params->res_flag,
|
||||
sz_lim, const_val,
|
||||
borrowed_if->params->rpn_stack_sz,
|
||||
mmap_arg);
|
||||
Py_DECREF(sz_lim);
|
||||
Py_DECREF(const_val);
|
||||
if(!args || PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = PyObject_CallObject((PyObject*)&RPNIterExprType, args);
|
||||
Py_DECREF(args);
|
||||
if(!ret || PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyRPNIterExpr_t* instance = (PyRPNIterExpr_t*)ret;
|
||||
|
||||
// changing if instance
|
||||
rpn_if_free(instance->rif);
|
||||
instance->rif = borrowed_if;
|
||||
// reseting expr tuple
|
||||
Py_DECREF(instance->expr);
|
||||
instance->expr = NULL;
|
||||
|
||||
// mmap update
|
||||
PyBuffer_Release(&instance->mm_buff);
|
||||
if(!mmap_obj)
|
||||
{
|
||||
Py_DECREF(instance->mmap);
|
||||
instance->mmap = NULL;
|
||||
instance->mm_buff.buf = NULL;
|
||||
instance->_mmap = borrowed_if->mem;
|
||||
}
|
||||
instance->borrowed_if = 1;
|
||||
// someone else will take care to free the rif params
|
||||
if(instance->rif_params) { free(instance->rif_params); }
|
||||
instance->rif_params = NULL;
|
||||
|
||||
if(_rpnif_init_expr_tuple(instance) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**@brief Returns the parameters in a named tuple */
|
||||
PyObject *rpnif_get_params(PyObject *self)
|
||||
{
|
||||
|
@ -414,47 +518,7 @@ PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
|
|||
{
|
||||
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
|
||||
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
|
||||
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
|
||||
long long value;
|
||||
|
||||
if((size_t)argc != rif_data->ndim)
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"Expression expect %lu dimentions coordinates,"
|
||||
" but %ld arguments given.",
|
||||
rif_data->ndim, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpn_value_t result=0;
|
||||
size_t cur_dim_sz = 1;
|
||||
|
||||
for(size_t i=0; i<rif_data->ndim; i++)
|
||||
{
|
||||
if(!PyLong_Check(argv[i]))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"coordinates must be integers");
|
||||
return NULL;
|
||||
}
|
||||
value = PyLong_AsLongLong(argv[i]);
|
||||
if(value < 0)
|
||||
{
|
||||
value = (-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
|
||||
}
|
||||
if((size_t)value >= rif_data->size_lim[i+idx_off])
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"Coordinate %ld overflows : %R/%lu",
|
||||
i, argv[i],
|
||||
rif_data->size_lim[i+idx_off]);
|
||||
return NULL;
|
||||
}
|
||||
result += value * cur_dim_sz;
|
||||
cur_dim_sz *= rif_data->size_lim[i+idx_off];
|
||||
}
|
||||
|
||||
return PyLong_FromUnsignedLongLong(result);
|
||||
return _rpnif_to_pos(rif_data, argv, argc);
|
||||
}
|
||||
|
||||
|
||||
|
@ -462,48 +526,8 @@ PyObject *rpnif_from_pos(PyObject *self, PyObject* _pos)
|
|||
{
|
||||
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
|
||||
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
|
||||
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
|
||||
|
||||
if(!PyLong_Check(_pos))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Expected position to be an integer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t pos = PyLong_AsUnsignedLong(_pos);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *res = PyTuple_New(rif_data->ndim);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(size_t i=0; i<rif_data->ndim; i++)
|
||||
{
|
||||
size_t val;
|
||||
size_t lim = rif_data->size_lim[i+idx_off];
|
||||
|
||||
val = pos % lim;
|
||||
pos /= lim;
|
||||
|
||||
PyObject *elt = PyLong_FromUnsignedLong(val);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
PyTuple_SET_ITEM(res, i, elt);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
err:
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
return _rpnif_from_pos(rif_data, _pos);
|
||||
}
|
||||
|
||||
|
||||
|
@ -637,7 +661,7 @@ err_loop_newtuple:
|
|||
void rpnif_del(PyObject *self)
|
||||
{
|
||||
PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
|
||||
if(expr_self->rif)
|
||||
if((!expr_self->borrowed_if) && expr_self->rif)
|
||||
{
|
||||
rpn_if_free(expr_self->rif);
|
||||
expr_self->rif = NULL;
|
||||
|
@ -657,6 +681,7 @@ void rpnif_del(PyObject *self)
|
|||
Py_DECREF(expr_self->expr);
|
||||
expr_self->expr = NULL;
|
||||
}
|
||||
if(expr_self->rif_params) { free(expr_self->rif_params); }
|
||||
}
|
||||
|
||||
|
||||
|
@ -836,7 +861,7 @@ PyObject* rpnif_subscript(PyObject *self, PyObject *key)
|
|||
if(idx < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"No expression '%s' with given parameters",
|
||||
"No expression '%R' with given parameters",
|
||||
key);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -851,7 +876,7 @@ int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt)
|
|||
if(idx < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"Cannot set expression '%U' that do not exists with this parameters",
|
||||
"Cannot set expression '%R' that do not exists with this parameters",
|
||||
key);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1319,11 +1344,13 @@ PyObject* rpnif_setstate(PyObject *self, PyObject *state_bytes)
|
|||
"Unable to initialize rif expression");
|
||||
return NULL;
|
||||
}
|
||||
expr_self->rif_params = params;
|
||||
expr_self->ndim = ser_data->ndim;
|
||||
if(_rpnif_init_expr_tuple(expr_self) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
expr_self->borrowed_if = 0; // explicitly not borrowed
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -1556,6 +1583,99 @@ PyObject *_rpnif_params_to_tuple(const rpn_if_param_t *_params)
|
|||
}
|
||||
|
||||
|
||||
PyObject *_rpnif_to_pos(rpn_if_default_data_t *rif_data, PyObject** argv, Py_ssize_t argc)
|
||||
{
|
||||
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
|
||||
long long value;
|
||||
|
||||
if((size_t)argc != rif_data->ndim)
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"Expression expect %lu dimentions coordinates,"
|
||||
" but %ld arguments given.",
|
||||
rif_data->ndim, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpn_value_t result=0;
|
||||
size_t cur_dim_sz = 1;
|
||||
|
||||
for(size_t i=0; i<rif_data->ndim; i++)
|
||||
{
|
||||
if(!PyLong_Check(argv[i]))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"coordinates must be integers");
|
||||
return NULL;
|
||||
}
|
||||
value = PyLong_AsLongLong(argv[i]);
|
||||
if(value < 0)
|
||||
{
|
||||
value = (-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
|
||||
}
|
||||
if((size_t)value >= rif_data->size_lim[i+idx_off])
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"Coordinate %ld overflows : %R/%lu",
|
||||
i, argv[i],
|
||||
rif_data->size_lim[i+idx_off]);
|
||||
return NULL;
|
||||
}
|
||||
result += value * cur_dim_sz;
|
||||
cur_dim_sz *= rif_data->size_lim[i+idx_off];
|
||||
}
|
||||
|
||||
return PyLong_FromUnsignedLongLong(result);
|
||||
}
|
||||
|
||||
|
||||
PyObject *_rpnif_from_pos(rpn_if_default_data_t *rif_data, PyObject* _pos)
|
||||
{
|
||||
const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
|
||||
|
||||
if(!PyLong_Check(_pos))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Expected position to be an integer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t pos = PyLong_AsUnsignedLong(_pos);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *res = PyTuple_New(rif_data->ndim);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(size_t i=0; i<rif_data->ndim; i++)
|
||||
{
|
||||
size_t val;
|
||||
size_t lim = rif_data->size_lim[i+idx_off];
|
||||
|
||||
val = pos % lim;
|
||||
pos /= lim;
|
||||
|
||||
PyObject *elt = PyLong_FromUnsignedLong(val);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
PyTuple_SET_ITEM(res, i, elt);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
err:
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int _rpnif_init_expr_tuple(PyRPNIterExpr_t *expr_self)
|
||||
{
|
||||
expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz);
|
||||
|
|
21
python_if.h
21
python_if.h
|
@ -101,6 +101,13 @@ typedef struct
|
|||
/**@brief Memory map buffer pointer */
|
||||
void *_mmap;
|
||||
|
||||
/**@brief Pointer on params to free at del */
|
||||
rpn_if_param_t *rif_params;
|
||||
|
||||
/**@brief If true, someone else (an ifs ?) will take care of freeing
|
||||
* the if at deletion */
|
||||
short borrowed_if;
|
||||
|
||||
} PyRPNIterExpr_t;
|
||||
|
||||
/**@brief RPNIterExpr.params static method
|
||||
|
@ -128,6 +135,13 @@ PyObject* rpnif_new(PyTypeObject *subtype, PyObject* args, PyObject* kwds);
|
|||
*/
|
||||
int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds);
|
||||
|
||||
/**@brief RPNIterExpr constructor with a borrowed expression
|
||||
* @param borrowed_if Pointer on borrowed instance
|
||||
* @param mmap Pointer on borrowed python mmap object (NULL if deserialized instance)
|
||||
* @return 0 if no error else -1
|
||||
*/
|
||||
PyObject* rpnif_init_borrowed(rpn_if_t *borrowed_if, PyObject *mmap);
|
||||
|
||||
/**@brief RPNIterExpr __del__ method
|
||||
* @param self RPNExpr instance
|
||||
* @ingroup pymod_pyrpn_RPNExprIter
|
||||
|
@ -311,6 +325,13 @@ rpn_if_param_t *_rpnif_get_params(unsigned short pos_flag, unsigned short res_fl
|
|||
*/
|
||||
PyObject *_rpnif_params_to_tuple(const rpn_if_param_t *params);
|
||||
|
||||
|
||||
/**@brief Implementation of both RPNIterExpr.to_pos and RPNIFS.to_pos */
|
||||
PyObject *_rpnif_to_pos(rpn_if_default_data_t *rif_data, PyObject** argv, Py_ssize_t argc);
|
||||
|
||||
/**@brief Implementation of bot RPNIterExpr.to_pos and RPNIFS.from_pos */
|
||||
PyObject *_rpnif_from_pos(rpn_if_default_data_t *rif_data, PyObject* _pos);
|
||||
|
||||
int _rpnif_init_expr_tuple(PyRPNIterExpr_t *expr_self);
|
||||
|
||||
#endif
|
||||
|
|
166
python_ifs.c
166
python_ifs.c
|
@ -31,11 +31,28 @@ in the system."),
|
|||
METH_FASTCALL,
|
||||
"self, idx, weight=None",
|
||||
"Get or set a single weight"),
|
||||
PYRPN_method("position", rpnifs_position,
|
||||
METH_FASTCALL,
|
||||
"self, position=None",
|
||||
"Get or set the current position"),
|
||||
PYRPN_method("run", rpnifs_run,
|
||||
METH_FASTCALL,
|
||||
"self, steps, rand_bytes=None, /",
|
||||
"Run ifs steps times"),
|
||||
PYRPN_method("to_pos", rpnifs_to_pos,
|
||||
METH_FASTCALL,
|
||||
"self, *args, /",
|
||||
"Return a position (int) from a coordinates given as"
|
||||
"argument."),
|
||||
PYRPN_method("from_pos", rpnifs_from_pos,
|
||||
METH_O,
|
||||
"self, position, /",
|
||||
"Return a coordinates tuple from given position."),
|
||||
{NULL} // Sentinel
|
||||
};
|
||||
|
||||
static PyMemberDef RPNIFS_members[] = {
|
||||
{"expressions", T_OBJECT, offsetof(PyRPNIFS_t, rifs), READONLY,
|
||||
{"expressions", T_OBJECT, offsetof(PyRPNIFS_t, rpn_if), READONLY,
|
||||
"The tuple with RPNIterExpr instances"},
|
||||
{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
|
||||
"The mmap storing data"},
|
||||
|
@ -172,7 +189,12 @@ length %ld provided",
|
|||
"Error initializing ifs: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ifs_self->rpn_if = NULL;
|
||||
if(_rpnifs_update_if_tuple(ifs_self) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -182,6 +204,7 @@ void rpnifs_del(PyObject *self)
|
|||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
|
||||
rpn_ifs_free(ifs_self->ifs);
|
||||
free(ifs_self->ifs);
|
||||
if(ifs_self->mmap)
|
||||
{
|
||||
if(ifs_self->mm_buff.buf)
|
||||
|
@ -195,6 +218,23 @@ void rpnifs_del(PyObject *self)
|
|||
}
|
||||
|
||||
|
||||
PyObject *rpnifs_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)ifs_self->ifs->params.data;
|
||||
return _rpnif_to_pos(rif_data, argv, argc);
|
||||
}
|
||||
|
||||
|
||||
PyObject *rpnifs_from_pos(PyObject *self, PyObject* _pos)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)ifs_self->ifs->params.data;
|
||||
return _rpnif_from_pos(rif_data, _pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
|
@ -264,6 +304,11 @@ PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs
|
|||
if(PyErr_Occurred()) { return NULL; }
|
||||
PyTuple_SET_ITEM(ret, i, item);
|
||||
}
|
||||
|
||||
if(_rpnifs_update_if_tuple(ifs_self) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
|
||||
err_weights:
|
||||
|
@ -280,6 +325,85 @@ PyObject *rpnifs_weight(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
|||
}
|
||||
|
||||
|
||||
PyObject *rpnifs_position(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
|
||||
if(nargs == 1 && args[0] != Py_None)
|
||||
{
|
||||
size_t pos = PyLong_AsSize_t(args[0]);
|
||||
if(PyErr_Occurred()) { return NULL; }
|
||||
if(pos > ifs_self->ifs->params.mem_sz)
|
||||
{
|
||||
pos %= ifs_self->ifs->params.mem_sz;
|
||||
#ifndef NDEBUG
|
||||
PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
|
||||
"Given position %R overflows and stored as %lu",
|
||||
args[0], pos);
|
||||
#endif
|
||||
}
|
||||
ifs_self->ifs->pos = pos;
|
||||
}
|
||||
|
||||
return PyLong_FromSize_t(ifs_self->ifs->pos);
|
||||
}
|
||||
|
||||
PyObject *rpnifs_run(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
if(nargs == 0 || nargs > 2)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Expected 1 or 2 arguments but %ld given",
|
||||
nargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t steps = PyLong_AsSize_t(args[0]);
|
||||
if(PyErr_Occurred())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if(steps == 0)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Steps arguments must be > 0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char *rnd_buf = NULL;
|
||||
if(nargs == 2)
|
||||
{
|
||||
// Python bytes given as random source
|
||||
const Py_ssize_t sz = PyBytes_Size(args[1]);
|
||||
if(PyErr_Occurred()) { goto err; }
|
||||
if((size_t)sz != sizeof(char)*steps)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Given random bytes are too small."
|
||||
"Expected %ld bytes but got %ld",
|
||||
sizeof(char)*steps,
|
||||
sz);
|
||||
goto err;
|
||||
}
|
||||
rnd_buf = (unsigned char*)PyBytes_AsString(args[1]);
|
||||
}
|
||||
|
||||
const int ret = rpn_ifs_run(ifs_self->ifs, steps, rnd_buf);
|
||||
if(ret < 0)
|
||||
{
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"Unable to run IFS : %s",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *rpnifs_str(PyObject *self)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
|
@ -303,8 +427,23 @@ Py_ssize_t rpnifs_len(PyObject *self)
|
|||
|
||||
PyObject *rpnifs_expr_item(PyObject *self, Py_ssize_t idx)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
return NULL;
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
Py_ssize_t _idx = idx;
|
||||
|
||||
if(idx < 0)
|
||||
{
|
||||
_idx = ifs_self->ifs->if_sz - 1 + idx;
|
||||
}
|
||||
if(_idx < 0 || (size_t) _idx >= ifs_self->ifs->params.rpn_sz)
|
||||
{
|
||||
PyErr_Format(PyExc_IndexError,
|
||||
"There is %ld expressions in the system but index %ld asked",
|
||||
ifs_self->ifs->params.rpn_sz, idx);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *ret = PyTuple_GET_ITEM(ifs_self->rpn_if, _idx);
|
||||
Py_INCREF(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,4 +465,23 @@ void rpnifs_releasebuffer(PyObject *self, Py_buffer *view)
|
|||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
}
|
||||
|
||||
int _rpnifs_update_if_tuple(PyRPNIFS_t *ifs_self)
|
||||
{
|
||||
if(ifs_self->rpn_if)
|
||||
{
|
||||
Py_DECREF(ifs_self->rpn_if);
|
||||
}
|
||||
ifs_self->rpn_if = PyTuple_New(ifs_self->ifs->if_sz);
|
||||
for(size_t i=0; i<ifs_self->ifs->if_sz; i++)
|
||||
{
|
||||
PyObject *py_if = rpnif_init_borrowed(ifs_self->ifs->rpn_if[i],
|
||||
ifs_self->mmap);
|
||||
if((!py_if) || PyErr_Occurred())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
PyTuple_SET_ITEM(ifs_self->rpn_if, i, py_if);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef struct
|
|||
/** @brief Pointer on IF expressions in the system */
|
||||
rpn_if_t **rifs;
|
||||
|
||||
|
||||
/**@brief Python mmap.mmap instance representing rif memory map
|
||||
* @note NULL if unpickled instance */
|
||||
PyObject *mmap;
|
||||
|
@ -80,8 +81,14 @@ PyObject *rpnifs_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
|
|||
int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds);
|
||||
void rpnifs_del(PyObject *self);
|
||||
|
||||
|
||||
PyObject *rpnifs_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc);
|
||||
PyObject *rpnifs_from_pos(PyObject *self, PyObject* _pos);
|
||||
|
||||
PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
PyObject *rpnifs_weight(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
PyObject *rpnifs_position(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
PyObject *rpnifs_run(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
|
||||
|
||||
PyObject *rpnifs_str(PyObject *self);
|
||||
PyObject *rpnifs_repr(PyObject *self);
|
||||
|
@ -93,5 +100,7 @@ int rpnifs_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject *value);
|
|||
int rpnifs_getbuffer(PyObject *self, Py_buffer *view, int flags);
|
||||
void rpnifs_releasebuffer(PyObject *self, Py_buffer *view);
|
||||
|
||||
int _rpnifs_update_if_tuple(PyRPNIFS_t *ifs_self);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
5
rpn_if.c
5
rpn_if.c
|
@ -176,6 +176,11 @@ void rpn_if_free(rpn_if_t* rif)
|
|||
size_t rpn_if_step(rpn_if_t *rif, size_t pos)
|
||||
{
|
||||
size_t newpos;
|
||||
|
||||
assert(rif != NULL);
|
||||
assert(rif->params != NULL);
|
||||
assert(rif->params->getarg_f != NULL);
|
||||
|
||||
rif->params->getarg_f(rif, pos);
|
||||
for(size_t i=0; i<rif->params->rpn_sz; i++)
|
||||
{
|
||||
|
|
2
rpn_if.h
2
rpn_if.h
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "rpn_jit.h"
|
||||
|
||||
/**@file rpn_if.h
|
||||
|
|
12
rpn_ifs.c
12
rpn_ifs.c
|
@ -209,6 +209,9 @@ int rpn_ifs_run(rpn_ifs_t *rifs, size_t n, unsigned char *rnd)
|
|||
}
|
||||
if(getrandom(_rnd, n, GRND_NONBLOCK) < 0)
|
||||
{
|
||||
int err = errno;
|
||||
free(_rnd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +223,7 @@ int rpn_ifs_run(rpn_ifs_t *rifs, size_t n, unsigned char *rnd)
|
|||
for(size_t i=0; i<n; i++)
|
||||
{
|
||||
rpn_if_t *cur_if = rifs->if_proba[_rnd[i]];
|
||||
assert(cur_if != NULL);
|
||||
rifs->pos = rpn_if_step(cur_if, rifs->pos);
|
||||
}
|
||||
return 0;
|
||||
|
@ -251,9 +255,13 @@ int rpn_ifs_weight_update(rpn_ifs_t *rifs)
|
|||
j++;
|
||||
}
|
||||
}
|
||||
if(j==255)
|
||||
for(j=j; j<256; j++)
|
||||
{
|
||||
rifs->if_proba[255] = rifs->if_proba[254];
|
||||
// dirty & quick fill with last value
|
||||
/* @todo enhance the random choice resolution to match
|
||||
* more closely asked weights (uint16 vs actualt uint8 random
|
||||
* choice ? */
|
||||
rifs->if_proba[j] = rifs->if_proba[j-1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rpn_jit.h"
|
||||
|
@ -126,7 +127,7 @@ int rpn_ifs_del_if(rpn_ifs_t *rifs, size_t if_idx);
|
|||
* @param rifs The iterated function system
|
||||
* @param n consecutive IFS calls
|
||||
* @param seed prepopulated array of random bytes (if NULL one is generated)
|
||||
* @return 1 if error else 0
|
||||
* @return -1 if error else 0
|
||||
*/
|
||||
int rpn_ifs_run(rpn_ifs_t *rifs, size_t n, unsigned char *rnd);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import time
|
||||
|
@ -16,31 +18,24 @@ except (ImportError, NameError) as e:
|
|||
file=sys.stderr)
|
||||
raise e
|
||||
|
||||
if len(sys.argv) > 5:
|
||||
usage()
|
||||
exit(1)
|
||||
allint = lambda val: int(val, 0)
|
||||
|
||||
#expr_count = 0x200
|
||||
#max_iter = 0x3000
|
||||
#argc = 2
|
||||
#sz = 0x20
|
||||
expr_count = 0x200
|
||||
max_iter = 0x5000
|
||||
#argc = 2
|
||||
#sz = 0x30
|
||||
argc = 5
|
||||
sz = 0x50
|
||||
parser = argparse.ArgumentParser(description="Benchmark RPNExpr vs IFS")
|
||||
parser.add_argument("-c", "--expr-count", type=allint, default=0x200)
|
||||
parser.add_argument("-i", "--iterations", type=allint, default=0x5000)
|
||||
parser.add_argument("-s", "--expr-size", type=allint, default=0x50)
|
||||
parser.add_argument("-G", "--gnuplot-output", type=str, default=None)
|
||||
|
||||
try:
|
||||
expr_count = int(sys.argv[1], base=0)
|
||||
max_iter = int(sys.argv[2], base=0)
|
||||
argc = int(sys.argv[3], base=0)
|
||||
sz = int(sys.argv[4], base=0)
|
||||
except IndexError:
|
||||
pass
|
||||
except Exception:
|
||||
usage()
|
||||
exit(2)
|
||||
args = parser.parse_args()
|
||||
expr_count = args.expr_count
|
||||
max_iter = args.iterations
|
||||
sz = args.expr_size
|
||||
|
||||
argc = 1
|
||||
|
||||
gpout=None
|
||||
if args.gnuplot_output is not None:
|
||||
gpout = open(args.gnuplot_output, "a")
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
|
@ -53,14 +48,6 @@ except (ImportError, NameError) as e:
|
|||
tqr = range
|
||||
write=True
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
expr_count = int(sys.argv[1], 0)
|
||||
if len(sys.argv) > 2:
|
||||
max_iter = int(sys.argv[2], 0)
|
||||
if len(sys.argv) > 3:
|
||||
sz = int(sys.argv[4], 0)
|
||||
if len(sys.argv) > 4:
|
||||
argc = int(sys.argv[3], 0)
|
||||
|
||||
tot = 0
|
||||
time_op = 0
|
||||
|
@ -68,12 +55,15 @@ start = time.time()
|
|||
IMAX = (1<<63)-1
|
||||
samples = 8
|
||||
|
||||
print("========\nIF :", end=" ")
|
||||
print("Running %dK iter on %d expressions with %d op and %d args" % (max_iter//1000,
|
||||
expr_count,
|
||||
sz, argc))
|
||||
|
||||
res = [0 for _ in range(512)]
|
||||
rnd_samples = [[[random.randint(0, IMAX) for _ in range(argc)] for _ in range(max_iter)]
|
||||
for _ in range(samples)]
|
||||
|
||||
for i in tqr(expr_count):
|
||||
rnd_expr = pyrpn.random_expr(argc, sz)
|
||||
all_start = time.time()
|
||||
|
@ -82,7 +72,10 @@ for i in tqr(expr_count):
|
|||
start_op = time.time()
|
||||
rnds = random.choice(rnd_samples)
|
||||
for rnd in rnds:
|
||||
expr.eval(*rnd)
|
||||
r = expr.eval(*rnd)
|
||||
# emulate memory access for simple if to make comparison
|
||||
# consistant with IFS
|
||||
res[r%512] += 1
|
||||
time_op += time.time() - start_op
|
||||
tot += time.time() - all_start
|
||||
if write:
|
||||
|
@ -91,8 +84,7 @@ for i in tqr(expr_count):
|
|||
if write:
|
||||
sys.stderr.write("\n")
|
||||
total = time.time() - start
|
||||
print("Runned %dK iter on %d expressions in %.2fs" % (max_iter//1000,
|
||||
expr_count, total))
|
||||
|
||||
ops = max_iter*expr_count*sz/time_op/(1000*1000)
|
||||
msg = "%5.1fM op/s %6.1fK iter/s %.1fms per expr (%dK iter, %d op per expr)"
|
||||
msg %= (ops,
|
||||
|
@ -100,3 +92,51 @@ msg %= (ops,
|
|||
tot/expr_count*1000,
|
||||
max_iter//1000, sz)
|
||||
print(msg)
|
||||
print("++++++++")
|
||||
if_ops = ops
|
||||
|
||||
|
||||
if_sz = 5
|
||||
ifs_count = expr_count // if_sz
|
||||
ifs_sz = 3
|
||||
mem_sz = (512,512)
|
||||
expr_count = ifs_count * if_sz
|
||||
|
||||
print("IFS :", end=" ")
|
||||
print("Running %dK iter on %d ifs (sz=%d with %d if choosen randomly and %d op) RGB of size %r" % \
|
||||
(max_iter/1000, ifs_count , if_sz, ifs_sz, sz, mem_sz))
|
||||
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB, mem_sz)
|
||||
runtime = 0
|
||||
all_start = time.time()
|
||||
for i in tqr(ifs_count):
|
||||
weights = [random.randint(1,50) for _ in range(ifs_sz)]
|
||||
ifs.weights(weights)
|
||||
for i in range(ifs_sz):
|
||||
for expr_id in 'RGBXY':
|
||||
ifs[i][expr_id] = pyrpn.random_expr(if_sz, sz)
|
||||
|
||||
rnd = os.getrandom(max_iter)
|
||||
start = time.time()
|
||||
ifs.run(max_iter, rnd)
|
||||
runtime += time.time() - start
|
||||
if write:
|
||||
sys.stderr.write(".")
|
||||
sys.stderr.flush()
|
||||
if write:
|
||||
sys.stderr.write("\n")
|
||||
|
||||
total = time.time() - all_start
|
||||
ops = max_iter*ifs_count*if_sz*sz/(runtime*1000*1000)
|
||||
msg = "%5.1fM op/s %6.1fK expr_iter/s %.2fms per ifs"
|
||||
msg %= (ops,
|
||||
max_iter*ifs_count*if_sz/runtime/1000,
|
||||
total/ifs_count)
|
||||
ifs_ops = ops
|
||||
print(msg)
|
||||
print("========")
|
||||
|
||||
if gpout:
|
||||
line = "%d %d %f %f\n" % (max_iter, sz, if_ops, ifs_ops)
|
||||
gpout.write(line)
|
||||
gpout.close()
|
||||
|
|
|
@ -262,8 +262,8 @@ int test_rpn_if_default()
|
|||
return -1;
|
||||
}
|
||||
|
||||
free(rif_param);
|
||||
rpn_if_free(rif);
|
||||
free(rif_param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -289,8 +289,8 @@ int test_rpn_if_default2()
|
|||
return -1;
|
||||
}
|
||||
|
||||
free(rif_param);
|
||||
rpn_if_free(rif);
|
||||
free(rif_param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import sys
|
|||
|
||||
import unittest
|
||||
|
||||
|
||||
try:
|
||||
import pyrpn
|
||||
except (ImportError, NameError) as e:
|
||||
|
@ -63,3 +64,194 @@ class TestRPNIFS(unittest.TestCase):
|
|||
nw = ifs.weights()
|
||||
self.assertEqual(tuple(w), nw)
|
||||
|
||||
def test_position(self):
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_COUNT,
|
||||
(640,480))
|
||||
self.assertEqual(len(ifs), 0)
|
||||
self.assertEqual(ifs.position(), 0)
|
||||
self.assertEqual(ifs.position(10), 10)
|
||||
self.assertEqual(ifs.position(), 10)
|
||||
for i in range(640*480):
|
||||
ifs.position(i)
|
||||
self.assertEqual(ifs.position(), i)
|
||||
|
||||
|
||||
def test_run(self):
|
||||
""" Testing ifs run """
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_COUNT,
|
||||
(256,256))
|
||||
ifs.weights([1])
|
||||
ifs[0]['X'] = 'A0 13 +'
|
||||
ifs[0]['Y'] = 'A1 2 +'
|
||||
xpos = lambda steps: (steps*13)%256
|
||||
ypos = lambda steps: (steps*2)%256
|
||||
ifs.run(1)
|
||||
self.assertEqual(ifs.position(), ifs.to_pos(xpos(1),ypos(1)))
|
||||
steps = 1
|
||||
for _ in range(128):
|
||||
rnd = random.randint(1,128)
|
||||
steps += rnd
|
||||
ifs.run(rnd)
|
||||
self.assertEqual(ifs.position(),
|
||||
ifs.to_pos(xpos(steps), ypos(steps)))
|
||||
|
||||
|
||||
def test_run_rnd(self):
|
||||
""" Testing ifs run with random if choice, same weights """
|
||||
sz = [10000,10000]
|
||||
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_COUNT,
|
||||
sz)
|
||||
ifs.weights([1,1])
|
||||
ifs[0]['X'] = 'A0 1 +'
|
||||
ifs[0]['Y'] = 'A1 1 -'
|
||||
ifs[1]['X'] = 'A0 1 -'
|
||||
ifs[1]['Y'] = 'A0 1 +'
|
||||
for _ in Progress(256):
|
||||
ifs.position(ifs.to_pos(*[s//2 for s in sz]))
|
||||
|
||||
steps = 0
|
||||
steps_per_loop = 0x1000
|
||||
for _ in range(4):
|
||||
steps += steps_per_loop
|
||||
ifs.run(steps_per_loop)
|
||||
coord = ifs.from_pos(ifs.position())
|
||||
|
||||
distance = [min(c, sz[i]-c) for i, c in enumerate(coord)]
|
||||
dist = sum(distance)/2
|
||||
percent = steps / (dist * 100)
|
||||
self.assertLess(percent, 1)
|
||||
|
||||
class TestRPNIFSCoordinates(unittest.TestCase):
|
||||
""" Testing methods for coordinates <-> position convertions """
|
||||
|
||||
def test_position_linear(self):
|
||||
""" Testing linear coordinate convertion methods """
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_LINEAR,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
(256,), (42,))
|
||||
|
||||
for pos in range(256):
|
||||
with self.subTest(rif=rif, position=pos, expt=(pos,)):
|
||||
res = rif.from_pos(pos)
|
||||
self.assertEqual(res, (pos,))
|
||||
with self.subTest(rif=rif, expt=pos, coord=(pos,)):
|
||||
res = rif.to_pos(pos)
|
||||
self.assertEqual(res, pos)
|
||||
|
||||
def test_position_xy(self):
|
||||
""" Testing XY coordinate convertion methods """
|
||||
for _ in Progress(5):
|
||||
sz = (random.randint(32,128), random.randint(32,128))
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
sz, (42,))
|
||||
for pos in range(sz[0]*sz[1]):
|
||||
coord = rif.from_pos(pos)
|
||||
expt = (pos % sz[0], pos // sz[0])
|
||||
with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
|
||||
self.assertEqual(expt, coord)
|
||||
result = rif.to_pos(*coord)
|
||||
with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
|
||||
self.assertEqual(result, pos)
|
||||
|
||||
def test_position_xy_neg(self):
|
||||
""" Testing XY coordinates with negative values """
|
||||
sz = (100,200)
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
sz, (42,))
|
||||
|
||||
for _ in range(1000):
|
||||
ny = random.randint(-0x1000000, sz[1])
|
||||
nx = random.randint(0,sz[0]-1)
|
||||
pos = rif.to_pos(nx, ny)
|
||||
coord = rif.from_pos(pos)
|
||||
self.assertEqual(coord, (nx, (ny%(1<<64))%sz[1]))
|
||||
|
||||
def test_position_xy_random(self):
|
||||
""" Testing XY coordinate convertion methods (random samples)"""
|
||||
for _ in Progress(256):
|
||||
sz = (random.randint(32,4096), random.randint(32,4096))
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
sz, (42,))
|
||||
for _ in range(500):
|
||||
pos = random.randint(0, (sz[0]*sz[1])-1)
|
||||
coord = rif.from_pos(pos)
|
||||
expt = (pos % sz[0], pos // sz[0])
|
||||
with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
|
||||
self.assertEqual(expt, coord)
|
||||
result = rif.to_pos(*coord)
|
||||
with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
|
||||
self.assertEqual(result, pos)
|
||||
|
||||
def test_position_xdim(self):
|
||||
""" Testing XDIM coordinate convertion methods """
|
||||
ndim = 5
|
||||
resol = [8 for _ in range(ndim)]
|
||||
sz = [ndim]+resol
|
||||
linear_size = 1
|
||||
for e in resol:
|
||||
linear_size *= e
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XDIM,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
sz, (42,))
|
||||
for pos in range(linear_size):
|
||||
coord = rif.from_pos(pos)
|
||||
expt = []
|
||||
cur = pos
|
||||
for dim in resol:
|
||||
elt = cur % dim
|
||||
cur //= dim
|
||||
expt.append(elt)
|
||||
expt = tuple(expt)
|
||||
with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
|
||||
self.assertEqual(expt, coord)
|
||||
result = rif.to_pos(*coord)
|
||||
with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
|
||||
self.assertEqual(result, pos)
|
||||
|
||||
def test_position_xdim_neg(self):
|
||||
""" Testing XDIM negative position convertion """
|
||||
# TODO test negativ for other coordinate systems
|
||||
ndim = 4
|
||||
szlim = (ndim, 10,20,30,40)
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XDIM,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
szlim, (42,))
|
||||
|
||||
pos = rif.to_pos(0,0,-5,0)
|
||||
self.assertEqual(rif.from_pos(pos), (0,0,(-5%(1<<64))%30, 0))
|
||||
|
||||
def test_position_xdim(self):
|
||||
""" Testing XDIM coordinate convertion methods (random sampling)"""
|
||||
for _ in Progress(16):
|
||||
ndim = random.randint(3,8)
|
||||
resol = [random.randint(2, 16) for _ in range(ndim)]
|
||||
sz = [ndim]+resol
|
||||
linear_size = 1
|
||||
for e in resol:
|
||||
linear_size *= e
|
||||
rif = pyrpn.RPNIFS(pyrpn.const.POS_XDIM,
|
||||
pyrpn.const.RESULT_CONST,
|
||||
sz, (42,))
|
||||
for _ in range(2000):
|
||||
pos = random.randint(0, linear_size-1)
|
||||
coord = rif.from_pos(pos)
|
||||
expt = []
|
||||
cur = pos
|
||||
for dim in resol:
|
||||
elt = cur % dim
|
||||
cur //= dim
|
||||
expt.append(elt)
|
||||
expt = tuple(expt)
|
||||
with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
|
||||
self.assertEqual(expt, coord)
|
||||
result = rif.to_pos(*coord)
|
||||
with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
|
||||
self.assertEqual(result, pos)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue