Starts implementing RPNIFS class
- __init__ - weights setter/getter - __len__
This commit is contained in:
parent
472803dc60
commit
48b8f3fbad
5 changed files with 244 additions and 7 deletions
103
python_ifs.c
103
python_ifs.c
|
|
@ -21,11 +21,21 @@
|
||||||
/**@file python_ifs.c */
|
/**@file python_ifs.c */
|
||||||
|
|
||||||
static PyMethodDef RPNIFS_methods[] = {
|
static PyMethodDef RPNIFS_methods[] = {
|
||||||
|
PYRPN_method("weights", rpnifs_weights,
|
||||||
|
METH_FASTCALL,
|
||||||
|
"self, weights=None",
|
||||||
|
"Get or set the weights list.\n\n\
|
||||||
|
When setting the weight list, the weight list len sets the number of functions \
|
||||||
|
in the system."),
|
||||||
|
PYRPN_method("weight", rpnifs_weight,
|
||||||
|
METH_FASTCALL,
|
||||||
|
"self, idx, weight=None",
|
||||||
|
"Get or set a single weight"),
|
||||||
{NULL} // Sentinel
|
{NULL} // Sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyMemberDef RPNIFS_members[] = {
|
static PyMemberDef RPNIFS_members[] = {
|
||||||
{"iter_expressions", T_OBJECT, offsetof(PyRPNIFS_t, rifs), READONLY,
|
{"expressions", T_OBJECT, offsetof(PyRPNIFS_t, rifs), READONLY,
|
||||||
"The tuple with RPNIterExpr instances"},
|
"The tuple with RPNIterExpr instances"},
|
||||||
{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
|
{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
|
||||||
"The mmap storing data"},
|
"The mmap storing data"},
|
||||||
|
|
@ -156,7 +166,7 @@ length %ld provided",
|
||||||
ifs_self->_mmap = ifs_self->mm_buff.buf;
|
ifs_self->_mmap = ifs_self->mm_buff.buf;
|
||||||
|
|
||||||
ifs_self->ifs = rpn_ifs_new(rif_params, ifs_self->mm_buff.buf);
|
ifs_self->ifs = rpn_ifs_new(rif_params, ifs_self->mm_buff.buf);
|
||||||
if(!ifs_self->rifs)
|
if(!ifs_self->ifs)
|
||||||
{
|
{
|
||||||
PyErr_Format(PyExc_RuntimeError,
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
"Error initializing ifs: %s", strerror(errno));
|
"Error initializing ifs: %s", strerror(errno));
|
||||||
|
|
@ -185,6 +195,91 @@ void rpnifs_del(PyObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
|
{
|
||||||
|
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||||
|
PyObject *iter;
|
||||||
|
unsigned int *weights;
|
||||||
|
|
||||||
|
if(nargs == 1 && args[0] != Py_None)
|
||||||
|
{
|
||||||
|
// Try to update weights
|
||||||
|
const Py_ssize_t len = PyObject_Length(args[0]);
|
||||||
|
if(PyErr_Occurred())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if((size_t)len != ifs_self->ifs->if_sz)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"Expected %ld weights but argument length is %ld",
|
||||||
|
ifs_self->ifs->if_sz, len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
weights = malloc(sizeof(unsigned int)*len);
|
||||||
|
if(len && !weights)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_MemoryError,
|
||||||
|
"Unable to allocate weights : %s",
|
||||||
|
strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
iter = PyObject_GetIter(args[0]);
|
||||||
|
if(PyErr_Occurred())
|
||||||
|
{
|
||||||
|
goto err_weights;
|
||||||
|
}
|
||||||
|
for(size_t i=0; i<(unsigned int)len; i++)
|
||||||
|
{
|
||||||
|
PyObject *item = PyIter_Next(iter);
|
||||||
|
if(PyErr_Occurred())
|
||||||
|
{
|
||||||
|
goto err_weights;
|
||||||
|
}
|
||||||
|
const unsigned long w = PyLong_AsUnsignedLong(item);
|
||||||
|
Py_DECREF(item);
|
||||||
|
if(PyErr_Occurred())
|
||||||
|
{
|
||||||
|
goto err_weights;
|
||||||
|
}
|
||||||
|
weights[i] = w;
|
||||||
|
}
|
||||||
|
Py_DECREF(iter);
|
||||||
|
rpn_ifs_set_if_count(ifs_self->ifs, len, weights);
|
||||||
|
free(weights);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return weights in a new tuple
|
||||||
|
PyObject *ret = PyTuple_New(ifs_self->ifs->if_sz);
|
||||||
|
if(PyErr_Occurred())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(size_t i=0; i<ifs_self->ifs->if_sz; i++)
|
||||||
|
{
|
||||||
|
const unsigned int weight = ifs_self->ifs->weight[i];
|
||||||
|
PyObject *item = PyLong_FromUnsignedLong(weight);
|
||||||
|
if(PyErr_Occurred()) { return NULL; }
|
||||||
|
PyTuple_SET_ITEM(ret, i, item);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err_weights:
|
||||||
|
free(weights);
|
||||||
|
Py_DECREF(iter);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *rpnifs_weight(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *rpnifs_str(PyObject *self)
|
PyObject *rpnifs_str(PyObject *self)
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||||
|
|
@ -201,8 +296,8 @@ PyObject *rpnifs_repr(PyObject *self)
|
||||||
|
|
||||||
Py_ssize_t rpnifs_len(PyObject *self)
|
Py_ssize_t rpnifs_len(PyObject *self)
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||||
return -1;
|
return (Py_ssize_t)ifs_self->ifs->if_sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,9 @@ PyObject *rpnifs_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
|
||||||
int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds);
|
int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
void rpnifs_del(PyObject *self);
|
void rpnifs_del(PyObject *self);
|
||||||
|
|
||||||
|
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_str(PyObject *self);
|
PyObject *rpnifs_str(PyObject *self);
|
||||||
PyObject *rpnifs_repr(PyObject *self);
|
PyObject *rpnifs_repr(PyObject *self);
|
||||||
|
|
||||||
|
|
@ -87,7 +90,6 @@ Py_ssize_t rpnifs_len(PyObject *self);
|
||||||
PyObject *rpnifs_expr_item(PyObject *self, Py_ssize_t idx);
|
PyObject *rpnifs_expr_item(PyObject *self, Py_ssize_t idx);
|
||||||
int rpnifs_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject *value);
|
int rpnifs_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject *value);
|
||||||
|
|
||||||
|
|
||||||
int rpnifs_getbuffer(PyObject *self, Py_buffer *view, int flags);
|
int rpnifs_getbuffer(PyObject *self, Py_buffer *view, int flags);
|
||||||
void rpnifs_releasebuffer(PyObject *self, Py_buffer *view);
|
void rpnifs_releasebuffer(PyObject *self, Py_buffer *view);
|
||||||
|
|
||||||
|
|
|
||||||
70
rpn_ifs.c
70
rpn_ifs.c
|
|
@ -7,6 +7,7 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
|
||||||
|
|
||||||
if(!(res = malloc(sizeof(rpn_ifs_t))))
|
if(!(res = malloc(sizeof(rpn_ifs_t))))
|
||||||
{
|
{
|
||||||
|
err = errno;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
bzero(res, sizeof(rpn_ifs_t));
|
bzero(res, sizeof(rpn_ifs_t));
|
||||||
|
|
@ -25,6 +26,7 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
|
||||||
-1, 0);
|
-1, 0);
|
||||||
if(res->mem == (void*)-1)
|
if(res->mem == (void*)-1)
|
||||||
{
|
{
|
||||||
|
err = errno;
|
||||||
goto mmap_err;
|
goto mmap_err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,10 +34,8 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
mmap_err:
|
mmap_err:
|
||||||
err = errno;
|
|
||||||
free(res);
|
free(res);
|
||||||
error:
|
error:
|
||||||
err = errno;
|
|
||||||
errno = err;
|
errno = err;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +60,72 @@ void rpn_ifs_free(rpn_ifs_t *rifs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t rpn_ifs_set_if_count(rpn_ifs_t *rifs, size_t count, unsigned int *weights)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
const size_t old_sz = rifs->if_sz;
|
||||||
|
|
||||||
|
// free old functions if old_sz > count
|
||||||
|
if(old_sz)
|
||||||
|
{
|
||||||
|
for(size_t i=old_sz-1; i>=count; i--)
|
||||||
|
{
|
||||||
|
rpn_if_free(rifs->rpn_if[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if(!(tmp = realloc(rifs->rpn_if, sizeof(rpn_if_t*)*count)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rifs->rpn_if = tmp;
|
||||||
|
|
||||||
|
if(!(tmp = realloc(rifs->weight, sizeof(unsigned int) * count)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rifs->weight = tmp;
|
||||||
|
|
||||||
|
rifs->flat_sz = rifs->params.rpn_sz * count;
|
||||||
|
if(!(tmp = realloc(rifs->flat_rpn, sizeof(rpn_expr_t*) * rifs->flat_sz)))
|
||||||
|
{
|
||||||
|
rifs->flat_sz = rifs->params.rpn_sz * old_sz;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rifs->flat_rpn = tmp;
|
||||||
|
rifs->if_sz = count;
|
||||||
|
|
||||||
|
|
||||||
|
// init new functions if old_sz < count
|
||||||
|
for(size_t i=old_sz; i<count; i++)
|
||||||
|
{
|
||||||
|
rifs->rpn_if[i] = rpn_if_new(&(rifs->params), rifs->mem, NULL);
|
||||||
|
if(!rifs->rpn_if[i])
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for(size_t j=0; j<rifs->params.rpn_sz; j++)
|
||||||
|
{
|
||||||
|
const size_t flat_idx = (i*rifs->params.rpn_sz) + j;
|
||||||
|
rifs->flat_rpn[flat_idx] = &(rifs->rpn_if[i]->rpn[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// set all weights
|
||||||
|
memcpy(rifs->weight, weights, sizeof(unsigned int) * count);
|
||||||
|
|
||||||
|
if(rpn_ifs_weight_update(rifs) < 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return rifs->if_sz;
|
||||||
|
}
|
||||||
|
|
||||||
size_t rpn_ifs_add_if(rpn_ifs_t *rifs, unsigned int weight)
|
size_t rpn_ifs_add_if(rpn_ifs_t *rifs, unsigned int weight)
|
||||||
{
|
{
|
||||||
size_t res, i, first_flat;
|
size_t res, i, first_flat;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,15 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap);
|
||||||
*/
|
*/
|
||||||
void rpn_ifs_free(rpn_ifs_t *rifs);
|
void rpn_ifs_free(rpn_ifs_t *rifs);
|
||||||
|
|
||||||
|
/**@brief Set the number and weights of functions in the system
|
||||||
|
* @note Do not re-init existing function
|
||||||
|
* @param rifs The iterated function system
|
||||||
|
* @param count The number of functions in the system
|
||||||
|
* @param weights The function's weight
|
||||||
|
* @return The number of function in the system
|
||||||
|
*/
|
||||||
|
size_t rpn_ifs_set_if_count(rpn_ifs_t *rifs, size_t count, unsigned int *weights);
|
||||||
|
|
||||||
/**@brief Add a new iterated function to the system
|
/**@brief Add a new iterated function to the system
|
||||||
* @param rifs The iterated function system
|
* @param rifs The iterated function system
|
||||||
* @param weight The new expression weight
|
* @param weight The new expression weight
|
||||||
|
|
|
||||||
65
tests/tests_rpn_ifs.py
Executable file
65
tests/tests_rpn_ifs.py
Executable file
|
|
@ -0,0 +1,65 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# copyright 2023 weber yann
|
||||||
|
#
|
||||||
|
# this file is part of rpnifs.
|
||||||
|
#
|
||||||
|
# geneifs is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the gnu general public license as published by
|
||||||
|
# the free software foundation, either version 3 of the license, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# geneifs is distributed in the hope that it will be useful,
|
||||||
|
# but without any warranty; without even the implied warranty of
|
||||||
|
# merchantability or fitness for a particular purpose. see the
|
||||||
|
# gnu general public license for more details.
|
||||||
|
#
|
||||||
|
# you should have received a copy of the gnu general public license
|
||||||
|
# along with geneifs. if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import mmap
|
||||||
|
import pickle
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pyrpn
|
||||||
|
except (ImportError, NameError) as e:
|
||||||
|
print("error importing pyrpn. try to run make.",
|
||||||
|
file=sys.stderr)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
class TestRPNIFS(unittest.TestCase):
|
||||||
|
""" Testing RPNIFS features """
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||||
|
pyrpn.const.RESULT_COUNT,
|
||||||
|
(640,480))
|
||||||
|
self.assertEqual(len(ifs), 0)
|
||||||
|
|
||||||
|
def test_weights_set(self):
|
||||||
|
ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
|
||||||
|
pyrpn.const.RESULT_COUNT,
|
||||||
|
(640,480))
|
||||||
|
self.assertEqual(len(ifs), 0)
|
||||||
|
w = ifs.weights([1,2,4])
|
||||||
|
self.assertEqual(len(ifs), 3)
|
||||||
|
self.assertEqual(w, (1,2,4))
|
||||||
|
|
||||||
|
w = ifs.weights()
|
||||||
|
self.assertEqual(w, (1,2,4))
|
||||||
|
|
||||||
|
for ifs_len in [random.randint(1,10) for _ in range(10)]:
|
||||||
|
for _ in range(10):
|
||||||
|
w = [random.randint(1,1000) for _ in range(ifs_len)]
|
||||||
|
ifs.weights(w)
|
||||||
|
self.assertEqual(len(ifs), ifs_len)
|
||||||
|
nw = ifs.weights()
|
||||||
|
self.assertEqual(tuple(w), nw)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue