Set of pairs, with and without repetitions - tla+

I have two sets:
X = {a, b}
Y = {1, 2, 3}
I would like to generate the following set of sets of pairs:
{<<a, 1>>, <<a, 2>>, <<a, 3>>}
{<<a, 1>>, <<a, 2>>, <<b, 3>>}
{<<a, 1>>, <<b, 2>>, <<a, 3>>}
{<<a, 1>>, <<b, 2>>, <<b, 3>>}
...
{<<b, 1>>, <<b, 2>>, <<b, 3>>}
In each set the first element is from X and the second is from Y. X can be repeated, Y cannot. How to do it?

Using the \X operator gives us the set of all pairs: X \X Y = {<<a, 1>>, <<a, 2>>, ... <<b, 3>>}. SUBSET (X \X Y) gives us all possible sets. {s \in SUBSET (X \X Y): Cardinality(s) = 3} (from the FiniteSets module) gives us all 3-element sets.
We want to make this unique on the second element of each pair. Let's define a new operator:
UniqueBy(set, Op(_)) == Cardinality(set) = Cardinality({Op(s): s \in set})
If we do {x[2] : x \in {<<a, 1>>, <<a, 2>>, <<a, 2>>}}, we get {1, 2}, which has a smaller cardinality and will be filtered out. So our final expression is
{s \in SUBSET (X \X Y) : UniqueBy(s, LAMBDA x: x[2]) /\ Cardinality(s) = 3}
Note that without the cardinality check {<<a, 1>>} would be part of the set of sets, which isn't what you're looking for.

EXTENDS Functions, FiniteSets, Naturals
CONSTANTS a, b
X == {a, b}
Y == {1, 2, 3}
Dom == 1..Cardinality(Y)
Slice == {{<< xt[n], yt[n] >>: n \in Dom}:
<< xt, yt >> \in [Dom -> X] \X Bijection(Dom, Y)}
The TLAPS distribution includes the module Functions. The modules FiniteSets and Naturals are part of the standard library of TLA+.

Related

Strange behavior of groupBy

I am wondering why the following call of groupBy does not work: My predicate is x < y, so I expect [1, 6] to be a group, but instead, Haskell put [1, 6, 4, 2] into a group.
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,2]
[[8],[5],[3],[2],[1,6,4,2]]
More strangely, when I change the last number to -2, I expect the same behavior as in the above example. That is, since both 2 and -2 are less than 4, I expect that in the result [1, 6, 4, -2] would make up a group. But instead, This time, Haskell put -2 to be a group.
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,-2]
[[8],[5],[3],[2],[1,6,4],[-2]]
Do I have a wrong understanding of groupBy?
In the implementation of the groupBy, x is always the first item of the sublist. Indeed, groupBy is implemented as:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
especially the span (eq x) is important here, since x will be the first item of a new group.
Since x is thus not the previous value in the list. If we thus run groupBy with the list [5, 3, 2, 1, 6, 4, -2], we get:
list
current list
x=?
check with
outcome
[5,3,2,1,6,4,-2]
[8]
8
/
/
[5,3,2,1,6,4,-2]
[8]
8
5
False
[3,2,1,6,4,-2]
[5]
5
/
/
[3,2,1,6,4,-2]
[5]
5
3
False
[3,2,1,6,4,-2]
[3]
3
/
/
[2,1,6,4,-2]
[3]
3
2
False
[2,1,6,4,-2]
[2]
2
1
False
[1,6,4,-2]
[2]
2
/
/
[1,6,4,-2]
[2]
2
1
False
[6,4,-2]
[1]
1
/
/
[4,-2]
[1,6]
1
6
True
[-2]
[1,6,4]
1
4
True
[]
[-2]
-2
/
/
Especially the case where we compare x=1 and y=4 is important. If x was only the previous value, we should start generating a new list, but since x is the first item of the list, that is not the case.
Normally you should only work with an equivalence relation ~ [wiki], such relation is:
reflexive: so x ~ x is true;
symmetric: so x ~ y if and only if y ~ x; and
transitive: so x ~ y and y ~ z implies that x ~ z.
Your equivalence relation is not reflexive, nor is it symmetric. This is thus not a valid function to work with groupBy.
The conceptual definition of groupBy p l is that it yields sublists of l such that for each xs in l, you have
all (==True) [p x y | x<-xs, y<-xs]
IOW, each sublist should be part of an equivalence class of p. That notion only makes sense if p is an equivalence relation. In particular, you need p x y ≡ p y x, and the defining equation also assumes that p x x is always true.
The implementation in the standard libraries shows that idea quite clearly: each x:ys list in the result has ys defined by the span of elements that are equivalent to x by the relation. So in your case, you get 1:[6,4,2], where 6,4,2 are all greater than 1.
Evidently, groupBy doesn't actually check p x y for all pairs of elements in the result lists, so this really only makes sense if p is indeed an equivalence relation.
What you expected the idea to be – and IMO this is not unreasonable – is that only for all x,y such that x is the left neighbour of y, you want p x y to hold. This is in general a weaker condition, but if p is an equivalence relation then it actually implies the original condition, because such a relation also is transitive. So maybe the implementation should actually be
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' _ (x:l) = (x:xs) : zss
where (xs,zss) = case l of
[] -> ([],[])
zs#(y:_)
-> let ys:zss' = groupBy' p zs
in if p x y then (ys, zss')
else ([], ys:zss')
(This could be simplified a bit, but then it wouldn't be as lazy as the old implementation.)

Sorting a part of a list without using library functions

I want to sort the first three elements of a list, yet keep the other elements untouched. And I don't want to use any library functions because I am new to Haskell.
This is what I have so far:
{-# OPTIONS_GHC -Wincomplete-patterns #-}
sort2 (x, y) = if x > y then (y,x) else (x,y)
sort3 (x,y,z)
| x > y && y > z = (z,y,x)
| x > z && z > y = (y,z,x)
| y > x && x > z = (z,x,y)
| y > z && z > x = (x,z,y)
| z > x && x > y = (y,x,z)
| z > y && y > x = (x,y,z)
| otherwise = (0,0,0)
--sortfirst3 :: [Int] -> [Int]
sortfirst3 (x:y:z:v:xs) = sort3(x,y,z) : sortfirst3 (v:xs)
I'm trying to sort the first three elements, put them in a list, and then put the other elements in another list and then concatenate them with each other. However, this generates an error because of the type difference a tuple and a list. Is there another way I should be doing this?
You don't need to involve tuples. You can write what you wrote for tuples as patterns to match instead.
sortFirst3 [x, y] = if x > y then [y, x] else [x, y]
sortFirst3 [x, y, z]
| x >= y && y >= z = [z, y, x]
| x >= z && z >= y = [y, z, x]
| y >= x && x >= z = [z, x, y]
| y >= z && z >= x = [x, z, y]
| z >= x && x >= y = [y, x, z]
| z >= y && y >= x = [x, y, z]
sortFirst3 (x : y : z : ws) = sortFirst3 [x, y, z] ++ ws
sortFirst3 xs = xs
The last line catches what has not been matched, which are the singletons and empty lists, which remain the same when sorted. You should not have strict inequalities in your guards since elements may repeat. Also note that, in your code, even if you didn't have the type mismatch, the recursive call to sortFirst3 would be erroneous, since after sorting the first three terms, the first three of the rest would be sorted, and so on.
sortfirst3 (x:y:z:v:xs) = sort3(x,y,z) : sortfirst3 (v:xs)
This definition says, take the first 4 elements off the list, sort the first 3 into a tuple, then cons it onto the (recursive) result on the fourth element of the list with the rest of the list.
This reveals three changes to be made.
First, we only need to match the first 3 elements, not the first 4, but we should also probably deal with cases for when the list is <3 elements long. I've just made it an error, but you can use eg. sort2 instead.
sortfirst3 (x:y:z:xs) = sort3 (x,y,z) : sortfirst3 xs
sortfirst3 _ = error "Can't sort first 3 elements of list shorter than 3 elements"
Second, we intend to sort the first 3 elements ie. resulting in a 3 element list. (:) :: a -> [a] -> [a] ie. takes an element (not a list) in the first argument, what we want instead is concatentation (++) :: [a] -> [a] -> [a].
sortfirst3 (x:y:z:xs) = sort3 (x,y,z) ++ sortfirst3 xs
Third, we intend to leave the elements after the first 3 untouched, so we shouldn't actually make a recursive call on the rest of the list - otherwise we'll instead be sorting the list in 3 element chunks.
sortfirst3 (x:y:z:xs) = sort3 (x,y,z) ++ xs
This is now almost correct, but for sort3, which as you identified incorrectly returns a tuple rather than a 3-element list. kuoytfouy's answer helps with that.

Haskell: Array Loop Comparison Equivalent

I am trying to compare certain aspects of two linked lists.
The arrays both have format (assume a...p derive Eq):
linkedList1 = [(a, b, c, d), (e, f, g, h)]
linkedList2 = [(a, f, k, l), (a, b, g, m)]
What I hope to accomplish here is as follows:
I want to input an index, to be referenced in each quadruple.
For that index, I want to find out, for each quadruple in linkedList 1, how many times the value at that index is identical to the value at the same index in each of the quadruples in linkedList 2.
For example on the above linked lists, inputting the two linkedlists and the index 1 would return a value of 2 as the second value in the first quadruple of linkedList1 = the second value in the second quadruple of linkedList2.
Inputting the two linkedlists and the index 3, however, will return 0 as none of the 4th letters in the quadruples of the 1st linked list match any of the 4th letters in the suadruples of the 2nd linked list.
Any suggestions how to achieve this/get started? I've been trying to implement a recursive map function but it's been pretty choppy progress.
This is what I came up with:
howManyEqualAtIndex l1 l2 0
=> 2
howManyEqualAtIndex l1 l2 1
=> 2
howManyEqualAtIndex l1 l2 2
=> 1
howManyEqualAtIndex l1 l2 3
=> 0
l1 = [('a', 'b', 'c', 'd'), ('e', 'f', 'g', 'h')]
l2 = [('a', 'f', 'k', 'l'), ('a', 'b', 'g', 'm')]
--List comprehension checking all combinations.
--Predicate that they are equal
howManyEqualAtIndex xs ys idx = length [() | x<-xs, y<-ys, equalAt x y idx]
--Hardcoded for quads, can be extended to other n-tuples,
--or changed to list version commented out below
equalAt (a,_,_,_) (b,_,_,_) 0 = a == b
equalAt (_,a,_,_) (_,b,_,_) 1 = a == b
equalAt (_,_,a,_) (_,_,b,_) 2 = a == b
equalAt (_,_,_,a) (_,_,_,b) 3 = a == b
--equalAt :: (Eq a) => [a] -> [a] -> Int -> Bool
--equalAt xs ys idx = xs !! idx == ys !! idx

Conditions in a list comprehension , finding possibilities

there are 3 keys and 3 locks, and i have to write a code to show the possible tries. Rules are:
Second key never can be placed before the first one.
No keys can be tried more than once.
First key cannot be placed as the first one.
and you can't place them in the order 3 - 2 - 1
and as a tip, this is given: [(x,y,z) | x <- [1..3], ]
I want to change this code in a way that, instead of " fst <- [3] " it says; " fst cannot be [1] "
and I also want to add that 2 cannot come before 1. I tried it with (elemIndex 2 (x,y,z)) > (elemIndex 1 (x,y,z))
but it didn't work. I would appreciate for some ideas.
d = [(x,y,z) | x <- [1..3], y <- [1..3], z <-[1..3], fst <- [3] , tail <- 1], x /= y, y /= z, x /= z]
You could use something like this:
d = [(3, y, z) | y <- [1..2], z <-[1..2], y /= z, y /= 2]
which gives
[(3,1,2)]
Explanation
First key cannot be placed as the first one.
and
Second key never can be placed before the first one.
imply that x cannot be 1 or 2, and hence must be 3. This gives
[(3, y, z) | y <- [1..2], z <-[1..2]
Since
No keys can be tried more than once.
we also have
, y != z
Finally
Second key never can be placed before the first one.
gives
, y /= 2]
In fact, with some thought, you could argue that you can just write
d = [(3, 1, 2)]

Haskell: search list

I am new to Haskell, now I have a question here.
If I have a list [[1,2],[3,4],[5,6]], and I want use a function like searchList x = 3, then output 4, how to dual with it?
Use the filter high order function:
search :: [[Int]] -> Int -> Int
search list n = head (head (filter (\(x:xs) -> x == n) list))
What this search function does is to filter the elements of the passed list of lists, selecting only the ones which have the passed value n as head. Then takes only one (The first, thats why the first (right) head is used), and then extracts the first element of that list (Using head again).
If you want to store a list of pairs, I suggest you to use tuples instead of lists as elements of the list.
EDIT: As people suggested in comments, if you use tuples there is a function lookup on the prelude that implements this kind of searching.
So what you have a list of lists and you want to search it, find the element that matches [x,y] and return y.
searchList x (y:ys) = if x == head y then last y else searchList x ys
searchList x [] = -1
Which behaves like so:
Main> :load searchlist.hs
Main> searchList 3 [ [1, 2], [3, 4], [5, 6] ]
4
Main> searchList 5 [ [1, 2], [3, 4], [5, 6] ]
6
Main> searchList 6 [ [1, 2], [3, 4], [5, 6] ]
-1
As an aside it is uncommon to use lists in Haskell if you want a fixed width, like the pairs in your list. It would be more Haskell-ish to use a list of tuples, like so.
searchListTuples x (y:ys) = if x == fst y then snd y else searchListTuples x ys
searchListTuples x [] = -1
Which of course behaves very similarly:
Main> searchListTuples 3 [ (1,2), (3,4), (5,6) ]
4
Main> searchListTuples 5 [ (1,2), (3,4), (5,6) ]
6
Main> searchListTuples 6 [ (1,2), (3,4), (5,6) ]
-1
Try with :
searchList x y = last $ head $ dropWhile (\[a,_]->a/=x) y
Or, in pointfree notation:
searchList = ((last . head) .) . dropWhile . (. head) . (/=)
I like this recursive function, but a "-1" as a bad value is not a normal Haskell idiom. Use Maybe.
searchListTuples x (y:ys) = if x == fst y then Just (snd y) else SearchListTuples x ys
searchListTuples x [] = Nothing

Resources