1 | :- multifile generate/2. | |
2 | ||
3 | % shrinking of all mutations defined in mutation.pl | |
4 | ||
5 | :- use_module(library(lists),[is_list/1,maplist/2]). | |
6 | :- use_module(library(random),[random_permutation/2,random_member/2,random/3]). | |
7 | :- use_module(library(clpfd)). | |
8 | ||
9 | % ProB ast integer expressions | |
10 | generate(mutation(Expression:prob_ast_int_expr),NewExpression) :- | |
11 | \+is_list(Expression) , | |
12 | random_int_expr_mutation(Expression,NewExpression). | |
13 | % mutation of a list of integer expressions | |
14 | generate(mutation(Expressions:prob_ast_int_expr),NewExpression) :- | |
15 | % well-definedness problem with concatenation using div and modulo, division by zero | |
16 | % power_of also deprecated because of integer overflow | |
17 | concatenate_ast(Expressions,[add,minus,multiplication],Expression) , | |
18 | random_int_expr_mutation(Expression,NewExpression). | |
19 | ||
20 | % randomly replaces ground integer ast nodes with a matching | |
21 | % integer expression | |
22 | ||
23 | % leaves | |
24 | random_int_expr_mutation(Node,Mutation) :- | |
25 | prob_is_ground(Node,Res) , Res = true , | |
26 | replace_ground_with_expr(Node,Mutation). | |
27 | ||
28 | % two argument expressions | |
29 | random_int_expr_mutation(b(Expression,integer,Info),b(NewExpression,integer,Info)) :- | |
30 | Expression =.. [Type,Expr1,Expr2] , | |
31 | member(Type,[add,minus,multiplication,div,modulo,power_of]) , | |
32 | % random choice heuristic for argument | |
33 | random(0,3,R) , | |
34 | % if expression is ground replace its value by an arithmetic expression | |
35 | random_int_expr_mutation_aux(R,Expr1,Expr2,NewExpr1,NewExpr2) , | |
36 | NewExpression =.. [Type,NewExpr1,NewExpr2]. | |
37 | random_int_expr_mutation(b(Expression,integer,Info),b(NewExpression,integer,Info)) :- | |
38 | Expression =.. [Type,Expr1,Expr2] , | |
39 | random_int_expr_mutation(Expr1,NewExpr1) , | |
40 | random_int_expr_mutation(Expr2,NewExpr2) , | |
41 | NewExpression =.. [Type,NewExpr1,NewExpr2]. | |
42 | ||
43 | % one argument expressions | |
44 | random_int_expr_mutation(b(Expression,integer,Info),b(NewExpression,integer,Info)) :- | |
45 | Expression =.. [Type,_] , | |
46 | \+member(Type,[max,min]) , | |
47 | (prob_is_ground(b(Expression,integer,Info),true) | |
48 | -> replace_ground_with_expr(b(Expression,integer,Info),NewExpr) | |
49 | ; random_int_expr_mutation(b(Expression,integer,Info),NewExpr)) , | |
50 | NewExpression =.. [Type,NewExpr]. | |
51 | % no mutation for max_int, min_int, max, min or identifier | |
52 | random_int_expr_mutation(Expression,Expression). | |
53 | ||
54 | % either mutate only one argument or both | |
55 | random_int_expr_mutation_aux(0,Expr1,Expr2,NewExpr1,Expr2) :- | |
56 | random_int_expr_mutation_aux2(Expr1,NewExpr1). | |
57 | random_int_expr_mutation_aux(1,Expr1,Expr2,Expr1,NewExpr2) :- | |
58 | random_int_expr_mutation_aux2(Expr2,NewExpr2). | |
59 | random_int_expr_mutation_aux(2,Expr1,Expr2,NewExpr1,NewExpr2) :- | |
60 | random_int_expr_mutation_aux2(Expr1,NewExpr1) , | |
61 | random_int_expr_mutation_aux2(Expr2,NewExpr2). | |
62 | random_int_expr_mutation_aux2(Expr,NewExpr) :- | |
63 | prob_is_ground(Expr,Res) , Res = true , ! , | |
64 | replace_ground_with_expr(Expr,NewExpr). | |
65 | random_int_expr_mutation_aux2(Expr,NewExpr) :- | |
66 | random_int_expr_mutation(Expr,NewExpr). | |
67 | ||
68 | % replace ground value with an integer expression | |
69 | replace_ground_with_expr(b(unary_minus(Integer),integer,[]),NewExpr) :- | |
70 | replace_ground_with_expr(Integer,TempNewExpr) , | |
71 | NewExpr = b(multiplication(b(unary_minus(b(integer(1),integer,[])),integer,[]),TempNewExpr),integer,[]). | |
72 | replace_ground_with_expr(b(integer(Value),integer,Info),NewExpr) :- | |
73 | find_expr_clpfd(Value,Expr) , ! , | |
74 | % random choice of further mutation | |
75 | random(0,10,R) , | |
76 | (R < 3 | |
77 | -> NewExpr = b(Expr,integer,Info) | |
78 | ; random_int_expr_mutation(b(Expr,integer,Info),NewExpr)). | |
79 | ||
80 | % evaluate an expression using clpfd labeling to mutate a specific value | |
81 | find_expr_clpfd(Value,Expr) :- | |
82 | Val1 in -100000..100000 , | |
83 | Val2 in -100000..100000 , | |
84 | random_member(Operator,[add,minus,multiplication]) , % power_of, modulo, div | |
85 | find_expr_aux_operator(Operator,Val1,Val2,Value) , | |
86 | labeling([],[Val1,Val2]) , | |
87 | Expr =.. [Operator,b(integer(Val1),integer,[]),b(integer(Val2),integer,[])]. | |
88 | % if labeling failed try another expression | |
89 | find_expr_clpfd(Value,Expr) :- | |
90 | find_expr_clpfd(Value,Expr). | |
91 | ||
92 | find_expr_aux_operator(add,Val1,Val2,Value) :- | |
93 | Val1 + Val2 #= Value. | |
94 | find_expr_aux_operator(minus,Val1,Val2,Value) :- | |
95 | Val1 - Val2 #= Value. | |
96 | find_expr_aux_operator(div,Val1,Val2,Value) :- | |
97 | Val2 #\= 0 , | |
98 | Val1 div Val2 #= Value. | |
99 | find_expr_aux_operator(modulo,Val1,Val2,Value) :- | |
100 | Val1 in 1..100000 , | |
101 | Val2 in 1..100000 , % no negative numbers | |
102 | Val1 mod Val2 #= Value. | |
103 | find_expr_aux_operator(_,Val1,Val2,Value) :- | |
104 | Val1 * Val2 #= Value. |