Ir al contenido principal

Conjunto de primos relativos

Dos números enteros positivos son primos relativos si no tienen ningún factor primo en común; es decir, si 1 es su único divisor común. Por ejemplo, 6 y 35 son primos entre sí, pero 6 y 27 no lo son porque ambos son divisibles por 3.

Definir la función

   primosRelativos :: [Int] -> Bool

tal que primosRelativos xs se verifica si los elementos de xs son primos relativos dos a dos. Por ejemplo,

   primosRelativos [6,35]         ==  True
   primosRelativos [6,27]         ==  False
   primosRelativos [2,3,4]        ==  False
   primosRelativos [6,35,11]      ==  True
   primosRelativos [6,35,11,221]  ==  True
   primosRelativos [6,35,11,231]  ==  False

1. Soluciones en Haskell

import Data.Numbers.Primes (primes)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

primosRelativos1 :: [Int] -> Bool
primosRelativos1 []     = True
primosRelativos1 (x:xs) =
  and [sonPrimosRelativos x y | y <- xs] && primosRelativos1 xs

-- (sonPrimosRelativos x y) se verifica si x e y son primos
-- relativos. Por ejemplo,
--    sonPrimosRelativos 6 35  ==  True
--    sonPrimosRelativos 6 27  ==  False
sonPrimosRelativos :: Int -> Int -> Bool
sonPrimosRelativos x y =
  gcd x y == 1

-- 2ª solución
-- ===========

primosRelativos2 :: [Int] -> Bool
primosRelativos2 []     = True
primosRelativos2 (x:xs) =
  all (sonPrimosRelativos x) xs && primosRelativos2 xs

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: ([Int] -> Bool) -> Spec
specG primosRelativos = do
  it "e1" $
    primosRelativos [6,35]         `shouldBe`  True
  it "e2" $
    primosRelativos [6,27]         `shouldBe`  False
  it "e3" $
    primosRelativos [2,3,4]        `shouldBe`  False
  it "e4" $
    primosRelativos [6,35,11]      `shouldBe`  True
  it "e5" $
    primosRelativos [6,35,11,221]  `shouldBe`  True
  it "e6" $
    primosRelativos [6,35,11,231]  `shouldBe`  False

spec :: Spec
spec = do
  describe "def. 1" $ specG primosRelativos1
  describe "def. 2" $ specG primosRelativos2

-- La verificación es
--    λ> verifica
--    12 examples, 0 failures

-- Comprobación de equivalencia
-- ============================

-- La propiedad es
prop_primosRelativos :: [Positive Int] -> Bool
prop_primosRelativos xs =
  primosRelativos1 ys == primosRelativos2 ys
  where ys = getPositive <$> xs

-- La comprobación es
--    λ> quickCheck prop_primosRelativos
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> primosRelativos1 (take 2000 primes)
--    True
--    (1.43 secs, 1,730,437,768 bytes)
--    λ> primosRelativos2 (take 2000 primes)
--    True
--    (0.99 secs, 1,490,445,736 bytes)

2. Soluciones en Python

from math import gcd
from sys import setrecursionlimit
from timeit import Timer, default_timer

from hypothesis import given
from hypothesis import strategies as st
from sympy.ntheory.generate import primerange

setrecursionlimit(10**6)

# 1ª solución
# ===========

# sonPrimosRelativos(x, y) se verifica si x e y son primos
# relativos. Por ejemplo,
#    sonPrimosRelativos(6, 35)  ==  True
#    sonPrimosRelativos(6, 27)  ==  False
def sonPrimosRelativos(x: int, y: int) -> bool:
    return gcd(x, y) == 1

def primosRelativos1(ys: list[int]) -> bool:
    if not ys:
        return True
    x, *xs = ys
    return all(sonPrimosRelativos(x, z) for z in xs) and primosRelativos1(xs)

# 2ª solución
# ===========

def primosRelativos2(ys: list[int]) -> bool:
    if not ys:
        return True
    for y in ys[1:]:
        if gcd(ys[0], y) != 1:
            return False
    return primosRelativos2(ys[1:])

# Verificación
# ============

def test_primosRelativos() -> None:
    for primosRelativos in [primosRelativos1,
                            primosRelativos2]:
        assert primosRelativos([6,35])
        assert not primosRelativos([6,27])
        assert not primosRelativos([2,3,4])
        assert primosRelativos([6,35,11])
        assert primosRelativos([6,35,11,221])
        assert not primosRelativos([6,35,11,231])
    print("Verificado")

# La verificación es
#    >>> test_primosRelativos()
#    Verificado

# Comprobación de equivalencia
# ============================

# La propiedad es
@given(st.lists(st.integers(min_value=1, max_value=1000)))
def test_primosRelativos_equiv(xs: list[int]) -> None:
    assert primosRelativos1(xs) == primosRelativos2(xs)

# La comprobación es
#    >>> test_primosRelativos_equiv()
#    >>>

# Comparación de eficiencia
# =========================

def tiempo(e: str) -> None:
    """Tiempo (en segundos) de evaluar la expresión e."""
    t = Timer(e, "", default_timer, globals()).timeit(1)
    print(f"{t:0.2f} segundos")

# La comparación es
#    >>> tiempo('primosRelativos1(list(primerange(40000)))')
#    2.20 segundos
#    >>> tiempo('primosRelativos2(list(primerange(40000)))')
#    1.82 segundos