Eisenstein primes

From Rosetta Code
Revision as of 01:55, 15 May 2023 by Wherrera (talk | contribs) (→‎{{header|Julia}}: round output for compactness)
Eisenstein primes is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

An Eisenstein integer is a non-unit Gaussian integer a + bω where ω(1+ω) = -1, and a and b are integers.

ω is generally chosen as a cube root of unity:

As a Gaussian integer, any Eisenstein integer is either a unit (an integer with a multiplicative inverse [±1, ±ω, ±(ω^-1)]), a prime (a number p such that if p divides xy, then p necessarily divides either x or y), or composite (a product of primes).

An Eisenstein integer a + bω is a prime if either it is a product of a unit and an integer prime p such that p % 3 == 2 or norm(a + bω) is an integer prime.

Eisenstein numbers can be generated by choosing any a and b such that a and b are integers. To allow generation in a relatively fixed order, such numbers can be ordered by their 2-norm or norm:

    norm(eisenstein integer(a, b)) = |a + bω| = 
Task
  • Find, and show here as their complex number values, the first 100 (by norm order) Eisenstein primes nearest 0.
Stretch
  • Plot in the complex plane at least the first 2000 such numbers (again, as found with norm closest to 0).
See also


Julia

""" rosettacode.org/wiki/Eisenstein_primes """

import Base: Complex, real, imag
import LinearAlgebra: norm
import Primes: isprime
import Plots: scatter

struct Eisenstein{T<:Integer} <: Number
    a::T
    b::T
    Eisenstein(a::T, b::T) where {T} = new{T}(a, b)
    Eisenstein(a::T) where {T<:Integer} = new{T}(a, zero(T))
    Eisenstein(a::Integer, b::Integer) = new{eltype(promote(a, b))}(promote(a, b)...)
end

const ω = Eisenstein(false, true)

real(n::Eisenstein) = n.a - n.b / 2

imag(n::Eisenstein) = n.b * sqrt(big(3.0)) / 2

norm(n::Eisenstein) = n.a * n.a + n.b * n.b - n.a * n.b

Complex(n::Eisenstein{T}) where {T} = Complex{typeof(real(n))}(real(n), imag(n))

"""
    is_eisenstein_prime(n)

An Eisenstein integer is a non-unit Gaussian integer a + bω where ω(1+ω) = -1,
and a and b are integers. As a Gaussian integer, any Eisenstein integer is
either a unit (an integer with a multiplicative inverse [±1, ±ω, ±(ω^-1)]),
prime (a number p such that if p divides xy, then p necessarily divides
either x or y), or composite (a product of primes).

    An Eisenstein integer a + bω is a prime if either it is a product of a unit
and an integer prime p such that p % 3 == 2 or norm(a + bω) is an integer prime.
"""
function is_eisenstein_prime(n::Eisenstein)
    if n.a == 0 || n.b == 0 || n.a === n.b
        c = max(abs(n.a), abs(n.b))
        return isprime(c) && c % 3 == 2
    else
        return isprime(norm(n))
    end
end

function test_eisenstein_primes(graphlimitsquared = 10_000, printlimit = 100)
    lim = isqrt(graphlimitsquared)
    arr = [Eisenstein(a, b) for a = -lim:lim, b = -lim:lim]
    eprimes = sort!([arr[p[1]] for p in enumerate(arr) if is_eisenstein_prime(p[2])],
       lt = (x, y) -> norm(x) < norm(y))
    for (i, c) in enumerate(eprimes)
        if i <= printlimit
            print(lpad(round(Complex(c), digits = 4), 18), i % 5 == 0 ? "\n" : "")
        end
    end
    display(
        scatter(
            map(real, eprimes),
            map(imag, eprimes),
            markersize = 1,
            title = "Eisenstein primes with norm < $lim",
        ),
    )
end

test_eisenstein_primes()
Output:
    0.0 - 1.7321im    -1.5 - 0.866im     1.5 - 0.866im    -1.5 + 0.866im     1.5 + 0.866im
    0.0 + 1.7321im   -1.0 - 1.7321im    1.0 - 1.7321im      -2.0 + 0.0im       2.0 + 0.0im
   -1.0 + 1.7321im    1.0 + 1.7321im   -0.5 - 2.5981im    0.5 - 2.5981im   -2.0 - 1.7321im
    2.0 - 1.7321im    -2.5 - 0.866im     2.5 - 0.866im    -2.5 + 0.866im     2.5 + 0.866im
   -2.0 + 1.7321im    2.0 + 1.7321im   -0.5 + 2.5981im    0.5 + 2.5981im   -1.0 - 3.4641im
    1.0 - 3.4641im   -2.5 - 2.5981im    2.5 - 2.5981im    -3.5 - 0.866im     3.5 - 0.866im
    -3.5 + 0.866im     3.5 + 0.866im   -2.5 + 2.5981im    2.5 + 2.5981im   -1.0 + 3.4641im
    1.0 + 3.4641im   -0.5 - 4.3301im    0.5 - 4.3301im   -3.5 - 2.5981im    3.5 - 2.5981im
   -4.0 - 1.7321im    4.0 - 1.7321im   -4.0 + 1.7321im    4.0 + 1.7321im   -3.5 + 2.5981im
    3.5 + 2.5981im   -0.5 + 4.3301im    0.5 + 4.3301im   -2.5 - 4.3301im    2.5 - 4.3301im
      -5.0 + 0.0im       5.0 + 0.0im   -2.5 + 4.3301im    2.5 + 4.3301im   -2.0 - 5.1962im
    2.0 - 5.1962im   -3.5 - 4.3301im    3.5 - 4.3301im    -5.5 - 0.866im     5.5 - 0.866im
    -5.5 + 0.866im     5.5 + 0.866im   -3.5 + 4.3301im    3.5 + 4.3301im   -2.0 + 5.1962im
    2.0 + 5.1962im   -0.5 - 6.0622im    0.5 - 6.0622im   -5.0 - 3.4641im    5.0 - 3.4641im
   -5.5 - 2.5981im    5.5 - 2.5981im   -5.5 + 2.5981im    5.5 + 2.5981im   -5.0 + 3.4641im
    5.0 + 3.4641im   -0.5 + 6.0622im    0.5 + 6.0622im   -2.5 - 6.0622im    2.5 - 6.0622im
   -4.0 - 5.1962im    4.0 - 5.1962im    -6.5 - 0.866im     6.5 - 0.866im    -6.5 + 0.866im
     6.5 + 0.866im   -4.0 + 5.1962im    4.0 + 5.1962im   -2.5 + 6.0622im    2.5 + 6.0622im
   -0.5 - 7.7942im    0.5 - 7.7942im   -6.5 - 4.3301im    6.5 - 4.3301im   -7.0 - 3.4641im
    7.0 - 3.4641im   -7.0 + 3.4641im    7.0 + 3.4641im   -6.5 + 4.3301im    6.5 + 4.3301im
Eisenstein primes
Eisenstein primes