Splitting a given rectangle into n subrectangles - list
Preliminary remarks
I am learning Haskell.
A question that I answered some days ago gave me the inspiration for this exercise in Haskell, which gave the opportunity for experimenting with the few things that I've learned up to now, and also left me with questions :)
Problem statement
Given a rectangle A of width w and height h find the best rectangle B that fits n times within A, where best means having the smallest perimeter.
My attempt
I've started with the basic idea of generating the set of sub-rectangles of A having an area equal to div (w * h) n, and then picking the one having the smallest perimeter.
Here are the three implementations of this idea that I came up with; they're in chronological order: I got the inspiration for the third after having done the second, which I got after having done the first (OK, there's a version 0, in which I didn't use data Rectangle but just a tuple (x, y)):
Implementation 1
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle [ r ] = r
bestSubRectangle (r:rs)
| perimeter r < perimeter bestOfRest = r
| otherwise = bestOfRest
where bestOfRest = bestSubRectangle rs
perimeter :: Rectangle -> Integer
perimeter r = (width r) + (height r)
Implementation 2
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle xs = foldr smaller (last xs) xs
smaller :: Rectangle -> Rectangle -> Rectangle
smaller r1 r2
| perimeter r1 < perimeter r2 = r1
| otherwise = r2
perimeter :: Rectangle -> Integer
perimeter r = (width r) + (height r)
Implementation 3
import Data.List
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show, Eq)
instance Ord Rectangle where
(Rectangle w1 h1) `compare` (Rectangle w2 h2) = (w1 + h1) `compare` (w2 + h2)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle = head . sort
Questions
Which approach is more idiomatic?
Which approach is better in terms of performance? bestSubRectangle in Implementation 3 depends on sort, which is at best O(n lg n), while in Implementation 1, 2 bestSubRectangle requires only scanning the array returned by subRectangles, thus making it O(n). However I'm not sure if/how Haskell laziness works on bestSubRectangle = head . sort: will sort produce only the first element of the sorted array, because of head requiring only the first element (head (x:_) = x)?
In implementation 3, when making Rectangle an instance of Ord should I also define the other methods of the Ord class? Is this the right way to make Rectangle an instance of Ord?
Any further suggestion/recommendation to improve is highly welcome.
To answer your questions about Haskell (and not about the algorithm you've choosen):
I'd say your second implementation is most idiomatic.
You are right that the problem needs only a linear scan, so that sort is likely to be more expensive than needed. You are also asking the right question when asking if, due to laziness, head . sort will compute only the first element of the result of the sort. It will, but depending on how sort is implemented, that may very well rely on sorting the whole list before it can return the first element. You should assume that it does.
You can tell from the documentation for Ord that compare is sufficient. The key phrase is Minimal complete definition: either compare or <=. Many type classes have similar use patterns. You should feel free to write a minimal implementation where they do.
Some other observations about your code (again, not the algorithm):
Function calls bind tighter than operators, as in most languages - just in Haskell there are no parenthesis around the arguments. Hence you would write perimeter r = width r + height r
If you are folding over a list that must have at least one element, you can use foldr1 as in bestSubRectangle xs = foldr1 smaller xs
Your instance of Ord for Rectangle doesn't agree with the derived instance of Eq. That is, there are values which will compare as EQ but would return False for ==. In this case, I wouldn't try to bend Rectangle's general purpose instance of Ord for purposes of perimeter comparison, and instead go with the smaller predicate you wrote in the second implementation.
Seems like you are calculating too much, inductively going through posibilities of n (number of rectangles we wish to fill up our given rectangle) we should get:
n = 1 => always returns the given rectangle
n = 2 => always returns the 2 rectangles given by bisecting the given rectangle on the longest side, i.e. gives the 2 most square rectangles
n = 3 => same as 2 using 3, divide equally along longest side.
n = 4 More complicated, essentially the question comes up is it better to put the same rectangle 4 times in a row OR is is better to bisect both length and width into a 2x2 group of rectangle. For larger numbers of n it is also a question of these configuration of factors > 1
--Essentially this is a question of factoring n, dividing the length and width by the each of the factors THEN choosing the configuration where the divided length & width (i.e. the length and width of the resulting filler rectangles) are MOST SIMILAR, (most square-like). Also note it is not necessary to try all factors against all sides. The most square rectangle will be taking the larger factor against the longer side.
n = number of filler rectangles
l = longest of width or height of container rectangle
s = shortest of width or height container rectangle
h1 = height of candidate rectangle 1
w1 = width of candidate rectangle 1
d = difference of candidate dimensions
t = smallest difference in candidate height and width (initialize t to l)
b = best fit
Therefore the steps become:
1: Factor n
2: for each factor pair of n:
(l/largest factor) - (s/smaller factor) = d
if d < t:
t = d
store current best candidate rectangle
3: Return best fit remaining after all factors have been tried
Related
Find size of rectangles to fill area
I got trouble need your help: I'm working on a program that shows n videos in tiling mode (aka, videos wall, c columns and r rows). The n is arbitrary, the videos have same size (W x H) and we have W / H ratio, the size of wall is fixed, how can I get best set of c, r, W and H when n changes? The best set defined as: W and H is maximum values and videos fill maximum area of the wall. I have taken a look at Packing Problem but still can't solve my problem above, can someone help me this? Thank you very much!
As far as I understand, you want to place n rectangles with fixed C=W/H ratio on the wall with given Width and Height Let rectangle height is h (unknown yet), width is w = C * h Every row of grid contains nr = Floor(Width / (C * h)) // rounding down Every column contains nc = Floor(Height / h) Write inequality n <= nc * nr n <= Floor(Width / (C * h)) * Floor(Height / h) and solve it (find maximal possible h value) for unknown h For real values of parameters h might be found getting initial approximate value: h0 = Ceil(Sqrt(Width * Height / (n * C))) and decrementing h value until inequality becomes true
How do i remove items from a list with specific rules in haskell?
Basically i have a tupple of positions from an 8 x 8 chess board like so chessboard = [(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8),(1,0), (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(2,0),(2,1),(2,2),(2,3), (2,4),(2,5),(2,6),(2,7),(2,8),(3,0),(3,1),(3,2),(3,3),(3,4),(3,5),(3,6), (3,7),(3,8),(4,0),(4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(4,7),(4,8),(5,0), (5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(5,7),(5,8),(6,0),(6,1),(6,2),(6,3), (6,4),(6,5),(6,6),(6,7),(6,8),(7,0),(7,1),(7,2),(7,3),(7,4),(7,5),(7,6), (7,7),(7,8),(8,0),(8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8)] I need to be able to place 8 queens on the chess board without each one being able to kill another one. I figured out a method to do this: if a queen is, for example, on (0,0) then no positions containing the same row or column is allowed, so I can remove (0,1), (0,2), (0,3) ... (x,y+1) and (1,0) , (2,0), (3,0) ... (x+1,y) from the chessboard list. So if my queen is on (0,0), how can i remove all the tupples that are (x, y+1) , (x+1,y) , (x+1, y+1), (x-1,y-1) ? I'm leaning towards recursion, but cannot figure it out.
You can use filter :: (a -> Bool) -> [a] -> [a]. Note that the the first argument - the predicate - actually decides what to keep. Not what to remove (so if it says True that means it puts the element in the resulting list): So in order to remove all values with x = 0, you can use filter (\(x,_) -> x /= 0) chessboard Or filter out all elements with y equal to k: filtery k = filter (\(_,y) -> y /= k) You can filter out all elements that attack a queen positioned at (xq,yq) with: filterqueen :: (Int,Int) -> [(Int,Int)] -> [(Int,Int)] filterqueen (xq,yq) = filter noattack where noattack (x,y) = xq /= x && yq /= y && dx /= dy && dx /= -dy where dx = x-xq dy = y-yq
C++ Creating function to draw the hypotenuse - Trigonometry
I understand how to calculate the hypotenuse a^2 + b^2 = c^2, sqrt(c) = hypotenuse. And I am aware there are some relevant answers already on stackoverflow, but they are immersed in terminology I don't understand(yet) as a beginner programmer. As this is more programming orientated I haven't been able to find anything relevant on math websites either. If you have a right angle triangle * | 7.07 * | 5 * | * | *_ _ _ _ _ | 5 How do I increment x and y (x,y) in cartesian format, so that I can draw in pixels SetPixel(myDC, x, y, COLOUR); I somehow understand the concept of sin, cos and tan and their inverses, but can not for the life of me figure out how to increment (x,y) together in relation to the size of the adjacent and opposite lengths.
Well they would be incremented relative to each other. So, if the legs of the triangle are of equal length, then the x and y increments should also be equal. Similarly, if one leg is, say, 3 and the other 4, then x and y should be incremented such that for each each x and y increment (x,y), x=4y/3 or y=4x/3.
You can draw the hypotenuse with graphic functions for drawing lines between two points. Otherwise you can calculate the straight line equation passing for two points: y=mx + n and you avoid trigonometry functions.
Haskell: Call a function with each element in a list
I am making a sudoku solving program and I have a potentialNbrsAt function that gets the numbers that could be at position x y. Now, I am trying to get the intersect of each lists of potential numbers in a column. Something like the onlyOnePlaceForNbrInCol function bellow. Code: potentialNbrsAt :: Int -> Int -> Sudoku -> [Int] potentialNbrsAt x y sudoku = intersect rowMissingNbrs $ intersect colMissingNbrs sqrMissingNbrs where rowMissingNbrs = getMissingNbrs $ getRow y sudoku colMissingNbrs = getMissingNbrs $ getCol x sudoku sqrMissingNbrs = getMissingNbrs $ getSquare squareIndex sudoku squareIndex = 3 * (y `div` 3) + (x `div` 3) onlyOnePlaceForNbrInCol :: Int -> Int -> Sudoku -> Bool onlyOnePlaceForNbrInCol colIndex nbr sudoku = -- What goes here? Some pointers please??? I think onlyOnePlaceForNbrInCol should, at some point, call potentialNbrsAt with each numbers from 0 to 8 as an argument for y. Telling me how to do this would greatly help.
What about [ potentialNbrsAt x y sudoku | y <- [0..8] ] ? This gives you a list of all the results for such values of y.
So you're trying to determine whether all of the numbers [0..8] fulfill a given predicate.
elem function of no limit list
list comprehension haskell paar = [(a,b) | a<-[a | a<-[1..], mod a 3 == 0], b<-[b*b | b<-[1..]]] a = divisor 3 b = square The Elements must be constructed by equitable order. the test >elem (9, 9801) must be True my Error Main> elem (9, 9801) test ERROR - Garbage collection fails to reclaim sufficient space How can I implement this with Cantor's diagonal argument? thx
Not quite sure what your goal is here, but here's the reason why your code blows up. Prelude> let paar = [(a,b) | a<-[a | a<-[1..], mod a 3 == 0], b<-[b*b | b<-[1..]]] Prelude> take 10 paar [(3,1),(3,4),(3,9),(3,16),(3,25),(3,36),(3,49),(3,64),(3,81),(3,100)] Notice you're generating all the (3, ?) pairs before any other. The elem function works by searching this list linearly from the beginning. As there are an infinite number of (3, ?) pairs, you will never reach the (9, ?) ones. In addition, your code is probably holding on to paar somewhere, preventing it from being garbage collected. This results in elem (9, 9801) paar taking not only infinite time but also infinite space, leading to the crash you described. Ultimately, you probably need to take another approach to solving your problem. For example, something like this: elemPaar :: (Integer, Integer) -> Bool elemPaar (a, b) = mod a 3 == 0 && isSquare b where isSquare = ... Or alternatively figure out some other search strategy than straight up linear search through an infinite list.
Here's an alternate ordering of the same list (by hammar's suggestion): -- the integer points along the diagonals of slope -1 on the cartesian plane, -- organized by x-intercept -- diagonals = [ (0,0), (1,0), (0,1), (2,0), (1,1), (0,2), ... diagonals = [ (n-i, i) | n <- [0..], i <- [0..n] ] -- the multiples of three paired with the squares paar = [ (3*x, y^2) | (x,y) <- diagonals ] and in action: ghci> take 10 diagonals [(0,0),(1,0),(0,1),(2,0),(1,1),(0,2),(3,0),(2,1),(1,2),(0,3)] ghci> take 10 paar [(0,0),(3,0),(0,1),(6,0),(3,1),(0,4),(9,0),(6,1),(3,4),(0,9)] ghci> elem (9, 9801) paar True By using a diagonal path to iterate through all the possible values, we guarantee that we reach each finite point in finite time (though some points are still outside the bounds of memory). As hammar points out in his comment, though, this isn't sufficient, as it will still take an infinite amount of time to get a False answer. However, we have an order on the elements of paar, namely (3*a,b^2) comes before (3*c,d^2) when a + b < c + d. So to determine whether a given pair (x,y) is in paar, we only have to check pairs (p,q) while p/3 + sqrt q <= x/3 + sqrt y. To avoid using Floating numbers, we can use a slightly looser condition, that p <= x || q <= y. Certainly p > x && q > y implies p/3 + sqrt q > x/3 + sqrt y, so this will still include any possible solutions, and it's guaranteed to terminate. So we can build this check in -- check only a finite number of elements so we can get a False result as well isElem (p, q) = elem (p,q) $ takeWhile (\(a,b) -> a <= p || b <= q) paar And use it: ghci> isElem (9,9801) True ghci> isElem (9,9802) False ghci> isElem (10,9801) False