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