1
+ /**
2
+ * This file is part of cryptator, https://github.com/arnaud-m/cryptator
3
+ *
4
+ * Copyright (c) 2022, Université Côte d'Azur. All rights reserved.
5
+ *
6
+ * Licensed under the BSD 3-clause license.
7
+ * See LICENSE file in the project root for full license information.
8
+ */
9
+ package cryptator .gen ;
10
+
11
+ import java .util .Arrays ;
12
+ import java .util .Collection ;
13
+ import java .util .function .BinaryOperator ;
14
+ import java .util .stream .Collectors ;
15
+ import java .util .stream .IntStream ;
16
+ import java .util .stream .Stream ;
17
+
18
+ import org .chocosolver .solver .Model ;
19
+ import org .chocosolver .solver .variables .BoolVar ;
20
+ import org .chocosolver .solver .variables .IntVar ;
21
+
22
+ import cryptator .CryptaOperator ;
23
+ import cryptator .specs .ICryptaGenModel ;
24
+ import cryptator .specs .ICryptaNode ;
25
+ import cryptator .tree .CryptaConstant ;
26
+ import cryptator .tree .CryptaLeaf ;
27
+ import cryptator .tree .CryptaNode ;
28
+ import cryptator .tree .TreeUtils ;
29
+
30
+ /**
31
+ * Base class for generation model..
32
+ */
33
+ class CryptaGenBaseModel implements ICryptaGenModel {
34
+
35
+
36
+ /** The model. */
37
+ protected final Model model ;
38
+
39
+ /** The word array . */
40
+ protected final String [] words ;
41
+
42
+ /** The word variables that indicates if the word is present. */
43
+ protected final BoolVar [] vwords ;
44
+
45
+ /** The word count. */
46
+ protected final IntVar wordCount ;
47
+
48
+ /** The maximum length of a present word. */
49
+ protected final IntVar maxLength ;
50
+
51
+ public CryptaGenBaseModel (Model model , String [] words , String prefix , boolean boundedDomain ) {
52
+ super ();
53
+ this .model = model ;
54
+ this .words = words ;
55
+ this .vwords = buildWordVars (model , words , prefix );
56
+ this .wordCount = model .intVar (prefix + "wordCount" , 0 , words .length );
57
+ this .maxLength = model .intVar (prefix + "maxLength" , 0 , getMaxLength (words ), boundedDomain );
58
+ }
59
+
60
+ @ Override
61
+ public final Model getModel () {
62
+ return model ;
63
+ }
64
+
65
+ @ Override
66
+ public final String [] getWords () {
67
+ return words ;
68
+ }
69
+
70
+ @ Override
71
+ public final BoolVar [] getWordVars () {
72
+ return vwords ;
73
+ }
74
+
75
+ @ Override
76
+ public final IntVar getWordCount () {
77
+ return wordCount ;
78
+ }
79
+
80
+ @ Override
81
+ public final IntVar getMaxLength () {
82
+ return maxLength ;
83
+ }
84
+
85
+ /**
86
+ * Builds named boolean variables associated to the words.
87
+ *
88
+ * @param model the model
89
+ * @param words the words list
90
+ * @param prefix the prefix for the variable names
91
+ * @return the array of boolean variables
92
+ */
93
+ private static BoolVar [] buildWordVars (Model model , String [] words , String prefix ) {
94
+ final BoolVar [] vars = new BoolVar [words .length ];
95
+ for (int i = 0 ; i < words .length ; i ++) {
96
+ vars [i ] = model .boolVar (prefix + words [i ]);
97
+ }
98
+ return vars ;
99
+ }
100
+
101
+ protected void postWordCountConstraint () {
102
+ model .sum (vwords , "=" , wordCount ).post ();
103
+ }
104
+
105
+ protected void postMaxLengthConstraints () {
106
+ maxLength .eq (0 ).decompose ().post ();
107
+ }
108
+
109
+ @ Override
110
+ public void buildModel () {
111
+ postWordCountConstraint ();
112
+ postMaxLengthConstraints ();
113
+ }
114
+
115
+ public static int [] getLengths (String [] words ) {
116
+ return Arrays .stream (words ).mapToInt (String ::length ).toArray ();
117
+ }
118
+
119
+ public static int getMaxLength (String [] words ) {
120
+ return Arrays .stream (words ).mapToInt (String ::length ).max ().orElse (0 );
121
+ }
122
+
123
+ public static int [] getLengthCounts (String [] words ) {
124
+ final int n = getMaxLength (words );
125
+ int [] v = new int [n + 1 ];
126
+ for (String w : words ) {
127
+ v [w .length ()]++;
128
+ }
129
+ return v ;
130
+ }
131
+
132
+ public static BoolVar [] toArray (Collection <BoolVar > vars ) {
133
+ return vars .toArray (new BoolVar [vars .size ()]);
134
+ }
135
+
136
+ public static Stream <String > wordStream (ICryptaGenModel model ) {
137
+ final BoolVar [] v = model .getWordVars ();
138
+ final String [] w = model .getWords ();
139
+ return IntStream .range (0 , model .getN ())
140
+ .filter (i -> v [i ].isInstantiatedTo (1 ))
141
+ .mapToObj (i -> w [i ]);
142
+ }
143
+
144
+ public static String recordString (ICryptaGenModel model , String separator ) {
145
+ return wordStream (model ).collect ( Collectors .joining (separator ) );
146
+ }
147
+
148
+ public static ICryptaNode recordAddition (ICryptaGenModel model ) {
149
+ BinaryOperator <ICryptaNode > add = (a , b ) -> {
150
+ return a == null ? b : new CryptaNode (CryptaOperator .ADD , a , b );
151
+ };
152
+ return wordStream (model )
153
+ .map (CryptaLeaf ::new )
154
+ .map (ICryptaNode .class ::cast )
155
+ .reduce (null , add );
156
+ }
157
+
158
+
159
+ @ Override
160
+ public String toString () {
161
+ return recordString (this , " + " );
162
+ }
163
+
164
+ }
0 commit comments