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 */
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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"},
|
||||
{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
|
||||
"The mmap storing data"},
|
||||
|
|
@ -156,7 +166,7 @@ length %ld provided",
|
|||
ifs_self->_mmap = 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,
|
||||
"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)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
|
|
@ -201,8 +296,8 @@ PyObject *rpnifs_repr(PyObject *self)
|
|||
|
||||
Py_ssize_t rpnifs_len(PyObject *self)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "TODO");
|
||||
return -1;
|
||||
PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
|
||||
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);
|
||||
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_repr(PyObject *self);
|
||||
|
||||
|
|
@ -87,7 +90,6 @@ Py_ssize_t rpnifs_len(PyObject *self);
|
|||
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_getbuffer(PyObject *self, Py_buffer *view, int flags);
|
||||
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))))
|
||||
{
|
||||
err = errno;
|
||||
goto error;
|
||||
}
|
||||
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);
|
||||
if(res->mem == (void*)-1)
|
||||
{
|
||||
err = errno;
|
||||
goto mmap_err;
|
||||
}
|
||||
}
|
||||
|
|
@ -32,10 +34,8 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
|
|||
return res;
|
||||
|
||||
mmap_err:
|
||||
err = errno;
|
||||
free(res);
|
||||
error:
|
||||
err = errno;
|
||||
errno = err;
|
||||
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 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);
|
||||
|
||||
/**@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
|
||||
* @param rifs The iterated function system
|
||||
* @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