Counting the times of recursion in Haskell - loops

I am writing a small school assignment in Haskell to determine the distance between two given dates. I wrote a crude function to cycle through dates but I can't wrap my head around how to write loops in a Functional Programming way. I have only done procedural- and OOP-programming before. I somehow need to store the information of how many times I've called the nextDate-function but Haskell doesn't allow me to introduce a variable inside a function. Here is the code I've come up so far. It is not very Haskelly at all...
nextDate year month day =
if day + 1 < 31
then (year,month, day+1)
else if month + 1 < 12
then (year, month + 1, 1)
else (year +1,1,1)
calculateDifference year month day year2 month2 day2 =
let x = 0
if year == year2 && month == month2 && day == day2 then x
else
nextDate(year, month, day)
x = x + 1
-- How I would do it in Python
-- x = 0
-- while((tuple1) != (year2, month2, day2)):
-- x += 1
-- tuple1 = nextDate(tuple1)
-- print(x)

If you want to track how many times the function is called, you need to provide that as an input. There's no other way to do this, because Haskell only lets you work with arguments that are passed into the function.
For example, let's say I wanted to compute a factorial, but I wanted to track how many steps it took. My function signature could look like this:
factorial :: Int -> (Int, Int) -- Takes a number, returns the number and recursion count
factorialInternal :: (Int, Int) -> (Int, Int) -- This actually does the recursion
and then the definitions could look like this:
factorial n = factorialInternal (n, 0)
factorialInternal (1, n) = (1, n + 1)
factorialInternal (x, n) = let (y, z) = factorialInternal (x-1, n) in (x * y, z + 1)
Essentially, the parameter tracking the amount of recursion is incremented at each level, and then becomes part of the output of factorial.
It definitely helps to create an interface function so that you don't have to manually input the starting recursion level when using the function (which is always zero, anyway). An example of what your function signatures could look like:
-- The function you call
calculateDifference :: (Int, Int, Int) -> (Int, Int, Int) -> Int
-- What the calculateDifference function calls (the third parameter is the recursion counter)
calculateDifferenceInternal :: (Int, Int, Int) -> (Int, Int, Int) -> Int -> Int
From here, you should be able to figure out how to implement calculateDifference and calculateDifferenceInternal.
EDIT: As amalloy pointed out, a better solution is to just output the counter, not take one in: so instead of factorialInternal :: (Int, Int) -> (Int, Int), factorialInternal Int -> (Int, Int) would work. The definition would then look like:
factorialInternal 1 = (1, 0)
factorialInternal n = let (x, y) = factorialInternal (n - 1) in (n * x, y + 1)

Related

How to solve x + ceiling(x) +c = y, for x

I am working on a SQL server project to make conversion between two types of car prices (eg, x is the original price, y is the dealer asking price) based on some rules, so that for every given dealer asking price y, I can get a corresponding original price x. The conversion rule I am having trouble with is this one: x + 5*ceiling(x/100) + some constant c = y, x=?
(It's more of a math problem actually. For example, if the rule is as easy as x + 10 = y, then x = y-10.)
Indeed, it's a math problem, that should be asked on Mathematics Stack Exchange.
That said, note that in the equation x+ceil(x)+c=y, x and y-c differ only by an integer (that depends on x). And since x+ceil(x) is an increasing function of x, if there is a solution it's unique.
Another remark:
for x in (0,1], x+ceil(x) lies in (1,2].
for x in (1,2], x+ceil(x) lies in (3,4].
...
That is, there is a solution only if y-c is in (2n-1,2n] for some integer n. And then, x=y-c-n.
How do we find n? Well, y-c in (2n-1,2n] iff (y-c)/2 in (n-1/2,n]. So we must have n=ceil((y-c)/2).
It's not much more difficult for the equation x+5ceil(x/100)=y-c.
Now,
for x in (0,100], x+5ceil(x/100) in (5,105]
for x in (100,200], x+5ceil(x/100) in (110,210]
...
for x in (100(n-1), 100n], x+5ceil(x/100) in (105n-100,105n]
Again, some values can't be reached, and if there is a solution, it's unique.
And if y-c lies in (105n-100,105n] for some n, then x=y-c-5n.
Of course, you want to find n. Note that y-c in (105n-100,105n] iff (y-c)/105 is in (n-100/105,n], which is a subset of (n-1,n]. So if there is a solution, you must have n=ceil((y-c)/105).
Not a complete answer but for the simple case of
Y = X + Ceiling(X)
declare #X float = 3.7
declare #Y float = 0.0
SELECT #y = #x + ceiling(#x)
SELECT CASE
WHEN (#y -floor(#y)) = 0 THEN #y/2
ELSE (#y - (#y -floor(#y)) - 1)/2 + (#y -floor(#y))
END XValue
This works for all values of X that I've tested. The first case is for when X is a whole integer.
EDIT
For your case of Y = X + 5*CEILING(X)/100 we can surmise that if X is an integer then Y = X + 5/100 * X => 1.05 * X, if X is not an integer then y = X + 5/100(X+1) => 1.05*X + 0.05
So I think the following works for your case:
declare #X float = 3.1
declare #Y float = 0.0
SELECT #y = #x + 5*ceiling(#X)/100
SELECT CASE WHEN (ROUND(#y/1.05,0) = #y/1.05) THEN #y / 1.05
ELSE ROUND((#y - 0.05) / 1.05,2) END
For your case with a constant, I can't see how to solve this without knowing the constant.

How to loop multiple decay rate in multiple columns in pyspark

I try to pass a list in parameter of my function.
My list is composed of different coefficients to be apply to lag numerous columns.
However, I only manage to generate the columns in my dataframe for the first value of my list.
this is my actual result :
"col1", "col2", "col1_0.2", "col2_0.2"
what is expected :
"col1", "col2", "col1_0.2", "col2_0.2", "col1_0.4", "col2_0.4", "col1_0.6", "col2_0.6"
I must have missed a few things in my loop ?
selected_col = col_selector(df, ["col1", "col2"])
w = Window.partitionBy("student").orderBy("date")
coef = (.1,.4,.6)
def custom_coef(col, w, coef):
for x in coef:
return sum(
pow(i, x) * F.lag(F.col(col), i, default=0).over(w)
for i in range(1)
).alias(col +"_"+str(x))
new_df = df.select(
F.col("*"),
*[custom_coef(col, w, coef) for col in selected_col]
)
thanks
The return statement in the custom_coef function ends the function after the first execution of loop over coef. This means that custom_coef will always return the first column definition, and this is the column definition for coef 0.1. As the function is called once per column in selected_col you get the result that you are describing.
One way to fix the problem without changing the structure of the code is to replace return with yield. This way custom_coef creates one generator per element of selected_col. These generators can be chained with itertools.chain and this result can be used as parameter of the select statement:
def custom_coef(col, w, coef):
for x in coef:
yield sum( #use yield instead of return
pow(i, x) * F.lag(F.col(col), i, default=0).over(w)
for i in range(1)
).alias(col +"_"+str(x))
new_df = df.select(
F.col("*"),
*chain(*[custom_coef(col, w, coef) for col in selected_col]) #chain the generators
)
new_df.show()

How to do SUM on array from outside file?

I'm newbie college student for programming studies,
so recently i have task to calculate matrix from outside files for Gauss Jordan Numeric Method, in the txt file i provide has 10 (x) and (y) data, and declare with do functions to calculate the 10 data from the txt file each for x^2, x^3, x^4, xy, x^2y
my question is : how to SUM (calculate total) each x^2, x^3 ... that was calculated by program ? i try do sum file in below and still got errors (the first argument of sum must not a scalar.)
the Fortran apps i use was Plato cc from Silverfrost.
I apologize if my english bad and my pogram looks funny.
i have 10 data in my txt looks like these :
(x) (y)
12 10
5 6
28 8
9 11
20 17
6 24
32 9
2 7
1 30
26 22
in program below i open these files and want each x and y i provide read and calculate to get x^2, x^3, x^4, xy, x^2y
Program Gauss_Jordan
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Do k = 1,10
T(xj2) = SUM( xj2, dim=1)
T(xj3) = SUM (xj3, dim=1)
T(xj4) = SUM (xj4, dim=1)
T(xjyj) = SUM (xjyj, dim=1)
T(xj2yj) = SUM (xj2yj, dim=1)
End Do
End Do
Close(10)
End
for T(xj2) I want to get one result scalar result from SUM the all xj^2 that program has been calculated.
Like in excel was expected :
(A) is 1st xj^2 value that has been calculated
.
.
.
until (J) is 10th xj^2 value that has been calculated
sxj^2 = SUM(Xj^2)
SUM (A-J)
The 'sum' intrinsic needs an array argument, which we can compute from the input arrays without using a loop, so your program could be:
Program Gauss_Jordan
Real x(10), y(10), x2(10), x3(10), x4(10), xy(10), x2y(10)
Open(10, file='Data.txt')
Do j = 1, 10
Read (10, *) x(j), y(j)
End Do
Close(10)
x2 = x**2
x3 = x**3
x4 = x**4
xy = x*y
x2y = (x**2)*y
sx2 = SUM(x2)
sx3 = SUM(x3)
sx4 = SUM(x4)
sxy = SUM(xy)
sx2y = SUM(x2y)
End
From what I see I think you are misunderstanding what the SUM intrinsic does. Since your example isn't storing xj2, xj3 etc. in arrays, SUM isn't going to be useful to you. Instead you could declare totals as scalars (as you described you wanted) and simply add the individual xj2 variables in a loop as in the example below.
Also, you should get in the habit of using the implicit none declaration. It will save you from unexpected errors due to spelling mistakes.
Program Gauss_Jordan
implicit none
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
real :: Txj2,Txj3,Txj4,Txjyj,Txj2yj
integer :: j
Txj2 = 0
Txj3 = 0
Txj4 = 0
Txjyj= 0
Txj2yj= 0
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Txj2 = Txj2 + xj2
Txj3 = Txj3 + xj3
Txj4 = Txj4 + xj4
Txjyj = Txjyj + xjyj
Txj2yj = Txj2yj + xj2yj
End Do
print *, 'Txj2 = ', Txj2
Close(10)
End
When I ran this I got the output below which is what I believe you intended:
3175

Is there anything possible idea of 'cyclic arithmetic operation' for some specific data type?

In integer-based data type like tinybit, smallbit, bigint, int, uint...
sometimes arithmetic overflow could be found when result is out of range of that data type.
The expression I used, 'cyclic arithmetic operation', that means,
(-1) 2 -> 1 -> 0 -> 255 -> 254 ... (tinybit)
or
(+2) 65533 -> 65535 -> 1 -> 3 ... (smallbit)
etc..
In other words, I want 0 - 1 = 255 in tinybit columns.
I know it's little awkward and everyone have avoided this kind of situation but is there anyone who have solution for this? The reason I ask is not only to avoid arithmetic overflow but also practical need. So "consider extending or changing your column data type!" will not be suitable in my case.
Applying a bit mask seems to be the most straightforward way to do this:
SELECT -10 & 255; -- Results in 246
SELECT 513 & 255; -- Results in 1
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/bitwise-operators-transact-sql
SQL Server does have a modulus operator, %, which might help here. Using it, you can do something like this:
DECLARE #inputValue INT = -1;
DECLARE #outputValue TINYINT;
DECLARE #minValue INT = 0;
DECLARE #maxValue INT = 255;
DECLARE #maxValues INT = 256;
SELECT #outputValue =
CASE
WHEN #inputValue < #minValue THEN #inputValue % #maxValues + #maxValues
ELSE #inputValue % #maxValues
END;
SELECT #outputValue; -- Results in 255
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/modulo-transact-sql

Convert Bit String To Array in PostgreSQL

I have a 160 chars bit string and I need to have an integer array that stores the position of the bits that have a value of 1.
Example:
bitstring = '00110101'
array = [3,4,6,8]
Is it possible to do this just with SQL or do I need to define a PL/SQL function or something like that?
It's assuredly possible to write it in SQL. Here's a starting point:
select array(
select substring(str from i for 1) as bit
from generate_series(1, length(str)) as i
where bit = '1'
);
You might want to wrap that in a pl/sql function regardless, though, so to avoid duplicating code all over the place.
Working function:
create or replace function get_bit_positions(varbit) returns bit[] as $$
select array(
select substring($1 from i for 1) as bit
from generate_series(1, length($1)) as i
where substring($1 from i for 1) = '1'
);
$$ language sql immutable;
Working version:
WITH x AS (SELECT '00110101'::varbit AS b)
SELECT array_agg(i)
FROM (SELECT b, generate_series(1, length(b)) AS i FROM x) y
WHERE substring(b, i, 1) = '1';
Simpler once you convert the varbit to text[]. Cast to text and run string_to_array().
Then you can use generate_subscripts() and pick array elements by index:
WITH x AS (SELECT string_to_array('00110101'::varbit::text, NULL) AS b)
SELECT array_agg(i)
FROM (SELECT b, generate_subscripts(b,1) AS i FROM x) y
WHERE b[i] = '1'
Details in this related question on dba.SE.

Resources