Related
I have a function f that takes a list of items as it's single parameter and returns true if the ordering of the items is accepted or false if the ordering of the items is not accepted.
There exists at least one or more permutations of list l which f(l) returns true.
Function f is a black box (we don't have it's source code) and the type of the elements held by list l are also unknown or generic.
p is a permutation of list l according to user preferences. The most preferred item has index 0 the least preferred item has index l.size()-1
list p will always contain all elements of list l.
The goal is to find a permutation of l let's call it p_accepted where f(p_accepted) returns true and preference p is maximized.
Here's an example
given l = [a, b, c, d, e, f]
given p = [c, a, f, b, e, d]
given f([ a, b, c, d, e, f ]) = false
given f([ c, a, f, b, e, d ]) = false
given f([ d, e, b, f, a, c ]) = true
given f([ f, e, d, c, b, a ]) = true
given f([ c, b, f, a, d, e ]) = true
given f([ a, c, f, b, e, d ]) = true
given f([ anything else ]) = false
the expected output for p_accepted is [c, b, f, a, d, e]
it is accepted because f(p_accepted) returns true and no other permutation of l ranks the item 'c' as high. item 'c' is the most preferred by the user since it has index 0
Implementations in pseudo code or any language are accepted.
[EDIT]
Clarifications
list p will always contain all elements of list l
list l items can only be compared by identity, i.e.: by reference
so an item in list p can be found in list l by l[i] == p[j]
list l items cannot always be compared like in the example where a compare function c might determine that a < b i.e.: c('a', 'b') = 1.
[EDIT 2]
To understand preferences better
Imagine Alice and Bob being forced to do 4 tasks together at the same time in order. [task a, task b, task c, task d].
Alice has one preferred order for doing the tasks [a,b,c,d]. Bob has two preferred orders for doing the tasks [a,c,b,d], [a,d,b,c]. If you are Alice, the function f would return true only for [a,c,b,d] and [a,d,b,c] which are Bob's preferences, since both like to do task a first p_accepted should start with a.
Note that this is an analogy function f does not accept permutations based on multiple user's order preference.
I'm new to constraint-programming (coming from c#) and I'm trying to solve this problem. Unfortunately I don't have a name for this kind of puzzle so I'm not sure what to search for. The closest examples I can find are Nonogram and Tomography puzzles.
Puzzle description:
The player is given an empty game board (varying size) that they must fill with n-colors, using clue patterns for the rows and columns. Each clue pattern is the sequence of colors in that row/col but with consecutive duplicates removed.
Here is an example easy small 4x4 grid with 3 colors:
rbg,rbr,grb,bgbg <- (top-to-bottom column constraints)
_,_,_,_ rgb <- (row constraints)
_,_,_,_ brg
_,_,_,_ b
_,_,_,_ grbg
Solutions (2):
r,r,g,b
b,?,r,g
b,b,b,b
g,r,b,g
? Can be either red or blue but not green.
Pattern examples below.
Examples given 6-length sequences to pattern:
aaaaaa -> a
aabbcc -> abc
abbbbc -> abc
cabbbc -> cabc
bbbaac -> bac
abbaab -> abab
abcabc -> abcabc
Examples given pattern to potential solution sequences:
abc -> abc (3 length solution)
abc -> abcc, abbc, aabc (4 length solutions)
abc -> abccc, abbcc, abbbc, aabbc, aaabc (5 length solutions)
I've tried to solve it in C# or-tools and MiniZinc but the biggest problem I have is building the constraints. I can generate the patterns from a sequence (in c# imperative way) but then how to turn that into a constraint?
How I'm thinking about it: generate all potential sequences from each clue pattern. Then make a constraint for the corresponding row/col that says it must be one of those sequences.
Example from top row in above puzzle: rgb to [4-length sequences] -> rgbb, rggb, rrgb, and then add a constraint for that row: must equal one of these sequences.
Am I thinking about this right? Any smarter ways to do it?
Thanks for any advice.
=====================================
Edit after some progress:
This MiniZinc correctly solves the top row for the pattern abc which has 3 solutions of 4 length: aabc, abbc, abcc.
include "globals.mzn";
array [1..4, 1..4] of var 1..3: colors;
constraint regular(row(colors, 1), 4, 3,
[|
% a, b, c
2,0,0| % accept 'a'
2,3,0| % accept 'a' or 'b' ?
0,3,4| % accept 'b' or 'c' ?
0,0,4| % accept 'c'
|], 1, {4});
% Don't care about rest of grid for now.
constraint forall(i,j in 1..4 where i > 1) (row(colors, i)[j] = 1);
solve satisfy;
output [show(colors)];
However I'm not sure how to handle larger grids with many patterns other than hardcoding everything like this. I will experiment a bit more.
The constraints you are talking about seem to be easily represented as regular expressions. For example your abc example with varying length can be caught using the regular expression abc.*, which requires one a then one b, and then one c, it will accept anything else afterwards.
In MiniZinc these kinds of constraints are expressed using the regular predicate. The regular predicate simulates an automaton with accepting states. By providing the allowed state-transitions the model is constraint.
The example expression abc.* would be enforced by the following constraint item:
% variables considered, nr states, input values
constraint regular(VARS, 4, 1..3, [|
% a, b, c
2,0,0| % accept 'a'
0,3,0| % accept 'b'
0,0,4| % accept 'c'
4,4,4| % accept all
|], 1, {4}); % initial state, accepting states
In Prolog(language), I use DCG form to describe such problems. It is extended BNF form.
So I suggest finding approach with Extended BNF Form in your environment.
SWI-Prolog example:
color_chunk_list(Encoded,Decoded):-
phrase(chunk_list(Encoded),Decoded),
chk_continuity(Encoded).
chunk_list([])-->[].
chunk_list([First|Rest])-->colorrow(First),chunk_list(Rest).
colorrow(Color)-->[Color],colorrow(Color).
colorrow(Color)-->[Color].
chk_continuity([First,Second|Rest]):-First \= Second,chk_continuity([Second|Rest]).
chk_continuity([_]).
In this program, encodings and decodings are bidirectional.
Tests:
?- length(L,4),color_chunk_list([r,g],L).
L = [r, r, r, g] ;
L = [r, r, g, g] ;
L = [r, g, g, g] ;
false.
?- length(L,6),color_chunk_list([a,b,c],L).
L = [a, a, a, a, b, c] ;
L = [a, a, a, b, b, c] ;
L = [a, a, a, b, c, c] ;
L = [a, a, b, b, b, c] ;
L = [a, a, b, b, c, c] ;
L = [a, a, b, c, c, c] ;
L = [a, b, b, b, b, c] ;
L = [a, b, b, b, c, c] ;
L = [a, b, b, c, c, c] ;
L = [a, b, c, c, c, c] ;
false.
?- color_chunk_list(L,[a,a,b,b,c,c]).
L = [a, b, c] ;
false.
?- color_chunk_list(L,[b,r,b,r,r,g,g,b]).
L = [b, r, b, r, g, b] ;
false.
In ECLiPSe, which is prolog based CLP system (not IDE one),
above predicate(color_chunk_list) can be turned into clp constraint
with propia mechanism and can genarate clp propagation.
Here is the motivation and how it should behave, but I need a help how to implement it.
I have several (typically) incomplete orders given as ordered values, for ex.:
1. A, C, D
2. D, E
3. X, B
4. B, C
5. C, F
6. C, A
and the resulting order should be:
A, X, B, C, D, E, F or A, X, B, C, F, D, E or A, X, B, C, D, F, E
The idea behind it is sort the result based on first seen order. I will try explain it on the example in steps:
order A, C, D
D, E - D seen, so add E after D, so order A, C, D, E
X, B - no value seen yet, so we can not determine the order now, so create 2nd temporary order X, B
B, C - C already seen, so order A, B, C, D, E
and 2nd order can be merged via B, so A, X, B, C, D, E
C, F - C see, so order A, X, B, C, D, E, F
C, A - ignore, both values are part of already defined order (by first incomplete order A, C, D)
But what if an additional incomplete order F, D or F, E will be part (added to the end) of the input? The step-by-step mental algorithm will fail - F was already placed.
How can the idea be implemented, any idea?
Algorithm for Finding first set:
Given a grammar with the rules A1 → w1, ..., An → wn, we can compute the Fi(wi) and Fi(Ai) for every rule as follows:
initialize every Fi(Ai) with the empty set
set Fi(wi) to Fi(wi) for every rule Ai → wi, where Fi is defined as follows:
Fi(a w' ) = { a } for every terminal a
Fi(A w' ) = Fi(A) for every nonterminal A with ε not in Fi(A)
Fi(A w' ) = Fi(A) \ { ε } ∪ Fi(w' ) for every nonterminal A with ε in Fi(A)
Fi(ε) = { ε }
add Fi(wi) to Fi(Ai) for every rule Ai → wi
do steps 2 and 3 until all Fi sets stay the same.
Grammar:
A -> B C c
A -> g D B
B -> EPSILON | b C D E
C -> D a B | c a
D -> EPSILON | d D
E -> g A f | c
This website generates the first set as follows:
Non-Terminal Symbol First Set
A g, ε, b, a, c, d
B ε, b
C a, c, ε, d
D ε, d
E g, c
But the algorithm says Fi(A w' ) = Fi(A) for every nonterminal A with ε not in Fi(A) so the First(A) according to this algorithm should not contain ε. First(A) = {g, b, a, c, d}.
Q: First(A) for the above grammar is = First(B) - ε U First(C) U {g} ?
This video also follows the above algorithm and do not choose ε.
First(B) = {ε, b}
First(D) = {ε, d}
First(E) = {g, c}
First(C) = {c, d, a}
First(A) = {b, g, c, d, a}
Example:
X -> Y a | b
Y -> c | ε
First(X) = {c, a, b}
First(Y) = {c, ε}
First(X) doesn't have ε because if you replace Y by ε, then First(Y a) is equal to First(ε a) = {a}
First set implementation on my github.
Edit: Updated link
https://github.com/amirbawab/EasyCC-CPP/blob/master/src/syntax/grammar/Grammar.cpp#L229
Computing the first and follow sets are both available on the new link above.
Suppose I have N elements, I want to create a list of all possible groupings of the elements, where there can be multiple groups of the N elements at once.
For example, suppose we have 4 elements: a, b, c, d. Let [ ] denote that the elements within the brackets are in a grouping. I'm looking for an algorithm (in Matlab if possible) that can create a list of all the ways they can group together like so:
a b c d
[a b] c d
a [b c] d
a b [c d]
[a d] b c
[a c] b d
a c [b d]
[a b] [c d]
[b c] [a d]
[a c] [b d]
[a b c] d
a [b c d]
b [c d a]
c [d a b]
[a b c d]
This solution generates all possibilities:
%Generate potential solutions
p=dec2base(0:base2dec('123',4), 4);
%convert to numeric
p=[zeros(size(p,1),1) p-'0'];
for col=2:4
%sort out. in column col a new group index is used, but not all previous indices are used.
valid=max(p(:,1:col-1),[],2)+1>=p(:,col);
p=p(valid,:);
end
The output is a matrix which labels the characters. For example 1233 is ab[cd] in your notation.