Remembering old data - loops

Remembering your first time (in a Haskell loop)
I am trying to teach myself a little Haskell by going through some Hackerrank questions.
The question I am looking at involves reading in sets of co-ordinates (x1,y1) and (x2,y2) and
Determining the perimeter of the polygon drawn by those co-ordinates.
Here is my code so far:
-- Calculate length of line given points x1,y2, x2,y2
calc_length:: Int -> Int -> Int -> Int -> Float
calc_length x1 y1 x2 y2 =
sqrt ( fromIntegral (height ^2 + width ^2) )
where height = abs( y2 - y1)
width = abs( x2 - x1)
main = do
x <- readLn :: IO Double
forM_ [1,2..(x / 2)] $ \lc -> do
line1 <- getLine
let wds1 = map (\str -> read str::Int) (words $ line1)
line2 <- getLine
let wds2 = map (\str -> read str::Int) (words $ line2)
print ( wds1, wds2)
The problem I have is that I need to calculate the distance between the first and last co-ordinates I.e. REMEMBER the first pair of numbers entered ( stored in line1). But after multiply iterations the first pair will be lost. I have tried using global variables to store the first calling of getLine (with little success, and even if that had worked I don’t it think it would help.)
I get the feeling that there is a more functional approach I could try but just don’t know how.
I am not looking for a full coded solution just an approach that points me in a better direction.
Any thoughts?

You asked for a more functional way of thinking about this, so I'm going to try to provide that. You said you're new to Haskell, so I apologize in advance if this touches on things you haven't explored yet. Feel free to ask for clarification in any part of it.
First off, let's segment your calcLength function a bit more. We're passing it two points, so rather than passing four arguments, let's pass only two.
data Point a = Point a a
calcLength :: Floating a => Point a -> Point a -> a
calcLength (Point x1 y1) (Point x2 y2) = sqrt (height ^ 2 + width ^ 2)
where height = abs (y2 - y1)
width = abs (x2 - x1)
Now let's write a function that reads a single point. We'll call this from main rather than reading two numerical values separately in main.
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = Point <$> readLn <*> readLn
I'm using applicative syntax here. If you're more familiar with do-notation, the equivalent would be
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = do
x <- readLn
y <- readLn
return $ Point x y
Now for the meat of your question. We want to take a list of things (points in your case) and produce adjacent pairs, making sure to loop around to the beginning. Let's stop thinking about it in terms of points for a moment and just write a function that works on any list of things.
-- We're going to take a list of things and produce a list of pairs of those things
loopedPairs :: [a] -> [(a, a)]
-- If the original list is empty, return the empty list
loopedPairs [] = []
-- Otherwise, start recursing
loopedPairs (x:xs) = go x xs
-- Here, we're pairing off all the elements
where go x' (y:ys) = (x', y) : go y ys
-- Because we defined this as an inner function, we can still access
-- the original first element, effectively "remembering" it like you
-- were asking about. Note that we never use any "global" storage or
-- mutable state to do this, just a bit of variable scope.
go x' [] = [(x', x)]
Now we'll write a perimeter function. It's good to separate as much of your "pure" non-IO logic from the IO work as possible, so we want to factor this out of main.
newtype Polygon a = Polygon [Point a]
perimeter :: Floating a => Polygon a -> a
perimeter (Polygon xs) = sum . map (\(a, b) -> calcLength a b) $ loopedPairs xs
We take a polygon, which is really just a list of points, pair off all of our points using loopedPairs, then calculate the length between each of them and sum the results.
With that in mind, main is fairly short.
main :: IO ()
main = do
n <- readLn :: IO Int
points <- replicateM n (readPoint :: IO (Point Double))
let result = perimeter (Polygon points)
print result
We read in the number of points, then we read each point (replicateM essentially means "do this thing n times and accumulate the result into a list). Then we calculate the perimeter and print it out.
Runnable solution:
import Control.Monad
data Point a = Point a a
newtype Polygon a = Polygon [Point a]
calcLength :: Floating a => Point a -> Point a -> a
calcLength (Point x1 y1) (Point x2 y2) = sqrt (height ^ 2 + width ^ 2)
where height = abs (y2 - y1)
width = abs (x2 - x1)
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = Point <$> readLn <*> readLn
loopedPairs :: [a] -> [(a, a)]
loopedPairs [] = []
loopedPairs (x:xs) = go x xs
where go x' (y:ys) = (x', y) : go y ys
go x' [] = [(x', x)]
perimeter :: Floating a => Polygon a -> a
perimeter (Polygon xs) = sum . map (\(a, b) -> calcLength a b) $ loopedPairs xs
main :: IO ()
main = do
n <- readLn :: IO Int
points <- replicateM n (readPoint :: IO (Point Double))
let result = perimeter (Polygon points)
print result
I invite you to dissect this, and let me know if you have any questions at all. Functional programming is a tricky mindset to get into, because it's very different from other programming, but it's a handy set of techniques to have in your toolbelt.

If you need to treat the first iteration differently, it should be separated (if I understand your problem correctly). You can reduce duplication by using a helper function:
getNumLine :: IO [Int]
getNumLine = do
line <- getLine
return (map read (words line))
main = do
x <- readLn :: IO Int -- Double seemed wrong, use integer `div` below instead
firstline <- getNumLine
forM_ [2..x `div` 2] $ \lc -> do
...
And yes you could be much more "functional" about this, but I think it's best to learn in baby steps.

After everbodys help: my final solution:
import Data.List
import Data.Foldable
import Data.Traversable
import Data.List.Split
-- Calculate length of line given points x1,y2, x2,y2
calc_length:: Int -> Int -> Int -> Int -> Float
calc_length x1 y1 x2 y2 =
sqrt ( fromIntegral (height ^2 + width ^2) )
where height = abs( y2 - y1)
width = abs( x2 - x1)
-- Calculate the distances between vertex points (except the last)
getResults list =
sum [ calc_length (head f) (last f) (head s) (last s) | (f,s) <- (zip list (tail list)) ]
-- Calculate the last vertex distance between points
headAndTail list =
calc_length (z!!0) (z!!1) (z!!2) (z!!3)
where z = head list ++ last list
-- Prompt the user for co-ordinate pairs
main = do
x <- readLn :: IO Double
result <- forM [1,2..x ] ( \lc -> do
line1 <- getLine
let wds1 = map (\str -> read str::Int) (words $ line1)
return wds1)
print ( (getResults result) + (headAndTail result) )

Related

Creating a 2D array in IDL starting from an equation

I'm trying to make a contour plot in IDL of quantity described by and equation, which here I'll take to be x^2 + y.
In order to do that, I first need to create a 2D array ("pxx").
Being a novice, I'm currently just moving my fist step into this direction and so far I've been trying to make this simpler foreach loop work:
pxx=fltarr(10, 10)
xx = indgen(10)
yy = indgen(10)
foreach k, xx do begin
pxx[k,*]=3*k
endforeach
print, pxx
But this only seems to work for the last column. Any idea on how to fix that? And how would you suggest I proceed to create a 2D array in space for the equation above?
Thank you in advance, any help is appreciated
Choose the range of x and y values you want to evaluate on:
n = 10
x = findgen(n) - (n - 1)/2.0
y = findgen(n) - (n - 1)/2.0
Expand x and y to 2-dimensional versions of themselves:
xx = rebin(reform(x, n, 1), n, n)
yy = rebin(reform(y, 1, n), n, n)
Evaluate the function:
z = xx^2 + yy
Plot:
contour, z, x, y

Load stl file in matlab and convert to a 3D array

I have a stl file and I've loaded it in Matlab using stlread function. At this point I have a set of faces and vertices. How can I convert these faces and vertices in a 3D binary array like 512x512x100 array to obtain a binary 3D volume?
Ah lucky you. I am working with STL files recently and I coded some functions to do exactly this.
First, note that you lose precision. STL files represent arbitrary shapes with arbitrary precision and converting it into a volume results in discretization and losses.
That said, there is a very easy method to know if something is inside or outside a closed, connected triangulated surface, regardless if its convex or not: Throw a ray to the infinite and count intersection with the surface. If odd, its inside, if even, outside.
The only special code you need is the line-triangle intersection, and the Möller Trumbore algorithm is one of the most common ones.
function in=inmesh(fv,points)
%INMESH tells you if a point is inside a closed,connected triangulated surface mesh
% Author: Ander Biguri
maxZ=max(fv.vertices(:,3));
counts=zeros(size(points,1),1);
for ii=1:size(points,1)
ray=[points(ii,:);points(ii,1:2) maxZ+1];
for jj=1:size(fv.faces,1)
v=fv.vertices(fv.faces(jj,:),:);
if all(v(:,3)<ray(1,3))
continue;
end
isin=mollerTrumbore(ray, fv.vertices(fv.faces(jj,:),:));
counts(ii)=counts(ii)+isin;
end
end
in=mod(counts,2);
end
From FileExchange, with small modifications:
function [flag, u, v, t] = mollerTrumbore (ray,tri)
% Ray/triangle intersection using the algorithm proposed by Moller and Trumbore (1997).
%
% IMPORTANT NOTE: Assumes infinite legth rays.
% Input:
% ray(1,:) : origin.
% d : direction.
% tri(1,:), tri(2,:), tri(3,:): vertices of the triangle.
% Output:
% flag: (0) Reject, (1) Intersect.
% u,v: barycentric coordinates.
% t: distance from the ray origin.
% Author:
% Jesus Mena
d=ray(2,:)-ray(1,:);
epsilon = 0.00001;
e1 = tri(2,:)-tri(1,:);
e2 = tri(3,:)-tri(1,:);
q = cross(d,e2);
a = dot(e1,q); % determinant of the matrix M
if (a>-epsilon && a<epsilon)
% the vector is parallel to the plane (the intersection is at infinity)
[flag, u, v, t] = deal(0,0,0,0);
return;
end
f = 1/a;
s = ray(1,:)-tri(1,:);
u = f*dot(s,q);
if (u<0.0)
% the intersection is outside of the triangle
[flag, u, v, t] = deal(0,0,0,0);
return;
end
r = cross(s,e1);
v = f*dot(d,r);
if (v<0.0 || u+v>1.0)
% the intersection is outside of the triangle
[flag, u, v, t] = deal(0,0,0,0);
return;
end
if nargout>3
t = f*dot(e2,r); % verified!
end
flag = 1;
return
end
Just generate your points:
yourboundaries=% get the range of your data from the STL file.
[x,y,z]=meshgrid(yourboundaries);
P=[x(:) y(:) z(:)];
in=inmesh(fv,P);
img=reshape(in,yourboundariesSize);

Standard ML running multiple functions in a loop (Using recursion or any other means)

I have defined three different functions that will perform calculations and return a value. These functions will consistently be redefining a variable until a specific condition is reached. I am having issues getting these to run in a "loop" scenario. I know functional languages are not best for performing loops and you should use recursion...but I am having a hard time wrapping my head around how to perform this.
I will make some real simple arbitrary functions to explain my situation.
fun add_them (a,b) =
a+b;
fun substract_them (c,d) =
c-d;
fun add_them2 (e,f) =
e-f;
val a = 5;
val b = 7;
val c = 10;
val d = 1;
val a = add_them (a,b);
val d = add_them2 (c,d);
So let's say I want to run the last two lines a 1000 times. So Val A and Val D will keep getting added up to a huge number. Now I could literally copy and paste those two lines a 1000 times and get the result I want..but this of course defeats the purpose of programming :)
I was trying to create a loop that I can throw these two functions in. I was coming up with something like below, but I would have no idea how to incorporate these two. Perhaps I am going at this completely backwards.
fun whileloop (x,a) =
if (a<1)
then x
else whileloop(x+1,a-1);
So my goal was to insert those above val a and val d expressions into another function using recursion and run it a certain amount of times. Any help would be much appreciated.
A function that simply iterates another function n times is given in my answer here. But it sounds like you want to apply a given function n times to a seed, like so:
f (f (f (f ... (f x) ... )))
That can be accomplished by the following function:
fun repeat n f x = if n = 0 then x else repeat (n-1) f (f x)
For example,
val n = repeat 20 (fn => n + 1) 0
results in 20.
Or perhaps you want to repeat based on a condition instead of a count:
fun repeatWhile p f x = if p x then repeatWhile p f (f x) else x
For example,
val n = repeatWhile (fn x => x > 0) (fn x => x - 1) 20
returns 0.
Both functions are polymorphic, so also work with tuples. For example:
val (x, y) = repeatWhile (fn (a, b) => a > 0) (fn (a, b) => (a-1, b+1)) (20, 0)
returns (0, 20).
If you dislike using two separate function parameters for condition and "action", you can also combine them by having it return a pair:
fun repeatWhile2 f x =
let val (c, y) = f x in if c then repeatWhile2 f y else x end
Then:
repeatWhile (fn (a, b) => (a > 0, (a-1, b+2))) (20, 0)

Value error in drawing the contourf plot

I want to draw the contourf of a certain function and my code was as follows:
xlist = linspace(0, 100, 100)
ylist = linspace(0, 100, 200)
X, Y = meshgrid(xlist, ylist)
#print "X = " + str(X)
#print "Y = " + str(Y)
Z = power_at_each_point(X, Y)
#print "Z = " + str(Z)
figure()
CP2 = contourf(X, Y, Z)
colorbar(CP2)
title('Contour Plot')
xlabel('Room-x (m)')
ylabel('Room-y (m)')
show()
The function power_at_each_point(X,Y) when I test it alone I write:
print power_at_each_point(50, 50)
and the output is -80.9187477018
which basically represents the power reached to this point in the room and it outputs a number normally but when I call it after the meshgrid command it returns an error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I want to take each coordinate of points in the room x-coord and y-coord and calculate the power reached at this point using the power_at_each_point method
which is supposed to return a number and I'd represent it in the contourf plot.
My guess is that the arguments (X,Y) of Z = power_at_each_point changed from being just numbers to being arrays which I don't want and that's what is causing the error.
How can I let the function Z = power_at_each_point(X,Y) take as arguments X as a number ex :1 and Y ex :2 and return a value for the power at this point so that I can represent it in my contourf plot.
Any help would be appreciated.
I've found that the function meshgrid wants a Matrix pretty much as an argument so I went ahead and created a Matrix called Z and I filled by myself the values in it and then I went ahead and entered Z as an argument to the meshgrid function:
x_list = linspace(0, 100, 100)
y_list = linspace(0, 100, 100)
X, Y = meshgrid(x_list, y_list)
Z = [[0 for x in range(len(x_list))] for x in range(len(y_list))]
for each_axes in range(len(Z)):
for each_point in range(len(Z[each_axes])):
Z[each_axes][each_point] = power_at_each_point(each_axes, each_point)
figure()
CP2 = contourf(X, Y, Z)
and that got me the result I wanted as far as I was asking here.
The points is reversed in the Z Matrix or as you can say mirrored along the horizontal but that's something i'm gonna play with so that I can get those elements in Z to match how the meshgrid actually sets it's grid points.

Function with input (a,b,c) that results in output (x,z,y)

So I'm working on a process that will allow me to calculate subobject normals for models I am putting into a game. Basically, I know how to calculate them but I need to create a function that can use this bit of code.
local sin, asin = math.sin, math.asin
local deg, rad = math.deg, math.rad
math.sin = function (x) return sin(rad(x)) end
math.asin = function (x) return asin(deg(x)) end --Makes math.sin read in degrees instead of radians
x = function (sin (a))
z = function (sin (b))
y = function (sin (c))
d = {a, b, c}
end
e = {x, z, y}
end
repeat
print("Enter a value for x:")
a = io.read("*number") -- read a number
print(math.sin(a))
print("Do you want to repeat? Type 1 to repeat")
a = io.read("*number")
until a ~= 1
The way it works is that the sine of the angle that the subobject was rotated becomes the normal value on that axis. (z = b because Blender operates in X-Y horizontal and the game is in X-Z horizontal)
Basically, I am looking for a function the allows me to input "array d" and get the output displayed as "array e" instead of that single output function. a, b, and c are variables, not constants.
A function in python can be defined as -
def myfunc(a,b,c):
x = sin (a)
z = sin (b)
y = sin (c)
return x,y,z
or you can input an array -
def myfunc(arr):
x = sin (arr[0])
z = sin (arr[1])
y = sin (arr[2])
return {x,y,z}
Notice that you can return multiple numbers stored in different ways, depending on your needs.

Resources