How to generate random triangle on a unit circle - haskell

I'm trying to find out the probability of the center of a unit circle falling inside a triangle. The vertexes of the triangle are randomly picked on the unit circle.
My idea is to pick a random float x in the range (-1.0, 1.0) and then randomly select up or down. This will get me one point (x, +/-sqrt(1 - x*x))
import Data.Random
main = do
x <- randomRIO (-1.0,1.0)
let y = (sample (randomElement [-1,1])) * sqrt(1-x*x)) -- I can't make this line work
So how do I select a random element from a [Int] ?

I don't speak Haskell, but to choose a point on a circle with even distribution, the variable you need to pick is the angle.
angle <- randomRIO(-pi, pi)
then
y = sin(angle)
x = cos(angle)
Pick 3 angles for your 3 dots and that gives you a random triangle.
As for testing if the center is in the triangle, I am fairly certain, though I have no demonstration so far, that you can go as follows:
Find the longest edge. The edge splits the circle in 2 parts
If the third vertex is in the smallest part, the center is not in the triangle
Else, it is
Edit, Demonstration
Let, ABC be a triangle in the circle of center D.
Let AB be the longest edge
Let C be on the largest half of the circle cut by AB
If D is not in ABC, then either AC or BC (for simplicity and since this is just naming convention, let assume AC) is the edge of the triangle that between AB and D
AC and AB being chords of the circle, the closest to the center is the longest
AC is longer than AB
How to apply this to angles only
From the previous demonstration, it quickly appears that if all 3 points are in the same half, the center is not in the triangle, otherwise it is.
The point is therefore to determine that the maximum distance between 2 points is pi.
Thanks to J. Abrahamson, we can compute the difference between all three points' angles, and sum the smaller two, return true if the sum is greater than pi.
The actual measurement of the distance between 2 points goes like this, as we need the absolute and most direct distance between the 2:
Compute the absolute distance diff = abs(theta1 - theta2)
If this is more than pi, use 2 * pi - diff

Look into the MonadRandom package, the uniform function will give you a random value from a list of values ([Int] in your case). I'm on my phone, but finding the package shouldn't be too tough. If you want to use a different distribution, look into random-fu.

An example of this using the MonadRandom package instead (cabal install MonadRandom):
import Control.Monad.Random
type R a = Rand StdGen a -- Just a type alias for less typing
type Point = (Double, Double)
type Triangle = (Point, Point, Point)
-- Monadic action
genAngle :: R Double
genAngle = getRandomR (-pi, pi)
-- Monadic action
genPoint :: R Point
genPoint = do
x <- genAngle
return (cos x, sin x)
-- Monadic action
genTriangle :: R Triangle
genTriangle = do
a <- genPoint
b <- genPoint
c <- genPoint
return (a, b, c)
-- Pure function
containsOrigin :: Triangle -> Bool
containsOrigin (a, b, c) = ??? -- You get to implement this (#njzk2 has given some pointers)
-- Monadic action
genTriangles :: R [Triangle]
genTriangles = do
tri <- genTriangle
rest <- genTriangles -- Recursion to get infinite list
return $ tri : rest
-- Monadic action
genTrianglesWithOrigin :: R [Triangle]
genTrianglesWithOrigin = do
triangles <- genTriangles
return $ filter containsOrigin triangles
main :: IO ()
main = do
triangles <- fmap (take 10) $ evalRandIO genTrianglesWithOrigin
mapM_ print triangles
If you want more reading on why MonadRandom is nicer than the base random package, I would recommend looking at this section of Learn You A Haskell. Basically, MonadRandom builds a nicer interface where not everything is in IO (which is dangerous, who knows what an IO function does) and provides some easy functions for generating random numbers, whereas the random package just provides the most barebones functionality possible. In fact, the Rand monad is nothing more than the State monad in disguise, it just keeps up with the state of your generator seed for you.

Related

Haskell - Creating rectangle of 1s with height and width of user input

I am trying to create a function that will take two integer values that correspond to the width and height of a rectangle of 1s that is outputted like so:
Main> rectangle 3 4
1111
1111
1111
I am a beginner at Haskell and have no experience, so any pointers would be appreciated, and therefore only basic Haskell operations should be used. Thanks.
rectangle :: Int -> Int -> String
rectangle h w = unlines (replicate h (replicate w '1'))
Although this is a pure function, it does show the relevant part. You can just putStrLn (rectangle 3 4) to have it printed out as expected in ghci, rather than wrapped in a show.
Giving it a second thought, here's a short walkthrough.
replicate :: Int -> a -> [a]
unlines :: [String] -> String
As you can see, replicate w '1'creates a list of w times the charakter 1. Because String = [Char], the result is a String of ones, as many as w says.
Now, this String is replicated again, h times, giving a list of h times that string.
unlines now concatenates those strings, inserting a new line character between the strings.
The result is what you'd expect, only that ghci (which you appear to be using) is wrapping each expression's result in a show call. So, to do exactly what you want to achieve, a call to putStr in needed as so:
impureRectangle :: Int -> Int -> IO ()
impureRectangle x y = putStr (rectangle x y)
Note that monads (or IO, as the first monad, people use to get to know as such) are not the easiest things to get your head around. I'd suggest staying pure until you feel safe.

"Linear" package truncating values close to 0 when using `normalize`

I've spent a few minutes debugging a problem that tracked down to "Linear" truncating values that are close to zero when using "Linear.normalize". Specifically, I was taking the cross product of very small triangles and normalizing the result, which, surprisingly, behaved wrongly until I noticed what was wrong and multiplied the cross product by 10000.
Why is that even necessary? How can I get rid of that behavior?
Edit: just for fun, here is a video of the bug. Notice that the sphere loses the color when the number of triangles approximating it is big enough? Yes, good luck debugging that...!
Looking at the source for normalize, you'll see that it's defined as
-- | Normalize a 'Metric' functor to have unit 'norm'. This function
-- does not change the functor if its 'norm' is 0 or 1.
normalize :: (Floating a, Metric f, Epsilon a) => f a -> f a
normalize v = if nearZero l || nearZero (1-l) then v else fmap (/sqrt l) v
where l = quadrance v
What this means is that if the magnitude of your points is really close to 0 you're going to end up with the wrong value. To avoid this you can write your own normalize function without this check as
normalize' :: (Floating a, Metric f) => f a -> f a
normalize' v = fmap (/ sqrt l) v where l = quadrance v
And with any luck it should solve your problem.
Another way around this might be to scale up your values, perform the computations, then scale them back down, something like
normalize' factor = (* factor) . normalize . (/ factor)
So you might call
normalize' 10e-10 (V3 1e-10 2e-10 3e-10)
instead, but this could easily introduce rounding errors due to how IEEE floating point numbers are stored.
EDIT: As cchalmers points out this is already implemented as signorm in Linear.Metric, so use that function instead.

Haskell Gloss Particle Effects

How to create particle effects in Haskell using the Gloss library? (e.g. to show an explosion)
If anyone could help me out a bit on how this is done it'd be much appreciated.
Best Regards,
Skyfe.
The comment on the question does a good job of providing a high-level solution, but I'm writing this answer to add detail.
Let's start by modeling the real-world object we want to represent. In our case, it's a particle. A particle ought to have a position, a velocity and an acceleration, all of which we can represent using 2D vectors. A reasonable way to store 2D vectors in Haskell is to use the Linear.V2 module. Next, let's think about nice additional properties we'd like a particle should have, specifically one involved in a firework or explosion. Notice how the particles in a firework burn bright for a time and then just 'fizzle out'? Let's call said time the particle's lifespan, and represent it using a Float. We can now create an appropriate representation for a Particle and a Cluster of Particles
data Particle = Particle
{ _age :: Float
, _lifespan :: Float
, _position :: V2 Float
, _velocity :: V2 Float
, _acceleration :: V2 Float }
deriving ( Show )
type Cluster = [Particle]
makeLenses ''Particle
There's an extra field called age in our datatype above. The lifespan of the particle represents the time for which the particle exists from creation to death, while its age represents the time that has passed since the Particle's creation. In other words, a Particle should disappear when its age exceeds its lifespan. Keep that in mind for later.
Next, let's write a function that helps us create a Particle. All it does is set the initial age to 0 and leave the rest up to additional arguments
makeParticle :: Float -> V2 Float -> V2 Float -> V2 Float -> Particle
makeParticle = Particle 0
Once this is done, we can write a function that helps us create a Cluster of n particles
makeCluster :: Int -> (Int -> Particle) -> Cluster
makeCluster n particleGen = map particleGen [0..(n - 1)]
After that, we create a function that will allow us to advance a Particle by dt seconds. The function advances the Particle's
age, changes its position based on its velocity and finally changes its velocity based on its acceleration. In the end, if the age of the Particle is more than its lifespan, we symbolize the deletion of the Particle by evaluating to Nothing instead of Just the changed particle.
advanceParticle :: Float -> Particle -> Maybe Particle
advanceParticle dt = hasDecayed . updateVel . updatePos . updateAge
where
r2f = realToFrac
hasDecayed p = if p^.age < p^.lifespan then Just p else Nothing
updateAge p = (age %~ (dt +)) p
updatePos p = (position %~ (r2f dt * p^.velocity +)) p
updateVel p = (velocity %~ (r2f dt * p^.acceleration +)) p
The following function advances a Cluster, and gets rid of 'dead' Particles
advanceCluster :: Float -> Cluster -> Cluster
advanceCluster dt = catMaybes . map (advanceParticle dt)
Now we can move on to the part of the code that has to do with actually drawing particles using Graphics.Gloss. We're going to use a Cluster to represent the state of the simulation, and so we start with a function that returns a Cluster representing the initial state of the program. For a simple animation we're going to simulate a firework, where all the particles start in the same position, have the same lifespan, radiate out from their central position at regular angles, and are subject to the same acceleration
initState :: Cluster
initState = makeCluster numParticles particleGen
where
numParticles = 10
particleGen :: Int -> Particle
particleGen i =
makeParticle initLifespan
initPosition
(initVelMagnitude * V2 (cos angle) (sin angle))
initAcceleration
where
fI = fromIntegral
angle = (fI i) * 2 * pi / (fI numParticles)
initLifespan = 10
initPosition = V2 0 0
initVelMagnitude = 5
initAcceleration = V2 0 (-3)
Then we write a function to draw a Cluster on to the screen
drawState :: Cluster -> Picture
drawState = pictures . map drawParticle
where
drawParticle :: Particle -> Picture
drawParticle p =
translate (p^.position._x) (p^.position._y) .
color (colorAdjust (p^.age / p^.lifespan)) .
circleSolid $ circleRadius
where
circleRadius = 3
colorAdjust a = makeColor 1 0 0 (1 - a)
Probably the only non-standard part about this is the colorAdjust function. What I was going for here was to color a Particle red and when it's created have it not be transparent at all (i.e. alpha value of 1) and keep fading out as its age approaches its lifespan (i.e. alpha value that keeps approaching 0)
We're almost done! Add a function that updates the Cluster to reflect the passage of time
stepState :: ViewPort -> Float -> Cluster -> Cluster
stepState _ = advanceCluster
Finish up the program by writing a main function that ties everything together
main :: IO ()
main =
simulate (InWindow name (windowWidth, windowHeight)
(windowLocX, windowLocY))
bgColor
stepsPerSec
initState
drawState
stepState
where
name = "Fireworks!"
windowWidth = 300
windowHeight = 300
windowLocX = 30
windowLocY = 30
stepsPerSec = 30
bgColor = white
I hope this helps!

How to add an element to a list of a data type in Haskell

I have defined two data types: Point and Curve. Point has two doubles for its coordinates and a Curve has a starting Point and a list of Points representing the rest of the Curve. I need to make a function that creates this Curve given a starting Point and a list of Points but I can't quite understand how am I supposed to add an element to the list of Points inside the Curve.
Here is my code:
data Point = Point Double Double deriving (Eq, Show)
point :: (Double, Double) -> Point
point (x, y) = Point x y
data Curve = Curve Point [Point] deriving (Eq, Show)
curve :: Point -> [Point] -> Curve
curve x [] = Curve x []
curve x [y] = Curve x [y]
curve x (y:ys) = curve x (y:ys)
I am pretty sure my recursion in the end is wrong. So could you give me maybe some guidelines on how to add a point in the list?
thanks
myCurve = Curve (Point 2 2) [Point 3 3, Point 4 4, Point 5 5]
Wait, what, you say? Indeed, Curve is already that function you want. It is both a type constructor (the left-hand-side in the data definition) and a value constructor (the right hand side.)
If you probe Curve with ghci, you will find...
Prelude> :t Curve
Curve :: Point -> [Point] -> Curve
The same goes for Point. In other words, the entirety of your code looks like this:
data Point = Point Double Double deriving (Eq, Show)
data Curve = Point [Point] deriving (Eq, Show)
EDIT: An ultra-small primer on value constructors.
When you create a new datatype, you automatically create a value constructor, which is a function that creates a value of the new type. It's not entirely clear in your example because the type and value constructors have the same name, which is permissible in Haskell because one lives in the type level and the other in the value level. Let's try and make it a bit more obvious:
data MyIntType = MakeIntType Int
Now, MakeIntType is a function that takes one argument, an Int, and creates a value of type MyIntType. Let's check that in ghci:
Prelude> :t MakeIntType
MakeIntType :: Int -> MyIntType
Now, we could write an identical function, like you're proposing:
makeIntType :: Int -> MyIntType
makeIntType x = MakeIntType x
or, dropping the explicit points (arguments):
makeIntType = MakeIntType
Both equation shows that we've duplicated work. There is no functional difference between makeIntType and MakeIntType. They are completely equivalent, and since you will always get the value constructor function "for free," makeIntType is a completely superfluous alias for something that's already there.
I hope that clears things up a bit.
Edit 2: Creating a new modified Curve based on an existing one
addPointToStartOfCurve p (Curve p' ps) = Curve p (p':ps)
Here, we create a new Curve from an existing one by pushing the first element of the existing Curve onto the list of points and adding a new starting point. Another variant would add a point to the end of an existing Curve.
addPointToEndOfCurve p (Curve p' ps) = Curve p' (ps ++ [p])
Note that because of immutability, the original curves aren't altered, we're just producing new values.

Functional equivalent to iterating over a 2D array

I have this function in Haskell (I am using the Haskell-SDL library):
pixel :: Surface -> Int16 -> Int16 -> Pixel -> IO Bool
pixel screen x y color
I want to use this to take a 2D array (or some other kind of data structure) and draw it to the screen, one pixel at a time. I looked into doing it with forM_ but can't figure out how to get it to operate on the x and y arguments.
I'm pretty new to Haskell and functional programming in general. I'm working my way through Yet Another Haskell Tutorial but this problem just has me stumped.
In case it's relevant to the solution, I'm trying to write a raytracer. It has to perform a calculation for each pixel, then write that pixel to the screen.
If you are using nested lists, do:
import Control.Monad
plot :: Surface -> [[Pixel]] -> IO ()
plot surf = zipWithM_ (\ y -> zipWithM_ (\ x c -> pixel surf x y c) [0..]) [0..]
You need to split two problems here. First you need to compute the pixel value. This should be a pure function of the scene and the coordinate of the ray you are firing into it. Then you need to write that pixel value to the screen.
So first you want a function:
type Coord = (Int, Int)
raytrace :: Scene -> Coord -> (Coord, Colour)
-- You will see why it returns this pair in a few lines
Then you want to call that function for every pixel in your surface, to get a list of coordinate-colour pairs:
allCoords :: Int -> Int -> [Coord]
allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]]
allPixels :: Scene -> Int -> Int -> [(Coord, Colour)]
allPixels scene w h = map (raytrace scene) (allCoords w h)
And finally put the list of pixels onto the display surface using your "pixel" function.
writeScene :: Surface -> Scene -> Int -> Int -> IO ()
writeScene surface scene w h = mapM_ writePixel (allPixels scene w h)
where writePixel ((x,y),c) = pixel surface x y c
The only thing is, your "pixel" function returns an "IO Bool". I don't know why, so I've ignored it by using "mapM_" rather than "mapM".
This looks like it builds a horribly inefficient list of coordinate-colour pairs and then iterates through it to draw the picture. But in fact, thanks to the lazy nature of Haskell, it actually compiles down to a loop that generates each colour and then calls "pixel" on the result.
Haskell has real arrays of various kinds. To me it seems like you're doing something quite inefficient, you want to create a pixel buffer and blit it to another buffer? it would be much more efficient to create a new SDL surface (for which you can get/set pixels) and blit that to another surface/screen or create a real array of pixels and create SDL surface with that then use SDL's blit routines. If you explain what you're trying to do I think we can show you a better way.

Resources