On pon, 2017-06-05 at 09:55 +0200, Alexis Ballier wrote:
> On Sun, 4 Jun 2017 10:59:38 +0200
> Alexis Ballier <aball...@gentoo.org> wrote:
> 
> > Here's a quick n dirty code to play with, based on yours: 
> > https://github.com/aballier/required-use
> 
> I've run that on the whole tree (considering all ebuilds with non
> empty REQUIRED_USE), some stats:
> 
> $ time python3 classify.py requsel 
> Stats:
>       Parse error: 16

Hmm, how did you get those numbers? I just tested parsing and found only
 7 unique REQUIRED_USE entries that fail. However, my sample file is
only around 1000 entries long, so either I failed to get all of them, or
you didn't deduplicate your list ;-). More on it below.

>       Good: 8316
>       Need topo sort: 140
>       Cyclic: 57
> 
> real  0m2.996s
> user  0m2.950s
> sys   0m0.004s
> 
> 
> Running time is good I think.
> Parse error is some nested construct not supported by your parser that
> I have not fixed either.

Yes, the time is great. It means we can actually think about integrating
it with repoman/pkgcheck.

> The cycle is mostly due to:
> $ python3 nsolve.py 'llvm? ( gallium ) gallium? ( llvm )'
> [...]
> toposort.CircularDependencyError: Circular dependencies exist among
> these items: {[gallium]? => [llvm]:{[llvm]? => [gallium]}, [llvm]? =>
> [gallium]:{[gallium]? => [llvm]}}
> 
> 
> This is something I had overseen when replacing 'a q'_j is some p_i and
> one of q_1 ... q_m might be false' by only 'a q'_j is some p_i'; it can
> be replaced without changing anything in the way PM would solve it by
> "a q'_j is some p_i and the set of {q_j} is not a subset of q' union
> p'" (that is, {q_i} is not trivially true if the 2nd clause is
> applied). Extending that, we get those stats:

I'm not even trying to understand the things you say with indexes but I
trust you know what you're doing. For completeness, we need to consider
three cross-dependent states:

a. a? ( b ) b? ( a )

i.e.:

  y_1 = y_2 = x_1 v x_2

iow, enabling either of the flags causes both of them being enabled. I'm
not sure if we have a valid use case to keep such flags long-term but
short-term they could be useful to handle transition periods when
upstream merges two features (or makes them cross-dependent) and we want
to preserve compatibility with split flags.

b. !a? ( !b ) !b? ( !a )

i.e.:

  y_1 = y_2 = x_1 ^ x_2

iow, you have to enable both flags to keep them enabled. Not sure if we
have any valid use case for this.

c. a? ( b ) !a? ( !b )

i.e.

  y_1 = y_2 = x_1

This mostly a reduced result of:

  a? ( || ( b c d ... ) ) !a? ( !b !c !d ... )

[NB: it would be useful to have a short syntax for that]

I suspect this will be commonly useful to express provider dependencies,
i.e. enforcing a particular constraint for providers only when
the feature flag is enabled, and disabling all provider flags when it is
not.

FWICS, my version solves all three cases correctly, and your does not
explode on them.

> I'll let you play with it, but for me it seems this would work quite
> nicely.
> 

Well, I guess it's time to hit the next level. For a start, we have to
handle all-of groups, i.e.:

  ( a b c )

Stand-alone makes little sense (and little trouble) but as you could
have seen it's used nested in other thingies:

1. || ( ( a b ) ( c d ) e )

2. ?? ( ( a b ) ( c d ) e )

3. ^^ ( ( a b ) ( c d ) e )

For verifying constraints, they are not bad. We just follow the generic
rule that the branch evaluates to true if all subexpressions are true. 

For solving, it might be a little unclear on how to proceed with
partially true branches but for the sake of simplicity I would just
ignore them and behave as if they were false. That is, case (1) with
USE='c' would result in 'a b' being enabled.

The practical uses I've seen are:

a. || ( deprecated ( gtk3 introspection ) )

I guess this one would be equivalent to:

  !gtk3? ( !introspection? ( deprecated ) )

b. ^^ ( ( !32bit 64bit ) ( 32bit !64bit ) ( 32bit 64bit ) )

This looks like a crazy way of saying:

  || ( 32bit 64bit )

c. ^^ ( ( !ruby !s7 ) ( ruby !s7 ) ( !ruby s7 ) )

This looks like an insane version of:

  ?? ( ruby s7 )

except that per my solver it just disables both when both are set ;-).

Not sure if the extra complexity is worth for roughly one valid use
case, and a lot of insanity.

I've pushed a simple update to my parser to account for this. However,
it doesn't support replace_nary atm, so it won't work for you.


Of course past that there's a deeper insanity: all those constructs can
be nested without limits. Verification is possible, solving maybe -- but
I'm not sure if we even want to try to think what the correct solution
would be.

There's only one use of this:

  ?? ( gl3plus ( || ( gles2 gles3 ) ) )

FWICS, it probably works like this;

 g       g    
 l       l    
 3 g g   3 g g
 p l l   p l l
 l e e   l e e
 u s s   u s s
 s 2 3 | s 2 3
 0 0 0 | 0 0 0 (==)
 0 0 1 | 0 0 1 (==)
 0 1 0 | 0 1 0 (==)
 0 1 1 | 0 1 1 (==)
 1 0 0 | 1 0 0 (==)
 1 0 1 | 1 0 1 [unsolvable due to loop]
 1 1 0 | 1 1 0 [unsolvable due to loop]
 1 1 1 | 1 1 1 [unsolvable due to loop]

i.e. it would be equivalent to:

  gl3plus? ( !gles2 !gles3 )

unless the author meant something else and failed.

The question is whether we want to:

a. actually try to solve this nesting insanity,

b. declare it unsupported and throw REQUIRED_USE mismatch on user,

c. ban it altogether.

-- 
Best regards,
Michał Górny

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to