Problem detecting cyclic numbers in Haskell - haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give):
p3 n = n*(n+1) `div` 2
p4 n = n*n
p5 n = n*(3*n -1) `div` 2
p6 n = n*(2*n -1)
p7 n = n*(5*n -3) `div` 2
p8 n = n*(3*n -2)
x n = take 2 $ show n
x2 n = reverse $ take 2 $ reverse $ show n
pX p = dropWhile (< 999) $ takeWhile (< 10000) [p n|n<-[1..]]
isCyclic2 (a,b,c) = x2 b == x c && x2 c == x a && x2 a == x b
ns2 = [(a,b,c)|a <- pX p3 , b <- pX p4 , c <- pX p5 , isCyclic2 (a,b,c)]
And all ns2 does is return an empty list, yet cyclic2 with the arguments given as the example in the question, yet the series doesn't come up in the solution. The problem must lie in the list comprehension ns2 but I can't see where, what have I done wrong?
Also, how can I make it so that the pX only gets the pX (n) up to the pX used in the previous pX?
PS: in case you thought I completely missed the problem, I will get my final solution with this:
isCyclic (a,b,c,d,e,f) = x2 a == x b && x2 b == x c && x2 c == x d && x2 d == x e && x2 e == x f && x2 f == x a
ns = [[a,b,c,d,e,f]|a <- pX p3 , b <- pX p4 , c <- pX p5 , d <- pX p6 , e <- pX p7 , f <- pX p8 ,isCyclic (a,b,c,d,e,f)]
answer = sum $ head ns

The order is important. The cyclic numbers in the question are 8128, 2882, 8281, and these are not P3/127, P4/91, P5/44 but P3/127, P5/44, P4/91.
Your code is only checking in the order 8128, 8281, 2882, which is not cyclic.
You would get the result if you check for
isCyclic2 (a,c,b)
in your list comprehension.

EDIT: Wrong Problem!
I assumed you were talking about the circular number problem, Sorry!
There is a more efficient way to do this with something like this:
take (2 * l x -1) . cycle $ show x
where l = length . show
Try that and see where it gets you.

If I understand you right here, you're no longer asking why your code doesn't work but how to make it faster. That's actually the whole fun of Project Euler to find an efficient way to solve the problems, so proceed with care and first try to think of reducing your search space yourself. I suggest you let Haskell print out the three lists pX p3, pX p4, pX p5 and see how you'd go about looking for a cycle.
If you would proceed like your list comprehension, you'd start with the first element of each list, 1035, 1024, 1080. I'm pretty sure you would stop right after picking 1035 and 1024 and not test for cycles with any value from P5, let alone try all the permutations of the combinations involving these two numbers.
(I haven't actually worked on this problem yet, so this is how I would go about speeding it up. There may be some math wizardry out there that's even faster)
First, start looking at the numbers you get from pX. You can drop more than those. For example, P3 contains 6105 - there's no way you're going to find a number in the other sets starting with '05'. So you can also drop those numbers where the number modulo 100 is less than 10.
Then (for the case of 3 sets), we can sometimes see after drawing two numbers that there can't be any number in the last set that will give you a cycle, no matter how you permutate (e.g. 1035 from P3 and 3136 from P4 - there can't be a cycle here).
I'd probably try to build a chain by starting with the elements from one list, one by one, and for each element, find the elements from the remaining lists that are valid successors. For those that you've found, continue trying to find the next chain element from the remaining lists. When you've built a chain with one number from every list, you just have to check if the last two digits of the last number match the first two digits of the first number.
Note when looking for successors, you again don't have to traverse the entire lists. If you're looking for a successor to 3015 from P5, for example, you can stop when you hit a number that's 1600 or larger.
If that's too slow still, you could transform the lists other than the first one to maps where the map key is the first two digits and the associated values are lists of numbers that start with those digits. Saves you from going through the lists from the start again and again.
I hope this helps a bit.

btw, I sense some repetition in your code.
you can unite your [p3, p4, p5, p6, p7, p8] functions into one function that will take the 3 from the p3 as a parameter etc.
to find what the pattern is, you can make all the functions in the form of
pX n = ... `div` 2

Related

Construct powerset without complements

Starting from this question I've built this code:
import itertools
n=4
nodes = set(range(0,n))
ss = set()
for i in range(1,n+1):
ss = ss.union( set(itertools.combinations(range(0,n), i)))
ss2 = set()
for s in ss:
cs = []
for i in range(0,n):
if not(i in s):
cs.append(i)
cs=tuple(cs)
if not(s in ss2) and not(cs in ss2):
ss2.add(s)
ss = ss2
The code construct all subsets of S={0,1,...,n-1} (i) without complements (example, for n=4, either (1,3) or (0,2) is contained, which one does not matter); (ii) without the empty set, but (iii) with S; the result is in ss. Is there a more compact way to do the job? I do not care if the result is a set/list of sets/lists/tuples. (The result contains 2**(n-1) elements)
Additional options:
favorite subset or complement that has less elements
output sorted by increasing size
When you exclude complements, you actually exclude half of the combinations. So you could imagine generating all combinations and then kick out the last half of them. There you must be sure not to kick out a combination together with its complement, but the way you have them ordered, that will not happen.
Further along this idea, you don't even need to generate combinations that have a size that is more than n/2. For even values of n, you would need to halve the list of combinations with size n/2.
Here is one way to achieve all that:
import itertools
n=4
half = n//2
# generate half of the combinations
ss = [list(itertools.combinations(range(0,n), i))
for i in range(1, half+1)]
# if n is even, kick out half of the last list
if n % 2 == 0:
ss[-1] = ss[-1][0:len(ss[-1])//2]
# flatten
ss = [y for x in ss for y in x]
print(ss)

Output all instances from 1 to 8 where the length of the spelling of a number is greater than the length of the spelling of a value higher than it?

I'm a complete Haskell noob and I've been trying to do this for an entire day now.
So one output could be:
Three,Six
(3 is less than 6 but the spelling of it is longer than the spelling of 6)
I came up with this in Haskell but the variables go out of scope, I don't really understand scope in Haskell yet. This might be completely wrong but any help is appreciated.
let numbers = [("One",1),("Two",2),("Three",3),("Four",4),("Five",5),("Six",6),("Seven",7),("Eight",8)]
[([ x | x <- numbers], [y | y <- numbers]) | length (fst x) > length (fst y), snd x < snd y]
Can someone help me to correct this nested list comprehension? Or even tell me if I can use a nested list comprehension at all?
To clarify:
I want to output a list of pairs, where the spelling of the first element in the pair is longer than the spelling of the second element in the pair, but also, the first element in the pair as a number, is less than the second element in the pair as a number.
It sounds like you want something like this:
[(y1, y2) | (x1, y1) <- numbers, (x2, y2) <- numbers, length x1 > length x2, y1 < y2]
That is, it's a list of pairs of numbers - with the requirements you specify. I'm not able to test this at a moment, I think it should work but let me know if you have any issues with it.
Your scope issues were because you were trying to do nested comprehensions and access variables from the inner comprehension in the outer one - this is not allowed, because a variable used inside a comprehension is only in scope in that particular comprehension.
I have also replaced your uses of fst and snd by explicit pattern-matching on the elements of the pair, which is almost always preferred because it's more explicit.

Counting change in Haskell

I came across the following solution to the DP problem of counting change:
count' :: Int -> [Int] -> Int
count' cents coins = aux coins !! cents
where aux = foldr addCoin (1:repeat 0)
where addCoin c oldlist = newlist
where newlist = (take c oldlist) ++ zipWith (+) newlist (drop c oldlist)
It ran much faster than my naive top-down recursive solution, and I'm still trying to understand it.
I get that given a list of coins, aux computes every solution for the positive integers. Thus the solution for an amount is to index the list at that position.
I'm less clear on addCoin, though. It somehow uses the value of each coin to draw elements from the list of coins? I'm struggling to find an intuitive meaning for it.
The fold in aux also ties my brain up in knots. Why is 1:repeat 0 the initial value? What does it represent?
It's a direct translation of the imperative DP algorithm for the problem, which looks like this (in Python):
def count(cents, coins):
solutions = [1] + [0]*cents # [1, 0, 0, 0, ... 0]
for coin in coins:
for i in range(coin, cents + 1):
solutions[i] += solutions[i - coin]
return solutions[cents]
In particular, addCoin coin solutions corresponds to
for i in range(coin, cents + 1):
solutions[i] += solutions[i - coin]
except that addCoin returns a modified list instead of mutating the old one. As to the Haskell version, the result should have an unchanged section at the beginning until the coin-th element, and after that we must implement solutions[i] += solutions[i - coin].
We realize the unchanged part by take c oldlist and the modified part by zipWith (+) newlist (drop c oldlist). In the modified part we add together the i-th elements of the old list and i - coin-th elements of the resulting list. The shifting of indices is implicit in the drop and take operations.
A simpler, classic example for this kind of shifting and recursive definition is the Fibonacci numbers:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
We would write this imperatively as
def fibs(limit):
res = [0, 1] + [0]*(limit - 2)
for i in range(2, limit):
res[i] = res[i - 2] + res[i - 1]
return res
Turning back to coin change, foldr addCoin (1:repeat 0) corresponds to the initialization of solutions and the for loop on the coins, with the change that the initial list is infinite instead of finite (because laziness lets us do that).

How to convert (0,0) to [0,0] in prolog?

I'm making a predicate distance/3 that calculates the distance between 2 points on a 2d plane. For example :
?- distance((0,0), (3,4), X).
X = 5
Yes
My predicate only works if (0,0) is the list [0,0]. Is there a way to make this conversion?
You can do this with a simple rule that unifies its left and right sides:
convert((A,B), [A,B]).
Demo.
Although the others have answered, keep in mind that (a,b) in Prolog is actually not what you might think it is:
?- write_canonical((a,b)).
','(a,b)
true.
So this is the term ','/2. If you are working with pairs, you can do two things that are probably "prettier":
Keep them as a "pair", a-b:
?- write_canonical(a-b).
-(a,b)
true.
The advantage here is that pairs like this can be manipulated with a bunch of de-facto standard predicates, for example keysort, as well as library(pairs).
Or, if they are actually a data structure that is part of your program, you might as well make that explicit, as in coor(a, b) for example. A distance in two-dimensional space will then take two coor/2 terms:
distance(coor(X1, Y1), coor(X2, Y2), D) :-
D is sqrt((X1-X2)^2 + (Y1-Y2)^2).
If you don't know how many dimensions you have, you can then indeed keep the coordinates of each point in a list. The message here is that lists are meant for things that can have 0 or more elements in them, while pairs, or other terms with arity 2, or any term with a known arity, are more explicit about the number of elements they have.
If you just have a simple pair, you can use the univ operator and simply say something like:
X = (a,b) ,
X =.. [_|Y] .
which produces
X = (a,b) .
Y = [a,b] .
This doesn't work if X is something like (a,b,c), producing as it does
X = (a,b,c) .
Y = [a,(b,c)] .
[probably not what you want].
The more general case is pretty simple:
csv2list( X , [X] ) :- % We have a list of length 1
var(X) . % - if X is UNbound
csv2list( X , [X] ) :- % We have a list of length 1
nonvar(X) , % - if X is bound, and
X \= (_,_) . % - X is not a (_,_) term.
cs22list( Xs , [A|Ys] ) :- % otherwise (the general case) ,
nonvar(Xs) , % - if X is bound, and
Xs = (A,Bs) , % - X is a (_,) term,
csv2list(Bs,Ys % - recurse down added the first item to result list.
. % Easy!

Generating triangular number using iteration in haskell

I am trying to write a function in Haskell to generate triangular number, I am not allowed to use recursion, I am supposed to use iteration
here is my code ...
triSeries 0 = [0]
triSeries n = take n $iterate (\x->(0+x)) 1
I know that my function after iterate is wrong .
But It has been hours looking for a function, any hint please?
Start by writing out some triangular numbers
T(1) = 1
T(2) = 1 + 2
T(3) = 1 + 2 + 3
An iterative process to generate T(n) is to start from [1..n], take the first element of the list, and add it to a running total. In a language with mutable state, you might write:
def tri(n):
sum = 0
for x in [1..n]:
sum += x
return sum
In Haskell, you can iteratively consume a list of numbers and accumulate state via a fold function (foldl, foldr, or some variant). Hopefully that's enough to get started with.
Maybe wikipedia could be a hint, where something like
triangular :: Int -> Int
triangular x = x * (x + 1) `div` 2
could be got from.
triSeries could be something like
triSeries :: Int -> [Int]
triSeries x = map triangular [1..x]
and works like that
> triSeries 10
[1,3,6,10,15,21,28,36,45,55]
Talking about iterate. Maybe there is some way to use it here, but as John said, foldl would be sufficient. Take a look at this page, what are you looking is in the very beginning.
It is not clear what is meant by "recursion is not allowed, use iteration". All functions that appear to be "iterative" are recursive inside.
iterate in all your uses can only modify the input with a constant, and iterate (+1) 1 is the same as [1..]. Consider using a Data.List function that can combine a number from infinite range [1..] and the previously computed sum to produce a infinite list of such sums:
T_i=i+T_{i-1}
This is definitely cheaper than x*(x+1) div 2
Consider using a Data.List function that can produce an infinite list of finite lists of sums from a infinite list of sums. This is going to be cheaper than computing a list of 10, then a list of 11 repeating the same computation done for the list of 10, etc.

Resources