Construction from many sets - algorithm

I have four sets:
A={a,b,c}, B={d,e}, C={c,d}, D={a,b,c,e}
I want to search the sequence of sets that give me: a b c d
Example: the sequence A A A C can give me a b c d because "a" is an element of A, "b" is an element of A, "c" is an element of A and "d" is an element of C.
The same thing for : D A C B, etc.
I want an algorithm to enumerate all sequences possibles or a mathematical method to find the sequences.

You should really come up with some code of your own and then ask specific questions about problems with it. But it's interesting, so I'll share some thoughts.
You want a b c d.
a can come from A, D
b can come from A, D
c can come from A, C, D
d can come from B, C
So the problem reduces to finding all of the 2*2*3*2=24 ways to combine those options.
One way is recursion with backtracking. Build it from left to right, output when you have a complete set. Like the 8 queens problem, but much simpler since everything is independent.
Another way is to count the integers and map them into a mixed-base system. First digit base 2, then 2, 3, 2. So 0 becomes AAAB, 1 is AAAC, 2 is AACB, etc. 23 is DDDC and 24 needs five digits so you stop there.

Related

Prolog pythagorean triplet

I'm trying to solve project Euler problem 9 using prolog. I'm a 100% n00b with prolog and I'm just trying to understand the basics right now.
I'm trying to use findall to get all triplets that would add up to 1000, but I can't really figure out the syntax.
What I'm hoping for is something like:
pythag_trip(A, B, C, D) :- D is (A * A) + (B * B) + (C * C).
one_thou_pythag(A, B, C) :- pythag_trip(A, B, C, 1000).
product_trip(A, B, C, D) :- D is A * B * C.
findall([A, B, C], one_thou_pythag(A, B, C) , Bag)).
writeln(Bag).
I know that doesn't work because it's saying Bag is not instantiated. But there are still some basics that I don't understand about the language, too.
1: can I even do this? With multiple moving pieces at once? Can I find all triplets satisfying a condition? Do I need to go down a completely different like like using clpfd?
2: What is supposed to be going in that last argument where I put Bag?
3: Is it possible to create data types? I was thinking it might be good to create a triplet set type and an operation to get the pythagorean triplet sum of them if I have to find some way to generate all the possibilities on my own
Basically those questions and then, I could use some pointing in the right direction if anyone has tips
Sorry but I don't answer your questions. It seems to me that you're trying not a prolog-like approach.
You should try to solve it logically.
So do this problem from the top to bottom.
We want to have 3 numbers that sum to 1000.
between(1,1000,A), between(A,1000,B), between(B,1000,C), C is 1000-A-B.
In that case, we will have them sorted and we won't take permutations.
So let's go a step further. We want them to be pythagorem triplet.
between(1,1000,A), between(A,1000,B), between(B,1000,C), C is 1000-A-B, is_triplet(A,B,C).
But we don't have is_triplet/3 predicate, so let's create it
is_triplet(A,B,C) :- D is C*C - A*A -B*B, D=0.
And that's actually it.
So let's sum it up
is_triple(A, B, C) :- D is C*C - A*A - B*B, D = 0.
triplet(A,B,C) :- between(1,1000,A), between(A,1000,B), C is 1000-A-B, between(B,1000,C), C is 1000-A-B, is_triple(A,B,C).
When you call triplet(A,B,C) you should get an answer.
Notice one thing, that at the end I've swapped C is 1000-A-B with between(B,1000,C). It makes the program much faster, try to think why.

How to allocate x copy of n objects among k persons

I have following use case;
I have N distinct items , each can have x number of copies. Now I need to distribute these items among k persons where each person's capacity is varying and can be <=N.
Following conditions must be met;
Each person should get one and only one copy of an Item
Example:
Items = apple , banana , orange
copies = 3 ( It means we have 3 apples , 3 bananas and 3 oranges )
So I have a array;
{1,2,3,4,5,6,7,8,9} // 1,2,3 = 3 apples ; 4,5,6 = 3 banana ; 7,8,9 = 3 oranges
Total Person = 5
Person Capacity
P1 3
P2 2
P3 1
P4 1
P5 2
How can I solve such problem ? The problem I am facing is that when I allocate it for an arbitrary numbers for N , x , k , I sometimes end up in a case where I am left with some items to allocate because I can't ensure the condition that "Each person should get one and only one copy of an Item"
Since each item has the same "weight", you can actually solve this problem greedily. To ensure that each person receives distinct items, we create the sequence containing all the xN items by repeating the sequence of N distinct items x times. Then, we go through each of the persons and simply remove and assign them the first c items of this sequence, where c is that person's carrying capacity.
This works because of the way we have laid out the items and because c <= N. In our "mega" sequence, duplicates are always N indices away from each other, so c consecutive elements will never contain two duplicates. Duplicates will only appear in contiguous subsequences containing more than N items.
Note that in the implementation of this algorithm, you don't actually have to create the mega sequence; you can simply repeatedly iterate through the distinct item sequence by using modular arithmetic. To keep the explanation simple, I will be forming the "mega" items sequence in the examples, but you don't have to do this in the implementation.
Taking the example in your question, let the 3 distinct items be A, B, C with 3 copies each. The "mega" sequence is formed by repeating the distinct items sequence 3 times: A, B, C, A, B, C, A, B, C. Now we go through each person and simply assign them the number of items they can carry. To illustrate this, consider the following cases for the capacity array (taken from your question and comments below):
[3, 2, 1, 1, 2]: P1 gets A, B, C, P2 gets A, B, P3 gets C, P4 gets A, and P5 gets B, C.
[2, 2, 2, 2, 1]: P1 gets A, B, P2 gets C, A, P3 gets B, C, P4 gets A, B, and P5 gets C.
[3, 1, 1, 1, 1, 2]: P1 gets A, B, C, P2 gets A, P3 gets B, P4 gets C, P5 gets A, P6 gets B, C.

Algorithm for enumerating all permutations of algebraic expressions

If I have a list of variables, such as {A, B, C} and a list of operators, such as {AND, OR}, how can I efficiently enumerate all permutations of valid expressions?
Given the above, I would want to see as output (assuming evaluation from left-to-right with no operator precedence):
A AND B AND C
A OR B OR C
A AND B OR C
A AND C OR B
B AND C OR A
A OR B AND C
A OR C AND B
B OR C AND A
I believe that is an exhaustive enumeration of all combinations of inputs. I don't want to be redundant, so for example, I wouldn't add "C OR B AND A" because that is the same as "B OR C AND A".
Any ideas of how I can come up with an algorithm to do this? I really have no idea where to even start.
Recursion is a simple option to go:
void AllPossibilities(variables, operators, index, currentExpression){
if(index == variables.size) {
print(currentExpression);
return;
}
foreach(v in variables){
foreach(op in operators){
AllPossibilities(variables, operators, index + 1, v + op);
}
}
}
This is not an easy problem. First, you need a notion of grouping, because
(A AND B) OR C != A AND (B OR C)
Second, you need to generate all expressions. This will mean iterating through every permutation of terms, and grouping of terms in the permutation.
Third, you have to actually parse every expression, bringing the parsed expressions into a canonical form (say, CNF. https://en.wikipedia.org/wiki/Binary_expression_tree#Construction_of_an_expression_tree)
Finally, you have to actually check equivalence of the expressions seen so far. This is checking equivalence of the AST formed by parsing.
It will look loosely like this.
INPUT: terms
0. unique_expressions = empty_set
1. for p_t in permutations of terms:
2. for p_o in permutations of operations:
3. e = merge_into_expression(p_t, p_o)
4. parsed_e = parse(e)
5. already_seen = False
6. for unique_e in unique_expressions:
7. if equivalent(parsed_e, unique_e)
8. already_seen = True
9. break
10. if not already_seen:
11. unique_expressions.add(parsed_e)
For more info, check out this post. How to check if two boolean expressions are equivalent

Restricted combinations (algorithm)

Consider the following example:
I have a list of 5 items, each with their occurrence with either 1 or 0:
{a, b, c, d, e}
The restricted combinations are as follows:
the occurrence of a, c, and e cannot be 1 at any given time.
the occurrence of b, d, and e cannot be 1 at any given time.
basically, if found in database that occurrence of a and c is already 1, and if a given input is e (giving e an occurrence of 1) is not allowed (clause 1) or vice versa.
another example, d and e has an occurrence of 1 respectively in the database, a new input of b will not be allowed (following clause 2).
An even more solid example:
LETTER | COUNT(OCCURRENCE)
------------------------------
a | 1
b | 1
c | 1
d | 0
e | 0
Therefore, a new input of e would be rejected because of the violation of clause 1.
What is the best algorithm/practice for this solution?
I thought of having many if-else statements, but that doesn't seem efficient enough. What if I had a dynamic list of elements instead? Or at least have a better extensibility to this piece of program.
As mentioned by BKassem(I think) in the comments(removed for whatever reason).
The algorithm for this scenario:
(count(a) * count(c) * count(e)) == 0 //proceed to further actions
Worked flawlessly!

Getting all nodes that have atleast 2 nodes connected to them

Having some issues with a Prolog question:
The following clauses represent a directed graph, where nodes are
atoms, and edges are denoted by the connected predicate. Given that
the following clauses are in the database, answer the two questions
below.
connected(a,b).
connected(b,d).
connected(b,e).
connected(b,f).
connected(a,c).
connected(c,f).
connected(c,g).
connected(h,c).
path(X,Y) :- connected(X,Y).
path(X,Z) :- connected(X,Y), path(Y,Z).
Show the Prolog query that returns all nodes having two or more
different incoming edges (i.e., at least two different nodes are
connected to it). Also, show the result of entering the query (asking
for every solution). Your query may return the same node multiple
times, and may printout the values of other variables in the query.
The variable denoting the node in question should be called DNode.
So far I have:
path(DNode,__) , path(__,DNode).
But that only give me b and c
I think the letters with more than one nodes are a, b, c, f.
I tried this to get a, b and c:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__).
But I got a, b, c and h.
I am assuming I'll have to like this to get all the letters I want:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__) ; path(__,DNode) , path(__,DNode).
It gives me a, b, c, e, f, g and h though.
Any advice about how to get the 4 letters I want would be appreciated.
if you display your graph, perhaps with Graphviz
?- writeln('digraph G {'), forall(connected(A,B), writeln(A->B)), writeln('}').
you can see that only [c,f] have 2 incoming edges, and that you don't need path/2. It's sufficient a join on the second argument of connected/2, with a test that the first arguments are different (operator (\=)/2).

Resources