Browse Source

Starts implementing RPNIFS class

- __init__
- weights setter/getter
- __len__
Yann Weber 1 year ago
parent
commit
48b8f3fbad
5 changed files with 244 additions and 7 deletions
  1. 99
    4
      python_ifs.c
  2. 3
    1
      python_ifs.h
  3. 68
    2
      rpn_ifs.c
  4. 9
    0
      rpn_ifs.h
  5. 65
    0
      tests/tests_rpn_ifs.py

+ 99
- 4
python_ifs.c View File

@@ -21,11 +21,21 @@
21 21
 /**@file python_ifs.c */
22 22
 
23 23
 static PyMethodDef RPNIFS_methods[] = {
24
+	PYRPN_method("weights", rpnifs_weights, 
25
+			METH_FASTCALL,
26
+			"self, weights=None",
27
+			"Get or set the weights list.\n\n\
28
+When setting the weight list, the weight list len sets the number of functions \
29
+in the system."),
30
+	PYRPN_method("weight", rpnifs_weight,
31
+			METH_FASTCALL,
32
+			"self, idx, weight=None",
33
+			"Get or set a single weight"),
24 34
 	{NULL} // Sentinel
25 35
 };
26 36
 
27 37
 static PyMemberDef RPNIFS_members[] = {
28
-	{"iter_expressions", T_OBJECT, offsetof(PyRPNIFS_t, rifs), READONLY,
38
+	{"expressions", T_OBJECT, offsetof(PyRPNIFS_t, rifs), READONLY,
29 39
 		"The tuple with RPNIterExpr instances"},
30 40
 	{"mmap", T_OBJECT, offsetof(PyRPNIFS_t, mmap), READONLY,
31 41
 		"The mmap storing data"},
@@ -156,7 +166,7 @@ length %ld provided",
156 166
 	ifs_self->_mmap = ifs_self->mm_buff.buf;
157 167
 
158 168
 	ifs_self->ifs = rpn_ifs_new(rif_params, ifs_self->mm_buff.buf);
159
-	if(!ifs_self->rifs)
169
+	if(!ifs_self->ifs)
160 170
 	{
161 171
 		PyErr_Format(PyExc_RuntimeError,
162 172
 			"Error initializing ifs: %s", strerror(errno));
@@ -185,6 +195,91 @@ void rpnifs_del(PyObject *self)
185 195
 }
186 196
 
187 197
 
198
+PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
199
+{
200
+	PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
201
+	PyObject *iter;
202
+	unsigned int *weights;
203
+
204
+	if(nargs == 1 && args[0] != Py_None)
205
+	{
206
+		// Try to update weights
207
+		const Py_ssize_t len = PyObject_Length(args[0]);
208
+		if(PyErr_Occurred())
209
+		{
210
+			return NULL;
211
+		}
212
+		/*
213
+		if((size_t)len != ifs_self->ifs->if_sz)
214
+		{
215
+			PyErr_Format(PyExc_ValueError,
216
+				"Expected %ld weights but argument length is %ld",
217
+				ifs_self->ifs->if_sz, len);
218
+			return NULL;
219
+		}
220
+		*/
221
+		weights = malloc(sizeof(unsigned int)*len);
222
+		if(len && !weights)
223
+		{
224
+			PyErr_Format(PyExc_MemoryError,
225
+				"Unable to allocate weights : %s",
226
+				strerror(errno));
227
+			return NULL;
228
+		}
229
+		iter = PyObject_GetIter(args[0]);
230
+		if(PyErr_Occurred())
231
+		{
232
+			goto err_weights;
233
+		}
234
+		for(size_t i=0; i<(unsigned int)len; i++)
235
+		{
236
+			PyObject *item = PyIter_Next(iter);
237
+			if(PyErr_Occurred())
238
+			{
239
+				goto err_weights;
240
+			}
241
+			const unsigned long w = PyLong_AsUnsignedLong(item);
242
+			Py_DECREF(item);
243
+			if(PyErr_Occurred())
244
+			{
245
+				goto err_weights;
246
+			}
247
+			weights[i] = w;
248
+		}
249
+		Py_DECREF(iter);
250
+		rpn_ifs_set_if_count(ifs_self->ifs, len, weights);
251
+		free(weights);
252
+	}
253
+
254
+	// return weights in a new tuple
255
+	PyObject *ret = PyTuple_New(ifs_self->ifs->if_sz);
256
+	if(PyErr_Occurred())
257
+	{
258
+		return NULL;
259
+	}
260
+	for(size_t i=0; i<ifs_self->ifs->if_sz; i++)
261
+	{
262
+		const unsigned int weight = ifs_self->ifs->weight[i];
263
+		PyObject *item = PyLong_FromUnsignedLong(weight);
264
+		if(PyErr_Occurred()) { return NULL; }
265
+		PyTuple_SET_ITEM(ret, i, item);
266
+	}
267
+	return ret;
268
+
269
+err_weights:
270
+	free(weights);
271
+	Py_DECREF(iter);
272
+	return NULL;
273
+}
274
+
275
+
276
+PyObject *rpnifs_weight(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
277
+{
278
+	PyErr_SetString(PyExc_NotImplementedError, "TODO");
279
+	return NULL;
280
+}
281
+
282
+
188 283
 PyObject *rpnifs_str(PyObject *self)
189 284
 {
190 285
 	PyErr_SetString(PyExc_NotImplementedError, "TODO");
@@ -201,8 +296,8 @@ PyObject *rpnifs_repr(PyObject *self)
201 296
 
202 297
 Py_ssize_t rpnifs_len(PyObject *self)
203 298
 {
204
-	PyErr_SetString(PyExc_NotImplementedError, "TODO");
205
-	return -1;
299
+	PyRPNIFS_t *ifs_self = (PyRPNIFS_t*)self;
300
+	return (Py_ssize_t)ifs_self->ifs->if_sz;
206 301
 }
207 302
 
208 303
 

+ 3
- 1
python_ifs.h View File

@@ -80,6 +80,9 @@ PyObject *rpnifs_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
80 80
 int rpnifs_init(PyObject *self, PyObject *args, PyObject *kwds);
81 81
 void rpnifs_del(PyObject *self);
82 82
 
83
+PyObject *rpnifs_weights(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
84
+PyObject *rpnifs_weight(PyObject *self, PyObject *const *args, Py_ssize_t nargs);
85
+
83 86
 PyObject *rpnifs_str(PyObject *self);
84 87
 PyObject *rpnifs_repr(PyObject *self);
85 88
 
@@ -87,7 +90,6 @@ Py_ssize_t rpnifs_len(PyObject *self);
87 90
 PyObject *rpnifs_expr_item(PyObject *self, Py_ssize_t idx);
88 91
 int rpnifs_expr_ass_item(PyObject *self, Py_ssize_t idx, PyObject *value);
89 92
 
90
-
91 93
 int rpnifs_getbuffer(PyObject *self, Py_buffer *view, int flags);
92 94
 void rpnifs_releasebuffer(PyObject *self, Py_buffer *view);
93 95
 

+ 68
- 2
rpn_ifs.c View File

@@ -7,6 +7,7 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
7 7
 
8 8
 	if(!(res = malloc(sizeof(rpn_ifs_t))))
9 9
 	{
10
+		err = errno;
10 11
 		goto error;
11 12
 	}
12 13
 	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)
25 26
 			-1, 0);
26 27
 		if(res->mem == (void*)-1)
27 28
 		{
29
+			err = errno;
28 30
 			goto mmap_err;
29 31
 		}
30 32
 	}
@@ -32,10 +34,8 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap)
32 34
 	return res;
33 35
 
34 36
 	mmap_err:
35
-		err = errno;
36 37
 		free(res);
37 38
 	error:
38
-		err = errno;
39 39
 		errno = err;
40 40
 		return NULL;
41 41
 }
@@ -60,6 +60,72 @@ void rpn_ifs_free(rpn_ifs_t *rifs)
60 60
 	}
61 61
 }
62 62
 
63
+size_t rpn_ifs_set_if_count(rpn_ifs_t *rifs, size_t count, unsigned int *weights)
64
+{
65
+	errno = 0;
66
+
67
+	const size_t old_sz = rifs->if_sz;
68
+
69
+	// free old functions if old_sz > count
70
+	if(old_sz)
71
+	{
72
+		for(size_t i=old_sz-1; i>=count; i--)
73
+		{
74
+			rpn_if_free(rifs->rpn_if[i]);
75
+		}
76
+	}
77
+
78
+	void *tmp;
79
+
80
+	if(!(tmp = realloc(rifs->rpn_if, sizeof(rpn_if_t*)*count)))
81
+	{
82
+		return 0;
83
+	}
84
+	rifs->rpn_if = tmp;
85
+
86
+	if(!(tmp = realloc(rifs->weight, sizeof(unsigned int) * count)))
87
+	{
88
+		return 0;
89
+	}
90
+	rifs->weight = tmp;
91
+
92
+	rifs->flat_sz = rifs->params.rpn_sz * count;
93
+	if(!(tmp = realloc(rifs->flat_rpn, sizeof(rpn_expr_t*) * rifs->flat_sz)))
94
+	{
95
+		rifs->flat_sz = rifs->params.rpn_sz * old_sz;
96
+		return 0;
97
+	}
98
+	rifs->flat_rpn = tmp;
99
+	rifs->if_sz = count;
100
+
101
+
102
+	// init new functions if old_sz < count
103
+	for(size_t i=old_sz; i<count; i++)
104
+	{
105
+		rifs->rpn_if[i] = rpn_if_new(&(rifs->params), rifs->mem, NULL);
106
+		if(!rifs->rpn_if[i])
107
+		{
108
+			return 0;
109
+		}
110
+		for(size_t j=0; j<rifs->params.rpn_sz; j++)
111
+		{
112
+			const size_t flat_idx = (i*rifs->params.rpn_sz) + j;
113
+			rifs->flat_rpn[flat_idx] = &(rifs->rpn_if[i]->rpn[j]);
114
+		}
115
+	}
116
+
117
+
118
+
119
+	// set all weights
120
+	memcpy(rifs->weight, weights, sizeof(unsigned int) * count);
121
+
122
+	if(rpn_ifs_weight_update(rifs) < 0)
123
+	{
124
+		return 0;
125
+	}
126
+	return rifs->if_sz;
127
+}
128
+
63 129
 size_t rpn_ifs_add_if(rpn_ifs_t *rifs, unsigned int weight)
64 130
 {
65 131
 	size_t res, i, first_flat;

+ 9
- 0
rpn_ifs.h View File

@@ -95,6 +95,15 @@ rpn_ifs_t* rpn_ifs_new(rpn_if_param_t *params, rpn_value_t *memmap);
95 95
  */
96 96
 void rpn_ifs_free(rpn_ifs_t *rifs);
97 97
 
98
+/**@brief Set the number and weights of functions in the system
99
+ * @note Do not re-init existing function
100
+ * @param rifs The iterated function system
101
+ * @param count The number of functions in the system
102
+ * @param weights The function's weight
103
+ * @return The number of function in the system
104
+ */
105
+size_t rpn_ifs_set_if_count(rpn_ifs_t *rifs, size_t count, unsigned int *weights);
106
+
98 107
 /**@brief Add a new iterated function to the system
99 108
  * @param rifs The iterated function system
100 109
  * @param weight The new expression weight

+ 65
- 0
tests/tests_rpn_ifs.py View File

@@ -0,0 +1,65 @@
1
+#!/usr/bin/python3
2
+# copyright 2023 weber yann
3
+#
4
+# this file is part of rpnifs.
5
+#
6
+#        geneifs is free software: you can redistribute it and/or modify
7
+#        it 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
+#        geneifs 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 geneifs.  if not, see <http://www.gnu.org/licenses/>.
18
+#
19
+
20
+import copy
21
+import mmap
22
+import pickle
23
+import random
24
+import sys
25
+
26
+import unittest
27
+
28
+try:
29
+    import pyrpn
30
+except (ImportError, NameError) as e:
31
+    print("error importing pyrpn. try to run make.",
32
+          file=sys.stderr)
33
+    raise e
34
+
35
+from utils import *
36
+
37
+class TestRPNIFS(unittest.TestCase):
38
+    """ Testing RPNIFS features """
39
+
40
+    def test_init(self):
41
+        ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
42
+                                pyrpn.const.RESULT_COUNT,
43
+                                (640,480))
44
+        self.assertEqual(len(ifs), 0)
45
+
46
+    def test_weights_set(self):
47
+        ifs = pyrpn.RPNIFS(pyrpn.const.POS_XY,
48
+                                pyrpn.const.RESULT_COUNT,
49
+                                (640,480))
50
+        self.assertEqual(len(ifs), 0)
51
+        w = ifs.weights([1,2,4])
52
+        self.assertEqual(len(ifs), 3)
53
+        self.assertEqual(w, (1,2,4))
54
+
55
+        w = ifs.weights()
56
+        self.assertEqual(w, (1,2,4))
57
+
58
+        for ifs_len in [random.randint(1,10) for _ in range(10)]:
59
+            for _ in range(10):
60
+                w = [random.randint(1,1000) for _ in range(ifs_len)]
61
+                ifs.weights(w)
62
+                self.assertEqual(len(ifs), ifs_len)
63
+                nw = ifs.weights()
64
+                self.assertEqual(tuple(w), nw)
65
+

Loading…
Cancel
Save