Browse Source

Adds coordinate convertion methods to python lib + tests

Yann Weber 1 year ago
parent
commit
d86a465339
12 changed files with 526 additions and 44 deletions
  1. 125
    10
      python_if.c
  2. 15
    0
      python_if.h
  3. 1
    0
      rpn_if.c
  4. 1
    1
      rpn_if.h
  5. 6
    15
      rpn_if_default.c
  6. 1
    1
      rpn_jit.c
  7. 13
    10
      tests/tests_rpn_compile.py
  8. 3
    3
      tests/tests_rpn_eval.py
  9. 278
    2
      tests/tests_rpniter.py
  10. 1
    1
      tests/tests_rpniter_seq.py
  11. 1
    1
      tests/tests_tokens.py
  12. 81
    0
      tests/utils.py

+ 125
- 10
python_if.c View File

@@ -28,6 +28,15 @@ static PyMethodDef RPNIterExpr_methods[] = {
28 28
 			METH_O,
29 29
 			"self, position, /",
30 30
 			"Run an IF given a position and return a new position"),
31
+	PYRPN_method("to_pos", rpnif_to_pos,
32
+			METH_FASTCALL,
33
+			"self, *args, /",
34
+			"Return a position (int) from a coordinates given as"
35
+			"argument."),
36
+	PYRPN_method("from_pos", rpnif_from_pos,
37
+			METH_O,
38
+			"self, position, /",
39
+			"Return a coordinates tuple from given position."),
31 40
 	PYRPN_method("__getstate__", rpnif_getstate,
32 41
 			METH_NOARGS,
33 42
 			"self, /",
@@ -165,33 +174,35 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
165 174
 
166 175
 	//Check & convert lim
167 176
 	PyObject *tmp;
168
-	tmp = lim_obj;
169
-	if(!PyTuple_Check(tmp))
177
+	tmp = PySequence_Fast(lim_obj, "Sequence expected for size_lim argument");
178
+	if(PyErr_Occurred())
170 179
 	{
171
-		PyErr_SetString(PyExc_ValueError,
172
-			"Invalid type for size_lim argument");
173 180
 		return -1;
174 181
 	}
175
-	Py_ssize_t lim_obj_sz = PyTuple_Size(tmp);
182
+	Py_ssize_t lim_obj_sz = PySequence_Fast_GET_SIZE(tmp);
176 183
 	ndim = lim_obj_sz;
177 184
 	if(PyErr_Occurred())
178 185
 	{
186
+		Py_DECREF(tmp);
179 187
 		return -1;
180 188
 	}
181 189
 	if(lim_obj_sz < 1)
182 190
 	{
191
+		Py_DECREF(tmp);
183 192
 		PyErr_SetString(PyExc_ValueError,
184 193
 			"Size limits cannot be empty");
194
+		return -1;
185 195
 	}
186 196
 
187 197
 	if(pos_flag == RPN_IF_POSITION_XDIM)
188 198
 	{
189
-		PyObject *item = PyTuple_GET_ITEM(tmp, 0);
199
+		PyObject *item = PySequence_Fast_GET_ITEM(tmp, 0);
190 200
 		Py_ssize_t tmp = PyLong_AsSsize_t(item);
191 201
 		if(PyErr_Occurred())
192 202
 		{
193 203
 			PyErr_SetString(PyExc_ValueError,
194 204
 				"Unable to convert size_lim[0] to int");
205
+			Py_DECREF(tmp);
195 206
 			return -1;
196 207
 		}
197 208
 		if(lim_obj_sz != tmp + 1)
@@ -199,6 +210,7 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
199 210
 			PyErr_Format(PyExc_ValueError,
200 211
 				"Xdim indicate %d size_lim but len(size_lim)=%d",
201 212
 				tmp+1, lim_obj_sz);
213
+			Py_DECREF(tmp);
202 214
 			return -1;
203 215
 		}
204 216
 		expt_sizes[0] = ndim = tmp;
@@ -210,6 +222,7 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
210 222
 			PyErr_Format(PyExc_ValueError,
211 223
 				"Expected %d size_lim but len(size_lim)=%d",
212 224
 				expt_sizes[0], lim_obj_sz);
225
+			Py_DECREF(tmp);
213 226
 			return -1;
214 227
 		}
215 228
 	}
@@ -217,22 +230,24 @@ int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
217 230
 	size_t sz_limits[lim_obj_sz];
218 231
 	for(Py_ssize_t i = 0; i<lim_obj_sz; i++)
219 232
 	{
220
-		PyObject *item = PyTuple_GET_ITEM(tmp, i);
233
+		PyObject *item = PySequence_Fast_GET_ITEM(tmp, i);
221 234
 		sz_limits[i] = PyLong_AsSize_t(item);
222 235
 		if(PyErr_Occurred())
223 236
 		{
224 237
 			PyErr_Format(PyExc_ValueError,
225 238
 				"Unable to convert size_lim[%d] to unsigned int",
226 239
 				i);
240
+			Py_DECREF(tmp);
227 241
 			return -1;
228 242
 		}
229 243
 	}
244
+	Py_DECREF(tmp);
245
+	tmp = NULL;
230 246
 
231 247
 	expr_self->ndim = ndim;
232 248
 
233 249
 	//Check & convert const values
234 250
 	Py_ssize_t values_obj_sz = 0;
235
-	tmp = NULL;
236 251
 	if(expt_sizes[1] > 0)
237 252
 	{
238 253
 		tmp = const_values_obj;
@@ -280,6 +295,12 @@ with given arguments");
280 295
 
281 296
 	// Creating rif with a new memory map
282 297
 	expr_self->rif = rpn_if_new(rif_params, NULL);
298
+	if(!expr_self->rif)
299
+	{
300
+		PyErr_Format(PyExc_RuntimeError,
301
+				"Error initalizing if : %s", strerror(errno));
302
+		return -1;
303
+	}
283 304
 
284 305
 	// Creating the tuple holding RPNExpr instances of expressions
285 306
 	expr_self->expr = PyTuple_New(expr_self->rif->params->rpn_sz);
@@ -369,10 +390,10 @@ PyObject *rpnif_get_params(PyObject *self)
369 390
 	return res;
370 391
 }
371 392
 
372
-
373 393
 PyObject *rpnif_step(PyObject *self, PyObject* opos)
374 394
 {
375 395
 	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
396
+	/** @todo allow tuple as argument !!!!! */
376 397
 	if(!PyLong_Check(opos))
377 398
 	{
378 399
 		PyErr_SetString(PyExc_TypeError, "Expected position to be an int");
@@ -390,6 +411,100 @@ PyObject *rpnif_step(PyObject *self, PyObject* opos)
390 411
 }
391 412
 
392 413
 
414
+PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
415
+{
416
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
417
+	rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
418
+	const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
419
+	long long value;
420
+	
421
+	if(argc != rif_data->ndim)
422
+	{
423
+		PyErr_Format(PyExc_IndexError,
424
+				"Expression expect %lu dimentions coordinates,"
425
+				" but %ld arguments given.",
426
+				rif_data->ndim, argc);
427
+		return NULL;
428
+	}
429
+
430
+	rpn_value_t result=0;
431
+	size_t cur_dim_sz = 1;
432
+
433
+	for(Py_ssize_t i=0; i<rif_data->ndim; i++)
434
+	{
435
+		if(!PyLong_Check(argv[i]))
436
+		{
437
+			PyErr_SetString(PyExc_TypeError,
438
+					"coordinates must be integers");
439
+			return NULL;
440
+		}
441
+		value = PyLong_AsLongLong(argv[i]);
442
+		value = value >= 0?value:(-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
443
+		if(value >= rif_data->size_lim[i+idx_off])
444
+		{
445
+			PyErr_Format(PyExc_IndexError,
446
+					"Coordinate %ld overflows : %R/%lu",
447
+					i, argv[i],
448
+					rif_data->size_lim[i+idx_off]);
449
+			return NULL;
450
+		}
451
+		result += value * cur_dim_sz;
452
+		cur_dim_sz *= rif_data->size_lim[i+idx_off];
453
+	}
454
+
455
+	return PyLong_FromUnsignedLongLong(result);
456
+}
457
+
458
+
459
+PyObject *rpnif_from_pos(PyObject *self, PyObject* _pos)
460
+{
461
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
462
+	rpn_if_default_data_t *rif_data = (rpn_if_default_data_t*)expr_self->rif->params->data;
463
+	const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
464
+
465
+	if(!PyLong_Check(_pos))
466
+	{
467
+		PyErr_SetString(PyExc_TypeError,
468
+				"Expected position to be an integer");
469
+		return NULL;
470
+	}
471
+
472
+	size_t pos = PyLong_AsUnsignedLong(_pos);
473
+	if(PyErr_Occurred())
474
+	{
475
+		return NULL;
476
+	}
477
+
478
+	PyObject *res = PyTuple_New(rif_data->ndim);
479
+	if(PyErr_Occurred())
480
+	{
481
+		return NULL;
482
+	}
483
+	
484
+	for(size_t i=0; i<rif_data->ndim; i++)
485
+	{
486
+		size_t val;
487
+		size_t lim = rif_data->size_lim[i+idx_off];
488
+
489
+		val = pos % lim;
490
+		pos /= lim;
491
+
492
+		PyObject *elt = PyLong_FromUnsignedLong(val);
493
+		if(PyErr_Occurred())
494
+		{
495
+			goto err;
496
+		}
497
+		PyTuple_SET_ITEM(res, i,  elt);
498
+	}
499
+
500
+	return res;
501
+
502
+err:
503
+	Py_DECREF(res);
504
+	return NULL;
505
+}
506
+
507
+
393 508
 PyObject *rpnif_keys(PyObject *self)
394 509
 {
395 510
 	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
@@ -719,7 +834,7 @@ int rpnif_ass_subscript(PyObject *self, PyObject *key, PyObject *elt)
719 834
 	if(idx < 0)
720 835
 	{
721 836
 		PyErr_Format(PyExc_IndexError,
722
-				"Cannot set expression '%s' that do not exists with this parameters",
837
+				"Cannot set expression '%U' that do not exists with this parameters",
723 838
 				key);
724 839
 		return -1;
725 840
 	}

+ 15
- 0
python_if.h View File

@@ -132,6 +132,21 @@ PyObject *rpnif_get_params(PyObject *self);
132 132
  */
133 133
 PyObject *rpnif_step(PyObject *self, PyObject* pos);
134 134
 
135
+/**@brief Convert given arguments coordinates to position
136
+ * @param self RPNIterExpr instance
137
+ * @param argv Pointer on the array of arguments
138
+ * @param argc Argument count
139
+ * @return An integer
140
+ */
141
+PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc);
142
+
143
+/**@brief Convert given position to coordinates tuple
144
+ * @param self RPNIterExpr instance
145
+ * @param pos Position, as integer, to convert
146
+ * @return A tuple
147
+ */
148
+PyObject *rpnif_from_pos(PyObject *self, PyObject* pos);
149
+
135 150
 /**@brief RPNIterExpr __getstate__ method for pickling
136 151
  * @param cls RPNIterExpr type object
137 152
  * @param noargs Not an argument...

+ 1
- 0
rpn_if.c View File

@@ -71,6 +71,7 @@ rpn_if_t* rpn_if_new(const rpn_if_param_t *params, rpn_value_t *memmap)
71 71
 		#endif
72 72
 		goto rpn_malloc_err;
73 73
 	}
74
+
74 75
 	res->rpn_args = &(res->rpn_res[params->rpn_sz]);
75 76
 
76 77
 	res->rpn = malloc(sizeof(rpn_expr_t) * params->rpn_sz);

+ 1
- 1
rpn_if.h View File

@@ -113,7 +113,7 @@ struct rpn_if_s
113 113
 /**@brief Macro fetching a memory pointer given a position
114 114
  * @return rpn_value_t* values
115 115
  */
116
-#define rpn_if_getitem(rif, pos) (rif->mem + ((rif->params->value_sz) * pos))
116
+#define rpn_if_getitem(rif, pos) (rpn_value_t*)(((unsigned char*)rif->mem + ((rif->params->value_sz) * pos)))
117 117
 
118 118
 /**@brief Alloc a new @ref rpn_if_s using given parameters
119 119
  * @param params IF parameters

+ 6
- 15
rpn_if_default.c View File

@@ -435,7 +435,7 @@ int rpn_if_argf_xdim(rpn_if_t *rif, size_t pos, rpn_value_t *args)
435 435
 	curpos = pos;
436 436
 	for(i=0; i<*(data->size_lim)-1; i++)
437 437
 	{
438
-		curdim_sz *= data->size_lim[i+1];
438
+		curdim_sz = data->size_lim[i+1];
439 439
 		args[i] = curpos % curdim_sz;
440 440
 		curpos /= curdim_sz;
441 441
 	}
@@ -454,7 +454,7 @@ int rpn_if_argf_xdim(rpn_if_t *rif, size_t pos, rpn_value_t *args)
454 454
 int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
455 455
 {
456 456
 	rpn_if_default_data_t *data;
457
-	size_t i, res, cur, curlim, prevlim;
457
+	size_t i, res, cur, curlim, dim_sz;
458 458
 
459 459
 	data = (rpn_if_default_data_t*)rif->params->data;
460 460
 	res = 0;
@@ -469,20 +469,10 @@ int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
469 469
 	}
470 470
 	/**@todo check if *(data->size_lim) overflow rif->params->rpn_argc */
471 471
 
472
-	res = rif->rpn_res[0];
473
-	if(res >= data->size_lim[1])
474
-	{
475
-		if(data->pos_flag & RPN_IF_POSITION_OF_ERR)
476
-		{
477
-			return -1;
478
-		}
479
-		res %= data->size_lim[1];
480
-	}
481
-
482
-	for(i=1; i < *(data->size_lim); i++)
472
+	dim_sz = 1;
473
+	for(i=0;  i < *(data->size_lim); i++)
483 474
 	{
484 475
 		cur = rif->rpn_res[i];
485
-		prevlim = data->size_lim[i];
486 476
 		curlim = data->size_lim[i+1];
487 477
 		if(cur >= curlim)
488 478
 		{
@@ -492,7 +482,8 @@ int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
492 482
 			}
493 483
 			cur %= curlim;
494 484
 		}
495
-		res += cur * prevlim;
485
+		res += cur * dim_sz;
486
+		dim_sz *= curlim;
496 487
 	}
497 488
 	*pos = res;
498 489
 	return 0;

+ 1
- 1
rpn_jit.c View File

@@ -400,7 +400,7 @@ int _rpn_expr_compile_tokens(rpn_expr_t* expr)
400 400
 unsigned long rpn_expr_eval(rpn_expr_t *expr, unsigned long *args)
401 401
 {
402 402
 	rpn_run_f expr_run;
403
-	unsigned long int res;
403
+	rpn_value_t res;
404 404
 	if(expr->state == RPN_ERROR)
405 405
 	{
406 406
 		return 0;

+ 13
- 10
tests/tests_rpn_compile.py View File

@@ -34,6 +34,8 @@ except (ImportError, NameError) as e:
34 34
           file=sys.stderr)
35 35
     raise e
36 36
 
37
+from utils import Progress, VERBOSE
38
+
37 39
 class TestRpnCompile(unittest.TestCase):
38 40
 
39 41
     def test_basic(self):
@@ -55,11 +57,9 @@ class TestRpnCompile(unittest.TestCase):
55 57
 
56 58
     def test_long_code(self):
57 59
         """ Compile longs expressions (from 256 to 65536 op )"""
58
-        for i in range(0x100,0x10000,0x500):
60
+        for i in Progress(range(0x100,0x10000,0x500)):
59 61
             with self.subTest('Testing expression with %X ops' % i):
60 62
                 for argc in range(1,32, 8):
61
-                    sys.stderr.write('.')
62
-                    sys.stderr.flush()
63 63
                     args = [random.randint(0,IMAX) for _ in range(argc)]
64 64
                     expr = pyrpn.RPNExpr(pyrpn.random_expr(argc, i), argc)
65 65
                     del(expr)
@@ -69,16 +69,19 @@ class TestRpnCompile(unittest.TestCase):
69 69
         argc = 4
70 70
         codelen = 0x50000
71 71
         import time
72
-        for i in range(3):
72
+        for i in Progress(3):
73 73
             args = [random.randint(0,IMAX) for _ in range(argc)]
74
-            sys.stderr.write('Generate')
75
-            sys.stderr.flush()
74
+            if VERBOSE:
75
+                sys.stderr.write('Generate')
76
+                sys.stderr.flush()
76 77
             expr_str = pyrpn.random_expr(argc, codelen)
77
-            sys.stderr.write('d Compile')
78
-            sys.stderr.flush()
78
+            if VERBOSE:
79
+                sys.stderr.write('d Compile')
80
+                sys.stderr.flush()
79 81
             expr = pyrpn.RPNExpr(expr_str, argc)
80
-            sys.stderr.write('d ')
81
-            sys.stderr.flush()
82
+            if VERBOSE:
83
+                sys.stderr.write('d ')
84
+                sys.stderr.flush()
82 85
             del(expr)
83 86
 
84 87
     def test_pickling(self):  

+ 3
- 3
tests/tests_rpn_eval.py View File

@@ -34,6 +34,8 @@ except (ImportError, NameError) as e:
34 34
           file=sys.stderr)
35 35
     raise e
36 36
 
37
+from utils import Progress
38
+
37 39
 class TestRpnEval(unittest.TestCase):
38 40
 
39 41
     def test_arithm(self):
@@ -50,10 +52,8 @@ class TestRpnEval(unittest.TestCase):
50 52
             #('l', '<<'),
51 53
             #('r', '>>')
52 54
         ]
53
-        for rpn_op, pyop in ops:
55
+        for rpn_op, pyop in Progress(ops):
54 56
             with self.subTest('Testing op %s (%s)' % (rpn_op, pyop)):
55
-                sys.stderr.write('.')
56
-                sys.stderr.flush()
57 57
                 for i in range(0x1000):
58 58
                     op1, op2 = random.randint(0,IMAX), random.randint(1,IMAX)
59 59
                     pyexpr = '%d %s %d' % (op1, pyop, op2)

+ 278
- 2
tests/tests_rpniter.py View File

@@ -26,11 +26,13 @@ import unittest
26 26
 
27 27
 try:
28 28
     import pyrpn
29
-except (importerror, nameerror) as e:
29
+except (ImportError, NameError) as e:
30 30
     print("error importing pyrpn. try to run make.",
31 31
           file=sys.stderr)
32 32
     raise e
33 33
 
34
+from utils import Progress
35
+
34 36
 
35 37
 class TestRpnExprCopy(unittest.TestCase):
36 38
     """ Testing RPNExpr sequence method """
@@ -124,7 +126,7 @@ class TestRPNIterInit(unittest.TestCase):
124 126
     
125 127
     @skipIfNoNumpy()
126 128
     def test_buffer(self):
127
-        """ Test the buffer interface using numpy """
129
+        """ Test the len on buffer interface using numpy """
128 130
         args = [((pyrpn.const.POS_XY,
129 131
                   pyrpn.const.RESULT_COUNT,
130 132
                   (640,480)), 640*480),
@@ -171,6 +173,280 @@ class TestRPNIterInit(unittest.TestCase):
171 173
             str_repr = repr(rif)
172 174
 
173 175
 
176
+class TestRPNIterCoordinates(unittest.TestCase):
177
+    """ Testing methods for coordinates <-> position convertions """
178
+
179
+    def test_position_linear(self):
180
+        """ Testing linear coordinate convertion methods """
181
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_LINEAR,
182
+                    pyrpn.const.RESULT_CONST,
183
+                    (256,), (42,))
184
+
185
+        for pos in range(256):
186
+            with self.subTest(rif=rif, position=pos, expt=(pos,)):
187
+                res = rif.from_pos(pos)
188
+                self.assertEqual(res, (pos,))
189
+            with self.subTest(rif=rif, expt=pos, coord=(pos,)):
190
+                res = rif.to_pos(pos)
191
+                self.assertEqual(res, pos)
192
+
193
+    def test_position_xy(self):
194
+        """ Testing XY coordinate convertion methods """
195
+        for _ in Progress(5):
196
+            sz = (random.randint(32,128), random.randint(32,128))
197
+            rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY,
198
+                    pyrpn.const.RESULT_CONST,
199
+                    sz, (42,))
200
+            for pos in range(sz[0]*sz[1]):
201
+                coord = rif.from_pos(pos)
202
+                expt = (pos % sz[0], pos // sz[0])
203
+                with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
204
+                    self.assertEqual(expt, coord)
205
+                result = rif.to_pos(*coord)
206
+                with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
207
+                    self.assertEqual(result, pos)
208
+
209
+    def test_position_xy_neg(self):
210
+        """ Testing XY coordinates with negative values """
211
+        sz = (100,200)
212
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY,
213
+                pyrpn.const.RESULT_CONST,
214
+                sz, (42,))
215
+        
216
+        for _ in range(1000):
217
+            ny = random.randint(-0x1000000, sz[1])
218
+            nx = random.randint(0,sz[0]-1)
219
+            pos = rif.to_pos(nx, ny)
220
+            coord = rif.from_pos(pos)
221
+            self.assertEqual(coord, (nx, (ny%(1<<64))%sz[1]))
222
+
223
+    def test_position_xy_random(self):
224
+        """ Testing XY coordinate convertion methods (random samples)"""
225
+        for _ in Progress(256):
226
+            sz = (random.randint(32,4096), random.randint(32,4096))
227
+            rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY,
228
+                    pyrpn.const.RESULT_CONST,
229
+                    sz, (42,))
230
+            for _ in range(500):
231
+                pos = random.randint(0, (sz[0]*sz[1])-1)
232
+                coord = rif.from_pos(pos)
233
+                expt = (pos % sz[0], pos // sz[0])
234
+                with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
235
+                    self.assertEqual(expt, coord)
236
+                result = rif.to_pos(*coord)
237
+                with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
238
+                    self.assertEqual(result, pos)
239
+
240
+    def test_position_xdim(self):
241
+        """ Testing XDIM coordinate convertion methods """
242
+        ndim = 5
243
+        resol = [8 for _ in range(ndim)]
244
+        sz = [ndim]+resol
245
+        linear_size = 1
246
+        for e in resol:
247
+            linear_size *= e
248
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XDIM,
249
+                pyrpn.const.RESULT_CONST,
250
+                sz, (42,))
251
+        for pos in range(linear_size):
252
+            coord = rif.from_pos(pos)
253
+            expt = []
254
+            cur = pos
255
+            for dim in resol:
256
+                elt = cur % dim
257
+                cur //= dim
258
+                expt.append(elt)
259
+            expt = tuple(expt)
260
+            with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
261
+                self.assertEqual(expt, coord)
262
+            result = rif.to_pos(*coord)
263
+            with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
264
+                self.assertEqual(result, pos)
265
+
266
+    def test_position_xdim_neg(self):
267
+        """ Testing XDIM negative position convertion """
268
+        # TODO test negativ for other coordinate systems
269
+        ndim = 4
270
+        szlim = (ndim, 10,20,30,40)
271
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XDIM,
272
+                pyrpn.const.RESULT_CONST,
273
+                szlim, (42,))
274
+
275
+        pos = rif.to_pos(0,0,-5,0)
276
+        self.assertEqual(rif.from_pos(pos), (0,0,(-5%(1<<64))%30, 0))
277
+
278
+    def test_position_xdim(self):
279
+        """ Testing XDIM coordinate convertion methods (random sampling)"""
280
+        for _ in Progress(16):
281
+            ndim = random.randint(3,8)
282
+            resol = [random.randint(2, 16) for _ in range(ndim)]
283
+            sz = [ndim]+resol
284
+            linear_size = 1
285
+            for e in resol:
286
+                linear_size *= e
287
+            rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XDIM,
288
+                    pyrpn.const.RESULT_CONST,
289
+                    sz, (42,))
290
+            for _ in range(2000):
291
+                pos = random.randint(0, linear_size-1)
292
+                coord = rif.from_pos(pos)
293
+                expt = []
294
+                cur = pos
295
+                for dim in resol:
296
+                    elt = cur % dim
297
+                    cur //= dim
298
+                    expt.append(elt)
299
+                expt = tuple(expt)
300
+                with self.subTest(sz=sz, pos=pos, expt=expt, result=coord):
301
+                    self.assertEqual(expt, coord)
302
+                result = rif.to_pos(*coord)
303
+                with self.subTest(sz=sz, coord=coord, expt=pos, result=result):
304
+                    self.assertEqual(result, pos)
305
+
306
+
307
+class TestRPNIterConst(unittest.TestCase):
308
+    """ Testing various coordinate systems with constant result value """
309
+
310
+    @skipIfNoNumpy()
311
+    def test_simple_linear_const(self):
312
+        """ Testing a simple constant result on linear coord  """
313
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_LINEAR,
314
+                                pyrpn.const.RESULT_CONST,
315
+                                (512,), (42,))
316
+
317
+        data = np.frombuffer(rif, dtype=np.uint64)
318
+        for elt in data:
319
+            self.assertEqual(elt, 0)
320
+
321
+        rif['X'] = 'A0 A1 +'
322
+        pos = rif.step(0)
323
+        self.assertEqual(pos, 0)
324
+        self.assertEqual(data[0], 42)
325
+
326
+        data = np.frombuffer(rif, dtype=np.uint64)
327
+        self.assertEqual(data[0], 42)
328
+        for elt in data[1:]:
329
+            self.assertEqual(elt, 0)
330
+
331
+
332
+
333
+        pos = rif.step(0)
334
+        self.assertEqual(pos, 42)
335
+
336
+        data = np.frombuffer(rif, dtype=np.uint64)
337
+        for i, elt in enumerate(data):
338
+            with self.subTest(cur_pos=i):
339
+                if i in (0, 42):
340
+                    self.assertEqual(elt, 42)
341
+                else:
342
+                    self.assertEqual(elt, 0)
343
+
344
+
345
+        pos = rif.step(1)
346
+        self.assertEqual(pos, 1)
347
+        pos = rif.step(pos)
348
+        self.assertEqual(pos, 43)
349
+
350
+        newpos = 512 - 40
351
+        pos = rif.step(newpos)
352
+        self.assertEqual(pos, newpos)
353
+        pos = rif.step(pos)
354
+        self.assertEqual(pos, 2)
355
+
356
+    def test_random_linear_const(self):
357
+        """ Testing linear coord with const with random expressions """
358
+        for _ in range(200):
359
+            const_val = random.randint(0,0xFFFF)
360
+            rif = pyrpn.RPNIterExpr(pyrpn.const.POS_LINEAR,
361
+                                    pyrpn.const.RESULT_CONST,
362
+                                    (512,), (const_val,))
363
+            rif['X'].mutate(n_mutations=random.randint(10,100))
364
+            pos=0
365
+            all_pos=[]
366
+            for  _ in range(100):
367
+                pos = rif.step(pos)
368
+                all_pos.append(pos)
369
+                data = np.frombuffer(rif, dtype=np.uint64)
370
+                self.assertEqual(data[pos], const_val)
371
+            for i, elt in enumerate(np.frombuffer(rif, dtype=np.uint64)):
372
+                if i in all_pos:
373
+                    self.assertEqual(elt, const_val)
374
+                else:
375
+                    self.assertEqual(elt, 0)
376
+
377
+    def test_simple_xy_const(self):
378
+        """ Testing xy coord with const value """
379
+        sz = (1024,256)
380
+
381
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY,
382
+                                pyrpn.const.RESULT_CONST,
383
+                                sz, (42,))
384
+        
385
+        rif['X'] = 'A0 A1 +'
386
+        rif['Y'] = 'A2'
387
+
388
+        pos = rif.step(0)
389
+        self.assertEqual(pos, 0)
390
+
391
+        pos = rif.step(0)
392
+        self.assertEqual(rif.from_pos(pos), (0,42))
393
+
394
+        pos = rif.step(rif.to_pos(1,1))
395
+        self.assertEqual(rif.from_pos(pos), (2,0))
396
+
397
+        pos = rif.step(rif.to_pos(1,1))
398
+        self.assertEqual(rif.from_pos(pos), (2,0))
399
+
400
+        pos = rif.step(rif.to_pos(2,0))
401
+        self.assertEqual(rif.from_pos(pos), (2,42))
402
+
403
+    def test_random_xy_const(self):
404
+        """ Testing xy coord with const with random expressions """
405
+        for _ in Progress(200):
406
+            const_val = random.randint(0,0xFFFF)
407
+            rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XY,
408
+                                    pyrpn.const.RESULT_CONST,
409
+                                    (1024,1024,), (const_val,))
410
+            rif['X'].mutate(n_mutations=random.randint(10,100))
411
+            rif['Y'].mutate(n_mutations=random.randint(10,100))
412
+            pos=0
413
+            all_pos=[]
414
+            for  _ in range(100):
415
+                sys.stdout.flush()
416
+                pos = rif.step(pos)
417
+                all_pos.append(pos)
418
+                data = np.frombuffer(rif, dtype=np.uint64)
419
+                self.assertEqual(data[pos], const_val)
420
+            expt = np.zeros(len(data), dtype=np.uint64)
421
+            for p in all_pos:
422
+                expt[p] = const_val
423
+            self.assertTrue((expt == data).all())
424
+
425
+    def test_simple_xdim_const(self):
426
+        """ Testing xdim coord with const """
427
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_XDIM,
428
+                                pyrpn.const.RESULT_CONST,
429
+                                (4,100,200,300,400), (42,))
430
+        rif['D0'] = 'A1'
431
+        rif['D1'] = 'A0 A2 +'
432
+        rif['D2'] = 'A0 A1 -'
433
+        rif['D3'] = 'A3 A4 +'
434
+
435
+        pos = rif.step(0)
436
+        self.assertEqual(pos, 0)
437
+        pos = rif.step(0)
438
+        self.assertEqual(rif.from_pos(pos), (0,0,0,42))
439
+
440
+        pos = rif.step(5)
441
+        self.assertEqual(rif.from_pos(pos), (0,5,5,0))
442
+        pos = rif.step(rif.to_pos(0,5,5,0))
443
+        self.assertEqual(rif.from_pos(pos), (5,5,(-5%(1<<64))%300,42))
444
+        expt = (5,5,-5,42)
445
+        expt_pos = rif.to_pos(*expt)
446
+        self.assertEqual(pos, expt_pos)
447
+
448
+
449
+
174 450
 if __name__ == '__main__':
175 451
     unittest.main()
176 452
 

+ 1
- 1
tests/tests_rpniter_seq.py View File

@@ -26,7 +26,7 @@ import unittest
26 26
 
27 27
 try:
28 28
     import pyrpn
29
-except (importerror, nameerror) as e:
29
+except (ImportError, NameError) as e:
30 30
     print("error importing pyrpn. try to run make.",
31 31
           file=sys.stderr)
32 32
     raise e

+ 1
- 1
tests/tests_tokens.py View File

@@ -23,7 +23,7 @@ import unittest
23 23
 
24 24
 try:
25 25
     import pyrpn
26
-except (importerror, nameerror) as e:
26
+except (ImportError, NameError) as e:
27 27
     print("error importing pyrpn. try to run make.",
28 28
           file=sys.stderr)
29 29
     raise e

+ 81
- 0
tests/utils.py View File

@@ -0,0 +1,81 @@
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 sys
21
+import math
22
+
23
+try:
24
+    import pyrpn
25
+except (ImportError, NameError) as e:
26
+    print("error importing pyrpn. try to run make.",
27
+          file=sys.stderr)
28
+    raise e
29
+
30
+
31
+VERBOSE = '-v' in sys.argv or '--verbose' in sys.argv
32
+
33
+class Progress:
34
+
35
+    STYLE = '|/-\\'
36
+
37
+    def __init__(self, iterator, count=None):
38
+        if isinstance(iterator, int):
39
+            self.__iter = range(iterator)
40
+            self.__count = iterator
41
+        else:
42
+            self.__iter = iterator
43
+            try:
44
+                self.__count = len(iterator) if count is None else count
45
+            except Exception:
46
+                self.__count = None
47
+        self.__iter = iter(self.__iter)
48
+
49
+        self.__cur = 0
50
+        if self.__count is not None:
51
+            count_sz = math.floor(math.log10(self.__count)+1)
52
+            self.__fmt = '%%%dd/%%%dd' % (count_sz, count_sz)
53
+    
54
+    def __iter__(self):
55
+        return self
56
+
57
+    def __next__(self):
58
+        return self.next()
59
+
60
+    def next(self):
61
+        if not VERBOSE or self.__count is None:
62
+            clean_len = 1
63
+            if VERBOSE and self.__count == 0:
64
+                sys.stderr.write('\b')
65
+            sys.stderr.write(self.STYLE[self.__cur%len(self.STYLE)])
66
+            sys.stderr.write('\b')
67
+        else:
68
+            msg = self.__fmt % (self.__cur+1, self.__count)
69
+            clean_len = len(msg)
70
+            msg += '\b' * clean_len
71
+            sys.stderr.write(msg)
72
+        sys.stderr.flush()
73
+        self.__cur += 1
74
+        try:
75
+            return next(self.__iter)
76
+        except Exception as expt:
77
+            sys.stderr.write(' '*clean_len + '\b'  *  clean_len)
78
+            raise expt
79
+
80
+
81
+

Loading…
Cancel
Save