Browse Source

Implements mutation & copy for rpnepxr

Yann Weber 1 year ago
parent
commit
3c593f2a04
4 changed files with 723 additions and 2 deletions
  1. 241
    2
      python_rpnexpr.c
  2. 32
    0
      python_rpnexpr.h
  3. 349
    0
      rpn_mutate.c
  4. 101
    0
      rpn_mutate.h

+ 241
- 2
python_rpnexpr.c View File

@@ -19,9 +19,15 @@
19 19
 #include "python_rpnexpr.h"
20 20
 
21 21
 PyMethodDef RPNExpr_methods[] = {
22
-	{"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"},
23 22
 	{"random", (PyCFunction)rpnexpr_random, METH_CLASS | METH_VARARGS | METH_KEYWORDS,
24 23
 		"Return a new random RPN expression string"},
24
+	{"default_mutation_params", (PyCFunction)rpnexpr_default_mutation_params,
25
+		METH_CLASS | METH_FASTCALL,
26
+		"Return the default mutation parameters"},
27
+	{"eval", (PyCFunction)rpnexpr_eval, METH_FASTCALL, "Evaluate an expression"},
28
+	{"mutate", (PyCFunction)rpnexpr_mutate,
29
+		METH_VARARGS | METH_KEYWORDS,
30
+		"Mutate an expression given an RPNMutationParamsTuple instance"},
25 31
 	{"reset_stack", (PyCFunction)rpnexpr_reset_stack, METH_NOARGS,
26 32
 		"Reset stack memory storage (set all items to 0)"},
27 33
 	{"__getstate__", (PyCFunction)rpnexpr_getstate, METH_NOARGS,
@@ -29,6 +35,8 @@ PyMethodDef RPNExpr_methods[] = {
29 35
 and the stack state."},
30 36
 	{"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O,
31 37
 		"Unpickling method"},
38
+	{"__copy__", (PyCFunction)rpnexpr_copy, METH_NOARGS,
39
+		"Clone method. Return a new cloned instance"},
32 40
 	{"uid", (PyCFunction)rpnexpr_getexprstate, METH_NOARGS,
33 41
 		"Return a base64 uid for expression"},
34 42
 	{NULL} //Sentinel
@@ -256,6 +264,7 @@ PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs)
256 264
 	Py_DECREF(comp);
257 265
 	return res;
258 266
 	*/
267
+	PyErr_SetString(PyExc_NotImplementedError, "Not implemented...");
259 268
 	return NULL;
260 269
 }
261 270
 
@@ -376,7 +385,7 @@ generating exception message !");
376 385
 	if(expr_self->rpn || expr_self->args) /* checking instance state */
377 386
 	{
378 387
 		PyErr_SetString(PyExc_ValueError,
379
-			"RPNExpr.__getstate__() instance in bad state : \
388
+			"RPNExpr.__setstate__() instance in bad state : \
380 389
 should not be initialized");
381 390
 		return NULL;
382 391
 	}
@@ -491,6 +500,35 @@ args buffer : %s",
491 500
 		return NULL;
492 501
 }
493 502
 
503
+
504
+PyObject* rpnexpr_copy(PyObject *self, PyObject *noargs)
505
+{
506
+	PyRPNExpr_t *copy;
507
+	PyObject *ret, *state, *setret;
508
+
509
+	ret = PyObject_CallMethod((PyObject*)&RPNExprType, "__new__", "O", &RPNExprType);
510
+	copy = (PyRPNExpr_t*)ret;
511
+
512
+	state = PyObject_CallMethod(self, "__getstate__", NULL);
513
+	if(PyErr_Occurred()) {
514
+		goto err;
515
+	}
516
+	setret = PyObject_CallMethod(ret, "__setstate__", "O", state);
517
+	if(PyErr_Occurred()) {
518
+		Py_DECREF(state);
519
+		goto err;
520
+	}
521
+
522
+	Py_DECREF(state);
523
+	Py_DECREF(setret);
524
+
525
+	return ret;
526
+err:
527
+	PyObject_Del(copy);
528
+	return NULL;
529
+}
530
+
531
+
494 532
 PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
495 533
 {
496 534
 	PyRPNExpr_t *expr_self;
@@ -536,6 +574,52 @@ PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc)
536 574
 	return PyLong_FromUnsignedLong(res);
537 575
 }
538 576
 
577
+
578
+PyObject* rpnexpr_mutate(PyObject* slf, PyObject *args, PyObject *kwds)
579
+{
580
+	PyRPNExpr_t *self = (PyRPNExpr_t*)slf;
581
+
582
+	char *str_args = "|OI:RPNIterExpr.mutate";
583
+	char *names[] = {"params", "n_mutations", NULL};
584
+
585
+	PyObject *py_params = NULL;
586
+	unsigned int n_mutations = 1;
587
+	rpn_mutation_params_t params;
588
+
589
+	if(!PyArg_ParseTupleAndKeywords(args, kwds, str_args, names,
590
+				&py_params, &n_mutations))
591
+	{
592
+		return NULL;
593
+	}
594
+
595
+	if(!py_params)
596
+	{
597
+		memcpy(&params, &rpn_mutation_params_default,
598
+				sizeof(rpn_mutation_params_t));
599
+	}
600
+	else
601
+	{
602
+		if(rpnexpr_pyobj_to_mutation_params(py_params, &params) < 0)
603
+		{
604
+			PyErr_SetString(PyExc_ValueError, "Bad value for params arguments");
605
+			return NULL;
606
+		}
607
+	}
608
+
609
+	for(size_t i=0; i<n_mutations; i++)
610
+	{
611
+		if(rpn_mutation(&(self->rpn->toks), &params) < 0)
612
+		{
613
+			PyErr_Format(PyExc_RuntimeError, "Mutation failed : %s",
614
+					strerror(errno));
615
+			return NULL;
616
+		}
617
+	}
618
+
619
+	rpn_expr_tokens_updated(self->rpn);
620
+	Py_RETURN_NONE;
621
+}
622
+
539 623
 PyObject* rpnexpr_reset_stack(PyObject *self, PyObject *noargs)
540 624
 {
541 625
 	rpn_expr_reset_stack(((PyRPNExpr_t*)self)->rpn);
@@ -608,3 +692,158 @@ PyObject* rpnexpr_random(PyObject *cls, PyObject *args, PyObject *kwds)
608 692
 	return res;
609 693
 }
610 694
 
695
+PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssize_t argc)
696
+{
697
+	PyObject *res, *wtypes;
698
+
699
+	if(!(wtypes = PyStructSequence_New(&rpn_token_types_SeqDesc)))
700
+	{
701
+		return NULL;
702
+	}
703
+
704
+	if(!(res = PyStructSequence_New(&rpn_mutation_params_SeqDesc)))
705
+	{
706
+		return NULL;
707
+	}
708
+
709
+	// wtypes filled with 1.0
710
+	PyObject *one = PyFloat_FromDouble(1.0);
711
+	for(size_t i=0; i<3; i++)
712
+	{
713
+		PyStructSequence_SET_ITEM(wtypes, i, one);
714
+	}
715
+
716
+
717
+	// max_len
718
+	PyStructSequence_SET_ITEM(res, 0,
719
+			PyLong_FromLong(rpn_mutation_params_default.min_len));
720
+	// weight_add
721
+	PyStructSequence_SET_ITEM(res, 1,
722
+			PyFloat_FromDouble(rpn_mutation_params_default.w_add));
723
+	// weight_del
724
+	PyStructSequence_SET_ITEM(res, 2,
725
+			PyFloat_FromDouble(rpn_mutation_params_default.w_del));
726
+	// weight_mut
727
+	PyStructSequence_SET_ITEM(res, 3,
728
+			PyFloat_FromDouble(rpn_mutation_params_default.w_mut));
729
+	// weight_mut_soft
730
+	PyStructSequence_SET_ITEM(res, 4,
731
+			PyFloat_FromDouble(rpn_mutation_params_default.w_mut_soft));
732
+
733
+	/** TODO use rpn_mutation_params_default instead of wtypes [1,1,1] */
734
+	// weight_add_elt
735
+	PyStructSequence_SET_ITEM(res, 5, wtypes);
736
+	Py_INCREF(wtypes);
737
+	// weight_mut_elt
738
+	PyStructSequence_SET_ITEM(res, 6, wtypes);
739
+	Py_INCREF(wtypes);
740
+
741
+	return res;
742
+
743
+}
744
+
745
+
746
+static inline void _parse_float(PyObject *obj, float *res)
747
+{
748
+	double tmp = PyFloat_AsDouble(obj);
749
+	if(tmp > FLT_MAX)
750
+	{
751
+		PyErr_SetString(PyExc_OverflowError, "Float overflows");
752
+		return;
753
+	}
754
+	*res=tmp;
755
+	return;
756
+}
757
+
758
+static inline void _parse_type_weights(PyObject *obj, float w[3])
759
+{
760
+	PyObject *fast = PySequence_Fast(obj, "Not a RPNTokenTypeTuple nor with a length of 3");
761
+	if(!fast) { return; }
762
+	if(PySequence_Length(obj) != 3)
763
+	{
764
+		PyErr_Format(PyExc_ValueError, "Excpected RPNTokenTypeTuple or 3 elements but got %d elements", PySequence_Length(obj));
765
+		return;
766
+	}
767
+
768
+	PyObject **elts = PySequence_Fast_ITEMS(fast);
769
+
770
+	const char* names[3] = {"op", "const", "var"};
771
+	for(size_t i=0; i<3; i++)
772
+	{
773
+		_parse_float(elts[i], &w[i]);
774
+		if(PyErr_Occurred())
775
+		{
776
+			PyErr_Format(PyExc_ValueError,
777
+					"Bad value for .%s field",
778
+					names[i]);
779
+			break;
780
+		}
781
+	}
782
+	return;
783
+}
784
+
785
+int rpnexpr_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params)
786
+{
787
+	if(!PySequence_Check(py_params))
788
+	{
789
+		PyErr_SetString(PyExc_TypeError, "The given object is not a a sequence");
790
+		return -1;
791
+	}
792
+	if(PySequence_Size(py_params) != 7)
793
+	{
794
+		PyErr_SetString(PyExc_ValueError, "The given object is not a RPNMutationParamsTuple nor of length 7");
795
+		return -1;
796
+	}
797
+	PyObject *fast = PySequence_Fast(py_params, "The given object is not a RPNMutationParamsTuple nor a sequence ?");
798
+	Py_INCREF(fast);
799
+
800
+	PyObject **elts = PySequence_Fast_ITEMS(fast);
801
+
802
+	params->min_len = PyLong_AsSize_t(elts[0]);
803
+	if(PyErr_Occurred())
804
+	{
805
+		PyErr_SetString(PyExc_ValueError, "Bad type for .minimum_length field");
806
+		return -1;
807
+	}
808
+
809
+	_parse_float(elts[1], &params->w_add);
810
+	if(PyErr_Occurred())
811
+	{
812
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add field");
813
+		return -1;
814
+	}
815
+	_parse_float(elts[2], &params->w_del);
816
+	if(PyErr_Occurred())
817
+	{
818
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_del field");
819
+		return -1;
820
+	}
821
+	_parse_float(elts[3], &params->w_mut);
822
+	if(PyErr_Occurred())
823
+	{
824
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_mut field");
825
+		return -1;
826
+	}
827
+	_parse_float(elts[4], &params->w_mut_soft);
828
+	if(PyErr_Occurred())
829
+	{
830
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_mut_soft field");
831
+		return -1;
832
+	}
833
+	
834
+	_parse_type_weights(elts[5], params->w_add_elt);
835
+	if(PyErr_Occurred())
836
+	{
837
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add_elt field");
838
+		return -1;
839
+	}
840
+
841
+	_parse_type_weights(elts[6], params->w_mut_elt);
842
+	if(PyErr_Occurred())
843
+	{
844
+		PyErr_SetString(PyExc_ValueError, "Bad value for .weight_add_elt field");
845
+		return -1;
846
+	}
847
+	return 0;
848
+}
849
+

+ 32
- 0
python_rpnexpr.h View File

@@ -22,12 +22,14 @@
22 22
 #include "config.h"
23 23
 
24 24
 #include <errno.h>
25
+#include <float.h>
25 26
 
26 27
 #define PY_SSIZE_T_CLEAN
27 28
 #include <Python.h>
28 29
 #include "structmember.h"
29 30
 
30 31
 #include "rpn_jit.h"
32
+#include "python_const.h"
31 33
 
32 34
 /**@defgroup python_type RPNExpr Python class
33 35
  * @brief Exposed Python class : RPNExpr
@@ -134,6 +136,14 @@ PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs);
134 136
  */
135 137
 PyObject* rpnexpr_setstate(PyObject *cls, PyObject *state);
136 138
 
139
+/**@brief RPNExpr __copy__ method for cloning
140
+ * @param self RPNExpr instance
141
+ * @param noargs Not an argument...
142
+ * @return A new cloned instance
143
+ * @ref rpnexpr_setstate
144
+ */
145
+PyObject* rpnexpr_copy(PyObject *cls, PyObject *noargs);
146
+
137 147
 /**@brief Eval an RPN expression given arguments and return the
138 148
  * value
139 149
  * @param self RPNExpr instance
@@ -144,6 +154,13 @@ PyObject* rpnexpr_setstate(PyObject *cls, PyObject *state);
144 154
  */
145 155
 PyObject* rpnexpr_eval(PyObject* self, PyObject** argv, Py_ssize_t argc);
146 156
 
157
+/**@brief Mutate an RPN expression given arguments and return the value
158
+ * @param PyObject* RPNExpr instance
159
+ * @param PyObject* Positionnal arguments
160
+ * @param PyObject* Keyword arguments
161
+ */
162
+PyObject* rpnexpr_mutate(PyObject* self, PyObject *args, PyObject *kwds);
163
+
147 164
 /**@brief Set all stack item to zero
148 165
  * @param self RPNExpr instance
149 166
  * @param noargs Dummy argument for METH_NOARG
@@ -172,4 +189,19 @@ PyObject* rpnexpr_str(PyObject *self);
172 189
  */
173 190
 PyObject* rpnexpr_random(PyObject *cls, PyObject *args, PyObject *kwds);
174 191
 
192
+/**@brief Return a new named tuple containing default mutation parameters
193
+ * @param PyObject* The class (class method)
194
+ * @param PyObject** The arguments (FASTCALL)
195
+ * @param Py_ssize_t The number of arguments
196
+ * @return The named tuple
197
+ */
198
+PyObject* rpnexpr_default_mutation_params(PyObject *cls, PyObject **argv, Py_ssize_t argc);
199
+
200
+/**@brief Try to convert a python object into a rpn_mutation_params_t
201
+ * @param PyObject* The python object
202
+ * @param rpn_mutation_params_t A pointer on the parameters to initialize
203
+ * @return -1 on failure and raise an exception
204
+ */
205
+int rpnexpr_pyobj_to_mutation_params(PyObject* py_params, rpn_mutation_params_t *params);
206
+
175 207
 #endif

+ 349
- 0
rpn_mutate.c View File

@@ -0,0 +1,349 @@
1
+#include "rpn_mutate.h"
2
+
3
+const rnd_t rnd_t_max = -1;
4
+
5
+const rpn_mutation_params_t rpn_default_mutation = {
6
+	.min_len = 3,
7
+	.w_add = 1.25,
8
+	.w_del = 1.0,
9
+	.w_mut = 2.0,
10
+	.w_mut_soft = 4.0,
11
+	.w_add_elt = {1,1,1},
12
+	.w_mut_elt={1,1,1},
13
+};
14
+
15
+#define to_weight(total, elt) ((rnd_t)((((long double)elt)*rnd_t_max)/total))
16
+int rpn_mutation_init_params(rpn_mutation_params_t *params)
17
+{
18
+	long double total;
19
+
20
+	if(params->w_add < 0) { goto err; }
21
+	if(params->w_del < 0) { goto err; }
22
+	if(params->w_mut < 0) { goto err; }
23
+	if(params->w_mut_soft < 0) { goto err; }
24
+
25
+	total = params->w_add + params->w_del + params->w_mut + params->w_mut_soft;
26
+	params->_weights[0] = to_weight(total, params->w_add);
27
+	params->_weights[1] = to_weight(total, params->w_del);
28
+	params->_weights[2] = to_weight(total, params->w_mut);
29
+	params->_weights[3] = to_weight(total, params->w_mut_soft);
30
+#ifdef DEBUG
31
+dprintf(2, "weights : %d %d %d %d\n",
32
+		params->_weights[0],
33
+		params->_weights[1],
34
+		params->_weights[2],
35
+		params->_weights[3]);
36
+#endif
37
+	for(uint8_t i=1; i<4; i++)
38
+	{
39
+		params->_weights[i] += params->_weights[i-1];
40
+	}
41
+#ifdef DEBUG
42
+dprintf(2, "summed weights : %d %d %d %d\n",
43
+		params->_weights[0],
44
+		params->_weights[1],
45
+		params->_weights[2],
46
+		params->_weights[3]);
47
+#endif
48
+
49
+	total = 0;
50
+	for(uint8_t i=0; i<3; i++)
51
+	{
52
+		if(params->w_add_elt[i] < 0) { goto err; }
53
+		total += params->w_add_elt[i];
54
+	}
55
+	for(uint8_t i=0; i<3; i++)
56
+	{
57
+		params->_weights[i+4] = to_weight(total, params->w_add_elt[i]);
58
+		if(i>0)
59
+		{
60
+			params->_weights[i+4] += params->_weights[i+3];
61
+		}
62
+	}
63
+
64
+	total = 0;
65
+	for(uint8_t i=0; i<3; i++)
66
+	{
67
+		if(params->w_mut_elt[i] < 0) { goto err; }
68
+		total += params->w_mut_elt[i];
69
+	}
70
+	for(uint8_t i=0; i<3; i++)
71
+	{
72
+		params->_weights[i+7] = to_weight(total, params->w_mut_elt[i]);
73
+		if(i>0)
74
+		{
75
+			params->_weights[i+7] += params->_weights[i+6];
76
+		}
77
+	}
78
+
79
+	return 0;
80
+err:
81
+	errno = EINVAL;
82
+	return -1;
83
+}
84
+#undef to_weight
85
+
86
+int rpn_mutation(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
87
+{
88
+	assert(toks->argc < rnd_t_max);
89
+
90
+	if(toks->tokens_sz <= params->min_len)
91
+	{
92
+		return rpn_mutation_add(toks, params);
93
+	}
94
+	size_t choice;
95
+	if(_rpn_random_choice(4, params->_weights, &choice) < 0)
96
+	{
97
+		return -1;
98
+	}
99
+	switch(choice)
100
+	{
101
+		case 0:
102
+			return rpn_mutation_add(toks, params);
103
+		case 1:
104
+			return rpn_mutation_del(toks, params);
105
+		case 2:
106
+			return rpn_mutation_mut(toks, params);
107
+		case 3:
108
+			return rpn_mutation_mut_soft(toks, params);
109
+		default:
110
+			dprintf(2, "Random error that should never occurs");
111
+			return -1;
112
+	}
113
+	
114
+}
115
+int rpn_mutation_add(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
116
+{
117
+	rpn_token_t *new_toks, new_token;
118
+	size_t position;
119
+
120
+	if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0)
121
+	{
122
+		return -1;
123
+	}
124
+	
125
+	if(rpn_random_token_type(&(new_token.type), &params->_weights[4]) < 0)
126
+	{
127
+		return -1;
128
+	}
129
+	if(rpn_mutation_random_token(&new_token, toks, params) < 0)
130
+	{
131
+		return -1;
132
+	}
133
+
134
+	toks->tokens_sz++;
135
+	new_toks = realloc(toks->tokens, sizeof(rpn_token_t) * toks->tokens_sz);
136
+	if(!new_toks)
137
+	{
138
+		toks->tokens_sz--;
139
+		return -1;
140
+	}
141
+	toks->tokens = new_toks;
142
+
143
+	if(position < toks->tokens_sz - 1)
144
+	{
145
+		memmove(&(toks->tokens[position+1]), &(toks->tokens[position]),
146
+				sizeof(rpn_token_t) * ((toks->tokens_sz-1) - position));
147
+	}
148
+	memcpy(&toks->tokens[position], &new_token, sizeof(rpn_token_t));
149
+
150
+	return 0;
151
+}
152
+int rpn_mutation_del(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
153
+{
154
+	rpn_token_t *new_toks;
155
+	size_t position;
156
+
157
+	if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0)
158
+	{
159
+		return -1;
160
+	}
161
+
162
+	if(position != toks->tokens_sz - 1)
163
+	{
164
+		memmove(&(toks->tokens[position]), &(toks->tokens[position+1]),
165
+				sizeof(rpn_token_t) * ((toks->tokens_sz - 1) - position));
166
+	}
167
+	toks->tokens_sz--;
168
+	new_toks = realloc(toks->tokens, sizeof(rpn_token_t) * toks->tokens_sz);
169
+	if(!new_toks)
170
+	{
171
+		toks->tokens_sz = 0;
172
+		toks->tokens = NULL;
173
+		return -1;
174
+	}
175
+	toks->tokens = new_toks;
176
+	return 0;
177
+}
178
+int rpn_mutation_mut(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
179
+{
180
+	rpn_token_t *tok;
181
+	size_t position;
182
+
183
+	if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0)
184
+	{
185
+		return -1;
186
+	}
187
+
188
+	tok = &toks->tokens[position];
189
+
190
+	if(rpn_random_token_type(&(tok->type), &(params->_weights[7])) < 0)
191
+	{
192
+		return -1;
193
+	}
194
+	if(rpn_mutation_random_token(tok, toks, params) < 0)
195
+	{
196
+		return -1;
197
+	}
198
+
199
+	return 0;
200
+}
201
+int rpn_mutation_mut_soft(rpn_tokenized_t *toks, rpn_mutation_params_t *params)
202
+{
203
+	rpn_token_t *tok;
204
+	size_t position;
205
+
206
+	if(rpn_rand_limit(toks->tokens_sz-1, &position) < 0)
207
+	{
208
+		return -1;
209
+	}
210
+
211
+	tok = &(toks->tokens[position]);
212
+
213
+	if(rpn_mutation_random_token(tok, toks, params) < 0)
214
+	{
215
+		return -1;
216
+	}
217
+
218
+	return 0;
219
+}
220
+
221
+
222
+int rpn_mutation_random_token(rpn_token_t *tok,
223
+		rpn_tokenized_t *toks, rpn_mutation_params_t *params)
224
+{
225
+	rnd_t rand;
226
+
227
+	if(rpn_getrandom(&rand) < 0)
228
+	{
229
+		return  -1;
230
+	}
231
+
232
+	unsigned char op_n;
233
+	unsigned char *val;
234
+	size_t left;
235
+	switch(tok->type)
236
+	{
237
+		case RPN_op:
238
+			op_n = rand / (rnd_t_max/RPN_OP_SZ);
239
+			op_n %= RPN_OP_SZ;
240
+			tok->op_n = op_n;
241
+			tok->op = &(rpn_ops[op_n]);
242
+			break;
243
+
244
+		case RPN_arg:
245
+			tok->arg_n = rand / (rnd_t_max/toks->argc);
246
+			tok->arg_n %= toks->argc;
247
+			break;
248
+		case RPN_val:
249
+			val =(unsigned char*)&(tok->value);
250
+			left = sizeof(tok->value);
251
+			do
252
+			{
253
+				ssize_t ret = getrandom(val, left, GRND_NONBLOCK);
254
+				if(ret == -1)
255
+				{
256
+					if(errno == EAGAIN || errno == EINTR)
257
+					{
258
+						continue;
259
+					}
260
+					return -1;
261
+				}
262
+				left -= ret;
263
+				val += ret;
264
+			}while(left);
265
+			break;
266
+		default:
267
+			dprintf(2, "Another random error that shouldn't occur\n");
268
+			return -1;
269
+	}
270
+	return 0;
271
+}
272
+
273
+
274
+int rpn_random_token_type(rpn_token_type_t *type, rnd_t *weights)
275
+{
276
+	const rpn_token_type_t types[3]  = { RPN_op, RPN_arg, RPN_val };
277
+	size_t choice;
278
+
279
+	if(_rpn_random_choice(3, weights, &choice) < 0)
280
+	{
281
+		return -1;
282
+	}
283
+	*type = types[choice];
284
+	return 0;
285
+}
286
+
287
+int rpn_getrandom(rnd_t *rand)
288
+{
289
+	rnd_t seed;
290
+	char *seed_ptr = (char*)&seed;
291
+	size_t buflen = sizeof(seed);
292
+
293
+	do
294
+	{
295
+		ssize_t ret = getrandom(seed_ptr, buflen, GRND_NONBLOCK);
296
+		if(ret == -1)
297
+		{
298
+			if(errno == EAGAIN || errno == EINTR)
299
+			{
300
+				continue;
301
+			}
302
+			return -1;
303
+		}
304
+		buflen -= ret;
305
+		seed_ptr += ret;
306
+	}while(buflen);
307
+	*rand = seed;
308
+	return 0;
309
+}
310
+
311
+int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res)
312
+{
313
+	rnd_t rand;
314
+	if(rpn_getrandom(&rand) < 0) { return -1; }
315
+	__rpn_random_choice(sz, weights, rand, res);
316
+	return 0;
317
+}
318
+
319
+void __rpn_random_choice(size_t sz, rnd_t *weights, rnd_t rand, size_t *res)
320
+{
321
+	for(*res=0; *res<sz; (*res)++)
322
+	{
323
+		if(weights[*res] >= rand)
324
+		{
325
+			return;
326
+		}
327
+	}
328
+	*res = sz-1;
329
+}
330
+
331
+int rpn_rand_limit(size_t max, size_t *res)
332
+{
333
+	unsigned long int step = rnd_t_max / max;
334
+	rnd_t rnd;
335
+
336
+	if(rpn_getrandom(&rnd) < 0)
337
+	{
338
+		return -1;
339
+	}
340
+	for(*res=0; *res<max; (*res)++)
341
+	{
342
+		if(*res * step >= rnd)
343
+		{
344
+			return 0;
345
+		}
346
+	}
347
+	//*res = max - 1;
348
+	return 0;
349
+}

+ 101
- 0
rpn_mutate.h View File

@@ -0,0 +1,101 @@
1
+/*
2
+ * Copyright (C) 2020,2023 Weber Yann
3
+ * 
4
+ * This file is part of pyrpn.
5
+ * 
6
+ * pyrpn 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
+ * any later version.
10
+ * 
11
+ * pyrpn 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 pyrpn.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+#ifndef __rpn_mutate__h__
20
+#define __rpn_mutate__h__
21
+#include "config.h"
22
+
23
+#include <assert.h>
24
+#include <errno.h>
25
+#include <stdint.h>
26
+#include <sys/random.h>
27
+
28
+#include "rpn_parse.h"
29
+
30
+typedef struct rpn_mutation_params_s rpn_mutation_params_t;
31
+typedef uint16_t rnd_t;
32
+
33
+
34
+struct rpn_mutation_params_s
35
+{
36
+	/**@brief Minimum expression length  */
37
+	size_t min_len;
38
+	/**@brief Weight of adding a token*/
39
+	float w_add;
40
+	/**@brief Weight of deleting a token*/
41
+	float w_del;
42
+	/**@brief Weight of mutating a token*/
43
+	float w_mut;
44
+	/**@brief Weight of mutating a token without type change*/
45
+	float w_mut_soft;
46
+	/**@brief Weight for each token types (op, const, var) when
47
+	 * adding a token*/
48
+	float w_add_elt[3];
49
+	/**@brief Weight for each token types (op, const, var) when
50
+	 * mutating a token*/
51
+	float w_mut_elt[3];
52
+
53
+	/**@brief For internal use, set by @ref rpn_mutation_init_params
54
+	 *
55
+	 * weight reported by groups on rnd_t integers
56
+	 * - [0..3] -> weights mutation
57
+	 * - [4..6] -> w_add_elt
58
+	 * - [7..9] -> w_mut_elt
59
+	 */
60
+	rnd_t  _weights[10];
61
+};
62
+
63
+/**@brief Initialize mutation parameters 
64
+ *
65
+ * pre-process integers threshold by group
66
+ * @param rpn_mutation_params_t*
67
+ * @return 0 if no error else -1 and set ERRNO (EINVAL)
68
+ */
69
+int rpn_mutation_init_params(rpn_mutation_params_t *params);
70
+
71
+/**@brief Mutate a tokenized rpn expression */
72
+int rpn_mutation(rpn_tokenized_t *toks, rpn_mutation_params_t *params);
73
+int rpn_mutation_add(rpn_tokenized_t *toks, rpn_mutation_params_t *params);
74
+int rpn_mutation_del(rpn_tokenized_t *toks, rpn_mutation_params_t *params);
75
+int rpn_mutation_mut(rpn_tokenized_t *toks, rpn_mutation_params_t *params);
76
+int rpn_mutation_mut_soft(rpn_tokenized_t *toks, rpn_mutation_params_t *params);
77
+
78
+/**@brief Change the "value" of a token randomly not it's type */
79
+int rpn_mutation_random_token(rpn_token_t *tok,
80
+		rpn_tokenized_t *toks, rpn_mutation_params_t *params);
81
+
82
+
83
+/**@breif Choose a random token type
84
+ * @return -1 on error
85
+ */
86
+int rpn_random_token_type(rpn_token_type_t *type, rnd_t *weights);
87
+
88
+/**@param rnd_t* Is set to a random value
89
+ * @return -1 on error else 0 */
90
+int rpn_getrandom(rnd_t *rand);
91
+
92
+/**@param size_t Maximum value
93
+ * @param size_t* Will be set to a value between [..max[
94
+ * @return -1 on error else 0 */
95
+int rpn_rand_limit(size_t max, size_t *res);
96
+
97
+/**@briref Given a size return an element with regards to given weights */
98
+int _rpn_random_choice(size_t sz, rnd_t *weights, size_t *res);
99
+void __rpn_random_choice(size_t sz, rnd_t *weights, rnd_t rand, size_t *res);
100
+
101
+#endif

Loading…
Cancel
Save