1 |
On pon, 2017-06-05 at 19:24 +0200, Alexis Ballier wrote: |
2 |
> On Mon, 05 Jun 2017 16:10:25 +0200 |
3 |
> Michał Górny <mgorny@g.o> wrote: |
4 |
> |
5 |
> > On pon, 2017-06-05 at 09:55 +0200, Alexis Ballier wrote: |
6 |
> > > On Sun, 4 Jun 2017 10:59:38 +0200 |
7 |
> > > Alexis Ballier <aballier@g.o> wrote: |
8 |
> > > |
9 |
> > > > Here's a quick n dirty code to play with, based on yours: |
10 |
> > > > https://github.com/aballier/required-use |
11 |
> > > |
12 |
> > > I've run that on the whole tree (considering all ebuilds with non |
13 |
> > > empty REQUIRED_USE), some stats: |
14 |
> > > |
15 |
> > > $ time python3 classify.py requsel |
16 |
> > > Stats: |
17 |
> > > Parse error: 16 |
18 |
> > |
19 |
> > Hmm, how did you get those numbers? I just tested parsing and found |
20 |
> > only 7 unique REQUIRED_USE entries that fail. However, my sample file |
21 |
> > is only around 1000 entries long, so either I failed to get all of |
22 |
> > them, or you didn't deduplicate your list ;-). More on it below. |
23 |
> |
24 |
> I did not deduplicate anything. I took every single ebuild and |
25 |
> generated a list of req use out of it. Meaning if you had 10 ebuilds |
26 |
> for 1 package with the same req use that'd count as 10 above. |
27 |
> |
28 |
> [...] |
29 |
> > > The cycle is mostly due to: |
30 |
> > > $ python3 nsolve.py 'llvm? ( gallium ) gallium? ( llvm )' |
31 |
> > > [...] |
32 |
> > > toposort.CircularDependencyError: Circular dependencies exist among |
33 |
> > > these items: {[gallium]? => [llvm]:{[llvm]? => [gallium]}, [llvm]? |
34 |
> > > => [gallium]:{[gallium]? => [llvm]}} |
35 |
> > > |
36 |
> > > |
37 |
> > > This is something I had overseen when replacing 'a q'_j is some p_i |
38 |
> > > and one of q_1 ... q_m might be false' by only 'a q'_j is some |
39 |
> > > p_i'; it can be replaced without changing anything in the way PM |
40 |
> > > would solve it by "a q'_j is some p_i and the set of {q_j} is not a |
41 |
> > > subset of q' union p'" (that is, {q_i} is not trivially true if the |
42 |
> > > 2nd clause is applied). Extending that, we get those stats: |
43 |
> > |
44 |
> > I'm not even trying to understand the things you say with indexes but |
45 |
> > I trust you know what you're doing. |
46 |
> |
47 |
> With that kind of things it's good to have someone having a second |
48 |
> look. It's so easy to forget a case or to miss a simplification. |
49 |
|
50 |
I'm sure Ciaran will love to elaborate ;-). |
51 |
|
52 |
> > Well, I guess it's time to hit the next level. For a start, we have to |
53 |
> > handle all-of groups, i.e.: |
54 |
> > |
55 |
> > ( a b c ) |
56 |
> > |
57 |
> > Stand-alone makes little sense (and little trouble) but as you could |
58 |
> > have seen it's used nested in other thingies: |
59 |
> > |
60 |
> > 1. || ( ( a b ) ( c d ) e ) |
61 |
> > |
62 |
> > 2. ?? ( ( a b ) ( c d ) e ) |
63 |
> > |
64 |
> > 3. ^^ ( ( a b ) ( c d ) e ) |
65 |
> |
66 |
> Yeah that's the nesting problem causing a parse error. |
67 |
> Those should be expanded to implications. What I'm relying onto is all |
68 |
> clauses to be of the form '[list of conditions]? [list of constraints]' |
69 |
|
70 |
I've noticed that you turned the implications into multi-conditions, |
71 |
breaking all my scripts ;-). Is the [list of conditions] conjunctive or |
72 |
disjunctive? |
73 |
|
74 |
> > For verifying constraints, they are not bad. We just follow the |
75 |
> > generic rule that the branch evaluates to true if all subexpressions |
76 |
> > are true. |
77 |
> > |
78 |
> > For solving, it might be a little unclear on how to proceed with |
79 |
> > partially true branches but for the sake of simplicity I would just |
80 |
> > ignore them and behave as if they were false. That is, case (1) with |
81 |
> > USE='c' would result in 'a b' being enabled. |
82 |
> > |
83 |
> > The practical uses I've seen are: |
84 |
> > |
85 |
> > a. || ( deprecated ( gtk3 introspection ) ) |
86 |
> > |
87 |
> > I guess this one would be equivalent to: |
88 |
> > |
89 |
> > !gtk3? ( !introspection? ( deprecated ) ) |
90 |
> |
91 |
> Unfortunately no. Favoring leftmost, you need to enable 'deprecated' |
92 |
> when either gtk3 or introspection is false. |
93 |
> |
94 |
> That'd be: |
95 |
> !gtk3? ( deprecated ) |
96 |
> !introspection? ( deprecated ) |
97 |
|
98 |
Well, I meant 'by current rules', without considering preferences. |
99 |
|
100 |
> Fortunately we can distribute \/ and /\: |
101 |
> > > ( deprecated ( gtk3 introspection ) ) |
102 |
> |
103 |
> is equivalent to: |
104 |
> > > ( deprecated gtk3 ) |
105 |
> > > ( deprecated introspection ) |
106 |
> |
107 |
> giving the above implication translation. |
108 |
> |
109 |
> This can be extended to |
110 |
> > > ( ( a1 a2 a3 ... ) ( b1 b2 b3 ... ) ... ) to handle all cases. |
111 |
> |
112 |
> |
113 |
> |
114 |
> > b. ^^ ( ( !32bit 64bit ) ( 32bit !64bit ) ( 32bit 64bit ) ) |
115 |
> > |
116 |
> > This looks like a crazy way of saying: |
117 |
> > |
118 |
> > || ( 32bit 64bit ) |
119 |
> |
120 |
> Hmm yes |
121 |
> |
122 |
> |
123 |
> > c. ^^ ( ( !ruby !s7 ) ( ruby !s7 ) ( !ruby s7 ) ) |
124 |
> > |
125 |
> > This looks like an insane version of: |
126 |
> > |
127 |
> > ?? ( ruby s7 ) |
128 |
> |
129 |
> |
130 |
> yes too it seems |
131 |
> |
132 |
> |
133 |
> |
134 |
> > except that per my solver it just disables both when both are set ;-). |
135 |
> |
136 |
> That's kind of the point. And that's why it is important to have the |
137 |
> solving rules well defined. Depending on how REQUIRED_USE is written, |
138 |
> it will be solved differently even for equivalent logical formulas. |
139 |
> |
140 |
> |
141 |
> > Not sure if the extra complexity is worth for roughly one valid use |
142 |
> > case, and a lot of insanity. |
143 |
> |
144 |
> I think this can be done without too much pain. As you noticed, replace |
145 |
> '^^ ( whatever )' by '|| ( whatever ) ?? ( whatever )' so we're left |
146 |
> with only || and ?? (and 'and' denoted by space and grouping in our |
147 |
> notation). |
148 |
> |
149 |
> > > ( clause1 clause2 ... ) is replaced by |
150 |
> |
151 |
> [!clause1 !clause2 ...]?[clause1] |
152 |
> |
153 |
> ?? ( clause1 clause2 ... ) is replaced by: |
154 |
> [clause1]?[!clause2 !clause3 ...] |
155 |
> [!clause1]?[ ?? ( clause2 clause3 ... ) ] |
156 |
> |
157 |
> ! (|| ( clause1 clause2 ... ) ) is '!clause1 !clause2 ...' (de morgan) |
158 |
> ! ( clause1 clause2 ... ) is '|| ( !clause1 !clause2 ... )' (de morgan |
159 |
> too) |
160 |
> ! (?? ( clause1 clause2 ... ) ) could be written as 'clause1? ( || |
161 |
> ( clause2 ... ) ) !clause1? ( ! ?? ( clause2 ... ) )' |
162 |
> |
163 |
> and I think that's it to allow expanding everything to implications. |
164 |
> |
165 |
> |
166 |
> [ begin || ( clause1 clause2 ... ) end ]?[constraint] |
167 |
> |
168 |
> is: |
169 |
> [ begin clause1 end]?[constraint] |
170 |
> [ begin clause2 end]?[constraint] |
171 |
> etc. |
172 |
> |
173 |
> |
174 |
> [ begin ([icond]?[iconstraint]) end]?[constraint] |
175 |
> is: |
176 |
> [ begin icond]?[iconstraint] |
177 |
> [ begin end]?[constraint] |
178 |
> |
179 |
> I think |
180 |
> |
181 |
> and |
182 |
> |
183 |
> [ begin ( clause1 clause2 ... ) end]?[constraint] |
184 |
> is |
185 |
> [ begin clause1 clause2 ... end]?[constraint] |
186 |
> |
187 |
> |
188 |
> [...] |
189 |
> > Of course past that there's a deeper insanity: all those constructs |
190 |
> > can be nested without limits. Verification is possible, solving maybe |
191 |
> > -- but I'm not sure if we even want to try to think what the correct |
192 |
> > solution would be. |
193 |
> |
194 |
> We're good as long as they're rewritten as implications internally. |
195 |
> |
196 |
> |
197 |
> > There's only one use of this: |
198 |
> > |
199 |
> > ?? ( gl3plus ( || ( gles2 gles3 ) ) ) |
200 |
> |
201 |
> That'd be: |
202 |
> gl3plus? ( ! || ( gles2 gles3 ) ) |
203 |
> |
204 |
> per the above reduced to: |
205 |
> gl3plus? ( !gles2 !gles3 ) |
206 |
> |
207 |
> > |
208 |
> > FWICS, it probably works like this; |
209 |
> > |
210 |
> > g g |
211 |
> > l l |
212 |
> > 3 g g 3 g g |
213 |
> > p l l p l l |
214 |
> > l e e l e e |
215 |
> > u s s u s s |
216 |
> > s 2 3 | s 2 3 |
217 |
> > 0 0 0 | 0 0 0 (==) |
218 |
> > 0 0 1 | 0 0 1 (==) |
219 |
> > 0 1 0 | 0 1 0 (==) |
220 |
> > 0 1 1 | 0 1 1 (==) |
221 |
> > 1 0 0 | 1 0 0 (==) |
222 |
> > 1 0 1 | 1 0 1 [unsolvable due to loop] |
223 |
> > 1 1 0 | 1 1 0 [unsolvable due to loop] |
224 |
> > 1 1 1 | 1 1 1 [unsolvable due to loop] |
225 |
> > |
226 |
> > i.e. it would be equivalent to: |
227 |
> > |
228 |
> > gl3plus? ( !gles2 !gles3 ) |
229 |
> > |
230 |
> > unless the author meant something else and failed. |
231 |
> |
232 |
> |
233 |
> Exactly. I don't know why you see a loop. |
234 |
|
235 |
My solver doesn't really support nested || ^^, so it failed to apply any |
236 |
reasonable change ;-). |
237 |
|
238 |
> > The question is whether we want to: |
239 |
> > |
240 |
> > a. actually try to solve this nesting insanity, |
241 |
> > |
242 |
> > b. declare it unsupported and throw REQUIRED_USE mismatch on user, |
243 |
> > |
244 |
> > c. ban it altogether. |
245 |
> |
246 |
> |
247 |
> I don't think it is *that* insane to support nesting :) |
248 |
> |
249 |
|
250 |
|| ( ^^ ( ?? ( a b ) c ( d e ) ) f ) |
251 |
|
252 |
? ;-) |
253 |
|
254 |
|
255 |
-- |
256 |
Best regards, |
257 |
Michał Górny |