Find triangle in the graph - haskell

I have a graph like this:
As part of a homework assignment I want to find the triangle (1->2->5). I have no idea how to find this.
In my case, I defined my graph:
type Graph = (Int, Int -> Int -> Bool)
g 2 3 = True
g 3 2 = True
g 1 2 = True
g 2 1 = True
g 1 1 = True
g n m = False
Answer to 2 comment.
I did this and it works, I think.
triangles :: [(Int, Int, Int)]
triangles = [(x, y, z) | x <- [1..3], y <- [1..x], z <- [1..y], isTriangle (x, y, z)]
isTriangle :: (Int, Int, Int) -> Bool
isTriangle (x, y, z) = g x y && g y z && g x z
I removed (_,g) and (n,g) (I dont understand why we need them :)
I call trinagles and it return (1,1,1) (2,1,1) (in my case). Is it right?

I guess the first Int of Graph is a bound for your nodes (like, 6 if the nodes are in [1..6]).
Therefore, you would like a function that returns the triangles of a graph, so the type might be:
triangles :: Graph -> [(Int, Int, Int)]
Now, a triangle exists whenever, for 3 nodes, say x y and z, all the combinations return True through g.
So, you might want to consider generating all these combinations (possibly avoiding the ones that are equivalent via re-ordering), and filter out only those that validate the criterion:
isTriangle :: Graph -> (Int, Int, Int) -> Bool
isTriangle (_, g) (x, y, z) == g x y && g y z && g x z
For this, you could use a list comprehension, or the function filter which has type (a -> Bool) -> [a] -> [a]
Answer to your first comment:
First, you would need to implement the triangles function, which is the reason of the error. But, as you have done in test, you could simply generate these triangles on the fly.
Now, you wrote:
test = filter (isTriangle) [(x,y,z) | x <- [1..3], y <- [1..3], z <- [1..3]]
Two things about this:
First, you wouldn't need the parentheses around isTriangle for what you wrote, but it is incorrect, since isTriangle expects a graph as its first parameter
Second, you are going to obtain a lot of duplicates, and if you want, you can prevent this by not generating them in the first place:
test = filter (isTriangle) [(x,y,z) | x <- [1..3], y <- [1..x], z <- [1..y]]
Alternatively, you can dismiss the filter function by providing a guard in the list comprehension syntax, as this:
[(x, y, z) | x <- [1..3], y <- [1..x], z <- [1..y], isTriangle yourGraph (x, y, z)]
Now, I'll let you go on with the details. You will want to make this a function that takes a graph, and to replace this 3 by the number of nodes in the graph, and yourGraph by said graph.
Since you chose to use list comprehension, forget about the generating function that I wrote about earlier, its purpose was just to generate input for filter, but with the list comprehension approach you won't necessarily need it.
Answer to your second comment:
You want to write a function:
triangles :: Graph -> [(Int, Int, Int)]
triangles (n, g) = [(x, y, z) | ...]
The ... are to be replaced with the correct things, from earlier (ranges for x, y and z, as well as the predicate isTriangle).
Alternatively, you can cut this in two functions:
allTriangles :: Int -> [(Int, Int, Int)]
allTriangles n = [(x, y, z) | ...]
graphTriangles :: Graph -> [(Int, Int, Int)]
graphTriangles (n, g) = [t | t <- allTriangles n, isGraphTriangle t]
where isGraphTriangle (x, y, z) = ...
This way, you could potentially reuse allTriangles for something else. If you don't feel the need, you can stay with the one-shot big comprehension triangles, since it's a homework you probably won't build up on it.
I try not to fill all the ... so that you can do it yourself and hopefully understand :)
Correcting your solution:
First, my mistake on the ranges, it should be x <- [1..n], y <- [x+1..n], z <- [y+1..n] where n denotes the number of nodes in your graph. This way, you only capture triples where x < y < z, which ensures that you only see one occurence of each set of three points.
Second, the reason why I put the graph as a parameter to the functions is that you might want to reuse the same function for another graph. By hardcoding g and 6 in your functions, you make them really specific to the particular graph you described, but if you want to compute triangles on a certain number of graphs, you do not want to write one function per graph!

I don’t really like your graph type but whatever. Here’s the algorithm we will use:
First find a Node x of the graph.
For every other node y see if it connects to x
If y does connect to x then for each node z, see if it connects to x and y
If so then return it.
To avoid duplicates, we require z<x<y
nodes (n,_) = [1..n]
nodesBefore (n,_) k = [1..min n (k - 1)]
edge (_,e) x y = e x y
neighboursBefore g x = [ y | y <- nodesBefore g x, edge g x y]
triangles g = [(x,y,z) | x <- nodes g, y <- neighboursBefore g x, z <- neighboursBefore g y, edge g x z]

Related

What can be the problem with my haskell code and how can I fix it?

deadNeighbors:
Give a list of empty cells that have a living cellular neighbor in that generation. Make sure that each cell is listed only once!
Something not work with my deadNeighbors function, but I do not know what is wrong about it. Can anybody help me to fix deadNeighbors ?
type Coordinate = (Integer, Integer)
type Generation = [Coordinate]
single :: Generation
single = [ (42, 42) ]
row :: Generation
row = [ (10, 1), (10, 2), (10, 3) ]
Code:
neighbors :: Coordinate -> [Coordinate]
neighbors (x,y) = [(x-1,y-1), (x-1,y), (x-1,y+1), (x ,y-1), (x,y+1), (x+1,y-1), (x+1,y), (x+1,y+1)]
alive :: Generation -> Coordinate -> Bool
alive x y = elem y x
livingNeighbors :: Generation -> Coordinate -> Int
livingNeighbors a = length .filter (alive a) . neighbors
staysAlive :: Generation -> Coordinate -> Bool
staysAlive a b
| alive a b = livingNeighbors a b `elem` [2,3]
| otherwise = livingNeighbors a b `elem` [3]
Problems:
deadNeighbors :: Generation -> [Coordinate]
deadNeighbors (neighbors (x,y))
|(alive (x,y)) = Nothing
|otherwise = [] ++ (x,y)
Examples:
sort (deadNeighbors single) == sort [(41.41), (41.42), (41.43), (42.41), (42.43), (43.41), (43.42) , (43.43)]
sort (deadNeighbors row) == sort [(9.0), (9.1), (9.2), (10.0), (11.0), (11.1), (11.2) , (9.3), (11.3), (9.4), (10.4), (11.4)]
Let's go over deadNeighbors function line by line:
(the type signature looks fine)
deadNeighbors (neighbors (x,y))
This is a clause of the deadNeighbors function and seems to use pattern matching notation, however you use the function neighbors in the pattern match. That is not allowed. I don't really know what your intention is here, so I cannot suggest a way to fix this.
|(alive (x,y)) = Nothing
Here you are using a guard correctly, but the alive function requires the generation in addition to the coordinate. You should pass both as arguments here.
Also, you are returning Nothing which has type Maybe a for some a. But the signature of the deadNeighbors function indicates it should return a [Coordinate]. Perhaps you intended to write [] (the empty list)?
|otherwise = [] ++ (x,y)
Here you are using the ++ operator, which expects two lists as arguments, with an empty list [] as argument and a coordinate (x,y). The coordinate type is not a list, so it is not compatible with the ++ operator. Perhaps you intended (x,y) : [] or just [(x,y)] (which means the same thing but is slightly prettier)?

Simplify haskell function

I'm really struggling with Haskell atm.
It took me almost 6 hours to write a function that does what I want. Unfortunately I'm not satisfied with the look of it.
Could someone please give me any hints how to rewrite it?
get_connected_area :: Eq generic_type => [[generic_type]] -> (Int, Int) -> [(Int,Int)] -> generic_type -> [(Int,Int)]
get_connected_area habitat point area nullValue
| elem point area = area
| not ((fst point) >= 0) = area
| not ((snd point) >= 0) = area
| not ((fst point) < (length habitat)) = area
| not ((snd point) < (length (habitat!!0))) = area
| (((habitat!!(fst point))!!(snd point))) == nullValue = area
| otherwise =
let new_area = point : area
in
get_connected_area habitat (fst point+1, snd point) (
get_connected_area habitat (fst point-1, snd point) (
get_connected_area habitat (fst point, snd point+1) (
get_connected_area habitat (fst point, snd point-1) new_area nullValue
) nullValue
) nullValue
) nullValue
The function get's a [[generic_type]] (representing a landscape-map) and searches the fully connected area around a point that isn't equal to the given nullValue.
Eg.:
If the function gets called like this:
get_connected_area [[0,1,0],[1,1,1],[0,1,0],[1,0,0]] (1,1) [] 0
That literally means
0 1 0
1 1 1
0 1 0
1 0 0
Represents a map (like google maps). Start from the point (coordinates) (1,1) I want to get all coordinates of the elements that form a connected area with the given point.
The result therefore should be:
0 1 0
1 1 1
0 1 0
1 0 0
And the corresponting return value (list of coordinates of bold 1s):
[(2,1),(0,1),(1,2),(1,0),(1,1)]
One small change is that you can use pattern matching for the variable point. This means you can use (x, y) instead of point in the function declaration:
get_connected_area habitat (x, y) area nullValue = ...
Now everywhere you have fst point, just put x, and everywhere you have snd point, put y.
Another modification is to use more variables for subexpressions. This can help with the nested recursive calls. For example, make a variable for the inner-most nested call:
....
where foo = get_connected_area habitat (x, y-1) new_area nullValue
Now just put foo instead of the call. This technique can now be repeated for the "new" inner-most call. (Note that you should pick a more descriptive name than foo. Maybe down?)
Note that not (x >= y) is the same as x < y. Use this to simplify all of the conditions. Since these conditions test if a point is inside a bounding rectangle, most of this logic can be factored to a function isIn :: (Int, Int) -> (Int, Int) -> (Int, Int) -> Bool which will make get_connected_area more readable.
This would be my first quick pass through the function, and sort of the minimum that might pass a code review (just in terms of style):
getConnectedArea :: Eq a => [[a]] -> a -> (Int, Int) -> [(Int,Int)] -> [(Int,Int)]
getConnectedArea habitat nullValue = go where
go point#(x,y) area
| elem point area = area
| x < 0 = area
| y < 0 = area
| x >= length habitat = area
| y >= length (habitat!!0) = area
| ((habitat!!x)!!y) == nullValue = area
| otherwise =
foldr go (point : area)
[ (x+1, y), (x-1, y), (x, y+1), (x, y-1) ]
We bind habitat and nullValue once at the top level (clarifying what the recursive work is doing), remove indirection in the predicates, use camel-case (underdashes obscure where function application is happening), replace generic_type with a (using a noisy variable here actually has the opposite effect from the one you intended; I end up trying to figure out what special semantics you're trying to call out when the interesting thing is that the type doesn't matter (so long as it can be compared for equality)).
At this point there are lots of things we can do:
pretend we're writing real code and worry about asymptotics of treating lists as arrays (!!, and length) and sets (elem), and use proper array and set data structures instead
move your bounds checking (and possible null value checking) into a new lookup function (the goal being to have only a single ... = area clause if possible
consider improvements to the algorithm: can we avoid recursively checking the cell we just came from algorithmically? can we avoid passing area entirely (making our search nicely lazy/"productive")?
Here is my take:
import qualified Data.Set as Set
type Point = (Int, Int)
getConnectedArea :: (Point -> Bool) -> Point -> Set.Set Point
getConnectedArea habitat = \p -> worker p Set.empty
-- \p is to the right of = to keep it out of the scope of the where clause
where
worker p seen
| p `Set.member` seen = seen
| habitat p = foldr worker (Set.insert p seen) (neighbors p)
| otherwise = seen
neighbors (x,y) = [(x-1,y), (x+1,y), (x,y-1), (x,y+1)]
What I've done
foldr over the neighbors, as some commenters suggested.
Since the order of points doesn't matter, I use a Set instead of a list, so it's semantically a better fit and faster to boot.
Named some helpful intermediate abstractions such as Point and neighbors.
A better data structure for the habitat would also be good, since lists are linear time to access, maybe a 2D Data.Array—but as far as this function cares, all you need is an indexing function Point -> Bool (out of bounds and null value are treated the same), so I've replaced the data structure parameter with the indexing function itself (this is a common transformation in FP).
We can see that it would also be possible to abstract away the neighbors function and then we would arrive at a very general graph traversal method
traverseGraph :: (Ord a) => (a -> [a]) -> a -> Set.Set a
in terms of which you could write getConnectedArea. I recommend doing this for educational purposes—left as an exercise.
EDIT
Here's an example of how to call the function in terms of (almost) your old function:
import Control.Monad ((<=<))
-- A couple helpers for indexing lists.
index :: Int -> [a] -> Maybe a
index _ [] = Nothing
index 0 (x:_) = x
index n (_:xs) = index (n-1) xs
index2 :: (Int,Int) -> [[a]] -> Maybe a
index2 (x,y) = index x <=< index y
-- index2 uses Maybe's monadic structure, and I think it's quite pretty.
-- But if you're not ready for that, you might prefer
index2' (x,y) xss
| Just xs <- index y xss = index x xs
| otherwise = Nothing
getConnectedArea' :: (Eq a) => [[a]] -> Point -> a -> [a]
getConnectedArea' habitat point nullValue = Set.toList $ getConnectedArea nonnull point
where
nonnull :: Point -> Bool
nonnull p = case index2 p habitat of
Nothing -> False
Just x -> x /= nullValue
OK i will try to simplify your code. However there are already good answers and that's why i will tackle this with a slightly more conceptual approach.
I believe you could chose better data types. For instance Data.Matrix seems to provide an ideal data type in the place of your [[generic_type]] type. Also for coordinates i wouldn't chose a tuple type since tuple type is there to pack different types. It's functor and monad instances are not very helpful when it is chosen as a coordinate system. Yet since it seems Data.Matrix is just happy with tuples as coordinates i will keep them.
OK your rephrased code is as follows;
import Data.Matrix
gca :: Matrix Int -> (Int, Int) -> Int -> [(Int,Int)]
gca fld crd nil = let nbs = [id, subtract 1, (+1)] >>= \f -> [id, subtract 1, (+1)]
>>= \g -> return (f,g)
>>= \(f,g) -> return ((f . fst) crd, (g . snd) crd)
in filter (\(x,y) -> fld ! (x,y) /= nil) nbs
*Main> gca (fromLists [[0,1,0],[1,1,1],[0,1,0],[1,0,0]]) (2,2) 0
[(2,2),(2,1),(2,3),(1,2),(3,2)]
The first thing to note is, the Matrix data type is index 1 based. So we have our center point at (2,2).
The second is... we have a three element list of functions defined as [id, subtract 1, (+1)]. The contained functions are all Num a => a -> a type and i need them to define the surrounding pixels of the given coordinate including the given coordinate. So we have a line just like if we did;
[1,2,3] >>= \x -> [1,2,3] >>= \y -> return [x,y] would result [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]] which, in our case, would yield a 2 combinations of all functions in the place of the numbers 1,2 and 3.
Which then we apply to our given coordinate one by one with a cascading instruction
>>= \[f,g] -> return ((f . fst) crd, (g . snd) crd)
which yields all neighboring coordinates.
Then its nothing more than filtering the neighboring filters by checking if they are not equal to the nil value within out matrix.

How to remove certain coordinates from a list

I'm new to Haskell and was trying to make a grid function which returns all the coordinates in the grid as a list. I want to filter this list to remove any coordinates where x = y given [(x,y)] (essentially getting rid of all the diagonal coordinates in the grid) but I'm not sure how to do it. Any help/pointers would be appreciated.
grid :: Int -> [(Int,Int)]
grid n = [(x,y) | x <- [0..n], y <- [0..n]]
Your function was good enough, just add a filter on it:
grid :: Int -> [(Int,Int)]
grid n = [(x,y) | x <- [0..n], y <- [0..n], x /= y]
using a filter (x /= y) in the list comprehensions is pretty simple and describes what you try to accomplish.
You should use filter.
The following predicate is True for non-diagonal elements:
predicate (x,y)=x/=y
Then you can define your filter:
gridFilter g=filter predicate g
Run it with:
gridFilter $ grid 2
Yields:
[(0,1),(0,2),(1,0),(1,2),(2,0),(2,1)]
Of course you can also make it a one-liner:
gridFiltered=filter (\(x,y)->x/=y) $ grid 2

Pythagorean triple in Haskell without symmetrical solutions

I gotta do the Pythagorean triple in Haskell without symmetrical solutions. My try is:
terna :: Int -> [(Int,Int,Int)]
terna x = [(a,b,c)|a<-[1..x], b<-[1..x], c<-[1..x], (a^2)+(b^2) == (c^2)]
and I get as a result:
Main> terna 10
[(3,4,5),(4,3,5),(6,8,10),(8,6,10)]
As you can see, I´m getting symmetrical solutions like: (3,4,5) (4,3,5). I need to get rid of them but I don´t know how. Can anyone help me?
Every time you have a duplicate you have one version in which a is greater than b and one where b is greater than a. So if you want to make sure you only ever get one of them, you just need to make sure that either a is always equal to or less than b or vice versa.
One way to achieve this would be to add it as a condition to the list comprehension.
Another, more efficient way, would be to change b's generator to b <- [1..a], so it only generates values for b which are smaller or equal to a.
Speaking of efficiency: There is no need to iterate over c at all. Once you have values for a and b, you could simply calculate (a^2)+(b^2) and check whether it has a natural square root.
Don't know Haskell at all (perhaps you're learning it now?) but it seems like you could get rid of them if you could take only the ones for which a is less than or equal to b. That would get rid of the duplicates.
Try with a simple recursive generator:
http://en.wikipedia.org/wiki/Formulas_for_generating_Pythagorean_triples
(new article)
http://en.wikipedia.org/wiki/Tree_of_primitive_Pythagorean_triples
EDIT (7 May 2014)
Here I have made infinite generator that can generate primitive triplets ordered by perimeter (but can be modified to be ordered by other parameter - hypotenuses, area, ...) as long as it holds that any triplet is smaller that any generated from generator matrix according to provided compare function
import Data.List -- for mmult
merge f x [] = x
merge f [] y = y
merge f (x:xs) (y:ys)
| f x y = x : merge f xs (y:ys)
| otherwise = y : merge f (x:xs) ys
mmult :: Num a => [[a]] -> [[a]] -> [[a]]
mmult a b = [ [ sum $ zipWith (*) ar bc | bc <- (transpose b) ] | ar <- a ]
tpgen_matrix = [[[ 1,-2, 2],[ 2 ,-1, 2],[ 2,-2, 3]],
[[ 1, 2, 2],[ 2 , 1, 2],[ 2, 2, 3]],
[[-1, 2, 2],[-2 , 1, 2],[-2, 2, 3]]]
matrixsum = sum . map sum
tripletsorter x y = ( matrixsum x ) < ( matrixsum y ) -- compare perimeter
triplegen_helper b = foldl1
( merge tripletsorter )
[ h : triplegen_helper h | x <- tpgen_matrix , let h = mmult x b ]
triplets = x : triplegen_helper x where x = [[3],[4],[5]]
main = mapM print $ take 10 triplets
You can do the following:
pythagorean = [ (x,y,m*m+n*n) |
m <- [2..],
n <- [1 .. m-1],
let x = m*m-n*n,
let y = 2*m*n ]
This might work: Got it from this tutorial
triangles x = [(a,b,c) | c <- [1..x], b <- [1..c], a <- [1..b] , a^2 + b^2 == c^2]
List comprehension syntax makes this easy:
triplets :: Integer -> [(Integer, Integer, Integer)]
triplets d = [(a,b,c) | a <- [1..d], b <- [a..d], c <- [b..d], a^2 + b^2 == c^2]
This basically says than we build a list from as,bs and cs, where a changes from 1 to d, b changes from current a to d and etc. It also says that a^2 + b^2 == c^2 should hold.

Graph representation in Haskell

I have chosen to represent a graph in Haskell by a list of nodes (ex. n=[1,2,3,4]) and a list of pairs representing the edges (example m=[(1,2), (2,3)]). Now I have to see if the graph is strongly connected.
My main issue is how to find if there is a way between 2 nodes in the graph. I wrote something like that:
-- sees if 2 nodes are adjacent
adjacent x y [] = False
adjacent x y (mu:m) =
if(x== (fst mu) && y==(snd mu)) then True
else adjacent x y m
-- the successor of a node, ex for the edge (1,2) the succ of 1 is 2
suc x [] = 0
suc x (l:list) =
if(x==(fst l)) then snd l
else suc x list
-- my main function
way 0 y list = False
way x y (mu:m)
| x==y = True
| (adjacent x y (mu:m)) == True = True
| otherwise =
if ((way (suc x (mu:m)) y (mu:m))==False) then way (suc x m) y m
else True
It works when I have nodes of degree 1, but for the nodes with a greater degree it doesn't always work. Can you give me a clue about it?
Here are some questions to ask yourself:
Should adjacent 3 2 [(1,2),(2,3)] be True?
How many successors to 1 are there in the graph [(1,2),(2,3),(1,4),(3,4)]
Why does, or doesn't, way need to have both a x==y case and an adjacent x y ... case?
In the recursion step of way does the == False test really tell you something that lets you recurse on the smaller graph of m?
In general, you haven't written type signatures for your top level functions. It is usually very instructive to do so, and will communicate your design more clearly:
type Vertex = Int
type Edge = (Vertex, Vertex)
type Graph = [Edge]
adjacent :: Vertex -> Vertex -> Graph -> Bool
suc :: Vertex -> Graph -> Vertex
way :: Vertex -> Vertex -> Graph -> Bool
Think about if those types make sense, and if they decompose your problem as you would expect, just thinking about graphs in general.
Is your aim really the way function, or is it to determine if the graph is connected? You might be presupposing too much about the way in which you can determine if the graph is connected.
Lastly, a small part about Haskell syntax: Like most other languages, function application binds very tightly, tighter than == and && operators. Unlike most other languages, function application doesn't use parenthesis. Hence, adjacent can be recoded as:
adjacent x y [] = False
adjacent x y (mu:m) =
if x == fst mu && y == snd mu then True
else adjacent x y m
Which in turn could be simplified to:
adjacent x y [] = False
adjacent x y (mu:m) = (x == fst mu && y == snd mu) || adjacent x y m
You have two errors of understanding:
m, your list of edges is static throughout the entire search. Don't eat it up as you recur in way.
Each vertex can have more than one edge leaving it. You want to know whether any of the neighbours of x has a way to y. To find the neighbours you first have to filter the list of edges to find only the edges leaving x.
You also need to build up a list of nodes you've already visited on your quest to find a connection. If you end up on a node you've already seen, then that particular path has failed.
Some hints to make your code a lot shorter: for adjacent, try elem.
For succ, try Data.Maybe.fromMaybe and lookup.

Resources