71 lines
2.3 KiB
Plaintext
71 lines
2.3 KiB
Plaintext
### Preliminaries
|
|
# If x is NULL then raise an error condition:
|
|
create or replace function try(x, ErrorMessage) as (
|
|
if( x IS NULL, error( ErrorMessage ), x )
|
|
);
|
|
|
|
create or replace function proper_divisors(n) as table (
|
|
select 1 where n > 1
|
|
union all
|
|
select distinct i
|
|
from (select unnest( [ j, n // j]) as i
|
|
from range(2, 1 + sqrt(n).floor()::BIGINT) as t(j)
|
|
where (n % j) == 0)
|
|
);
|
|
|
|
create or replace function composite(n) as (
|
|
select count(*) == 2 as n from (from proper_divisors(n) limit 2)
|
|
);
|
|
|
|
create or replace function average_is_integral(lst) as (
|
|
list_sum(lst) % length(lst) = 0
|
|
);
|
|
|
|
create or replace function list_of_proper_divisors(n) as (
|
|
select coalesce(array_agg(i), []) as divisors from proper_divisors(n) t(i)
|
|
);
|
|
|
|
|
|
### Arithmetic numbers
|
|
# A table of the arithmetic numbers in range(1, mx)
|
|
create or replace function arithmetic_numbers(mx) as table (
|
|
select n
|
|
from range(1, mx) t(n)
|
|
where average_is_integral(list_of_proper_divisors(n) || [n])
|
|
order by n -- needed
|
|
);
|
|
|
|
# A table (n, composite) of the arithmetic numbers in range(1, mx) showing also whether each is composite
|
|
create or replace function describe_arithmetic_numbers(mx) as table (
|
|
select n, length(lst) > 1 as composite
|
|
from
|
|
(select n, list_of_proper_divisors(n) as lst
|
|
from range(1, mx) t(n)
|
|
where average_is_integral(lst || [n])
|
|
order by n -- needed
|
|
)
|
|
);
|
|
|
|
# Return a struct {nth, composites} giving the nth arithmetic number
|
|
# and the number of composites less than or equal to that number.
|
|
# If the heuristic fails, an error is raised.
|
|
create or replace function describe_nth_arithmetic_number(nth) as (
|
|
with cte as (from describe_arithmetic_numbers(nth * 2) limit nth)
|
|
select try(
|
|
(select { nth: (select last(n) from cte),
|
|
composites: (select count(*) from cte where composite = true)}
|
|
where nth = (select count(*) from cte)),
|
|
'heuristic failure')
|
|
);
|
|
|
|
# Return a list of the first `number` arithmetic numbers using a
|
|
# heuristic cautiously
|
|
create or replace function arithmetic_numbers_list(number) as (
|
|
with cte as (from describe_arithmetic_numbers(number * 2 ) limit number),
|
|
m as (select count(*) as m from cte)
|
|
select try(
|
|
if (m = number, (select array_agg(n) from cte), null),
|
|
'heuristic failure' )
|
|
from m
|
|
);
|