Trying to optimize this algorithm / code to calculate the largest subset of mutually prime numbers between a and b

I am writing a function in Haskell that takes two integers a and b and calculates the length of the largest subset (s) of [a, b], so that all elements are mutually simple. Now the reason is that I believe that researching such values ​​can provide the means to create trivial smaller boundaries (perhaps one big enough to mean actual primes in different allowable ranges, such as consecutive squares). So naturally, I'm trying to run this for some fairly large numbers.

Unfortunately, the code below does not work fast enough to make it even practical for me. I think the flaw is the Haskell Agility policy, which causes problems, but I don’t know the syntax and the places where I need to be forced to prevent the accumulation of operations.

subsets [] = [[]]
subsets (x:xs) = subsets xs ++ map (x:) (subsets xs)

divides a b = (mod a b == 0)

coprime a b = ((gcd a b) == 1)

mutually_coprime []  = True
mutually_coprime (x:xs) | (coprime_list x xs) = mutually_coprime xs
                        | otherwise = False

coprime_list _ [] = True
coprime_list a (x:xs) | (coprime a x) = coprime_list a xs
                      | otherwise = False

coprime_subsets a b = coprime_subsets_helper (subsets [a..b])

coprime_subsets_helper [] = []
coprime_subsets_helper (x:xs) | (mutually_coprime x) = [x] ++ (coprime_subsets_helper xs)
                              | otherwise = coprime_subsets_helper xs

coprime_subset_length a b = max_element (map list_length (coprime_subsets a b))

list_length [] = 0
list_length (x:xs) = 1 + list_length xs

max_element a = max_element_helper a 0

max_element_helper [] a = a
max_element_helper (x:xs) a | (x > a) = max_element_helper xs x
                            | otherwise = max_element_helper xs a

Just to figure out what type of input this hangs in, "coprime_subsets 100 120" never stops at me. I actually left him running, got up, did something else and returned to him later. He was still running. I suspect that a large bottleneck calculates all subsets at once. However, I do not want to create an artificial lower bound for the generated subsets. It can save me all matching sets without leaving me with anything.

What I have tried so far:

  • gcd. . , gcd - , , .

  • . . , -.

  • -, Haskell . , .

, (winhugs). , ; , , ( n) Math Stack Exchange, , , . , . , , , , .

, ; , , . , , . , , , .

+4
3

, .

, . , GHC coprime_subsets

coprime_subsets :: Integral a => a -> a -> [[a]]

GHC Integral , Integer, , Int. Integer , gcds. GHC Int 6 1 , GHC .

. . , .

, .

main = print . length $ coprime_subsets (100 :: Int) 120
main :: IO ()

(stack build --profile Stack) +RTS -p -h (-p -h ) :

COST CENTRE            MODULE  SRC                            %time %alloc

subsets                Coprime src/Coprime.hs:(4,1)-(5,52)     52.5  100.0
coprime                Coprime src/Coprime.hs:11:1-26          25.5    0.0
coprime_list           Coprime src/Coprime.hs:(19,1)-(21,41)   18.5    0.0
coprime_subsets_helper Coprime src/Coprime.hs:(27,1)-(29,69)    1.8    0.0
mutually_coprime       Coprime src/Coprime.hs:(14,1)-(16,43)    1.7    0.0

Integer, (~ 78%) coprime. , .

, .

, -:

  • .
  • .
  • .

subsets? (1) . O(2^n), . ? . , , . , , .

( , ) , , , . , . , . ; Richard Bird sudoku solver. , , - , !

, !

, subsets, :

coprimeSubsets [] = [[]]
coprimeSubsets (x:xs)
  = coprimeSubsets xs ++ map (x :) (coprimeSubsets (filter (coprime x) xs))

(, - , , , .)

, [100..120] ~ 0,1 , . :

COST CENTRE    MODULE          SRC                            %time %alloc

MAIN           MAIN            <built-in>                      42.9    0.5
coprimeSubsets Coprime         src/Coprime.hs:(33,1)-(35,75)   28.6   67.4
CAF            GHC.IO.Encoding <entire-module>                 14.3    0.1
coprime        Coprime         src/Coprime.hs:13:1-26          14.3   31.1

, IO . , coprime 3848, . [100..150] 3 , ... , , , , , .

memoizing coprime, .

+5

:

  • gcd , .
  • "" , .

( , , .) ; , :

coprime_subsets' [] = [[]]
coprime_subsets' (x:xs)
    = coprime_subsets' xs
    ++ map (x:) (coprime_subsets' (filter ((1==) . gcd x) xs))

, ghci:

> coprime_subsets 10 20 == coprime_subsets' [10..20]
True
> coprime_subsets 100 120 == coprime_subsets' [100..120]
True

-, , : coprime_subsets 100 120 16 ghci. , 0.02 ghci, ... =)

, . filter :

maximal_coprime_subsets [] = [[]]
maximal_coprime_subsets (x:xs)
    = filter (any ((>1) . gcd x)) (maximal_coprime_subsets xs)
    ++ map (x:) (maximal_coprime_subsets (filter ((1==) . gcd x) xs))

gcd gcd, [100..120] 0,01 ghci, , .

, coprime_subsets' , ha!

+2

I'm not sure if this can be a way to solve the problem quite efficiently, but it will return all subsets between the provided two integer values ​​in 0.02 seconds even in GHCI.

coprimes :: Int -> Int -> [[Int]]
coprimes x y | y <= x    = []
             | otherwise = (x : filter ((== 1) . gcd x) (tail [x..y])) : (coprimes . head . tail) [x..y] y

*Main> coprimes 100 120
[[100,101,103,107,109,111,113,117,119],[101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120],[102,103,107,109,113,115],[103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120],[104,105,107,109,111,113,115,119],[105,106,107,109,113,116,118],[106,107,109,111,113,115,117,119],[107,108,109,110,111,112,113,114,115,116,117,118,119,120],[108,109,113,115,119],[109,110,111,112,113,114,115,116,117,118,119,120],[110,111,113,117,119],[111,112,113,115,116,118,119],[112,113,115,117],[113,114,115,116,117,118,119,120],[114,115,119],[115,116,117,118,119],[116,117,119],[117,118,119],[118,119],[119,120]]
(0.02 secs, 811,576 bytes)
+1
source

Source: https://habr.com/ru/post/1683697/


All Articles