| Bytes | Lang | Time | Link |
|---|---|---|---|
| 091 | Regex 🐇 PCRE2 v10.35 or later | 241029T224928Z | Deadcode |
| 012 | Jelly | 170610T025656Z | Dennis |
| 021 | MATL | 170608T152722Z | Luis Men |
| 075 | JavaScript ES6 | 170608T154530Z | Arnauld |
| 014 | Jelly | 170608T154504Z | Erik the |
| 048 | Mathematica | 170608T152353Z | Martin E |
Regex 🐇 (PCRE2 v10.35 or later), 102 91 bytes
^(?=(xx)\1+$|(xx+)\2+$|x$|(?*x(x*))(?!(?*(xx+)(x+$))(?=\4*(x+)).*(?=\5\6$)\3\4*$))\1?+\3?x+
Implements the same bijection as Dennis's Jelly answer:
- Every prime maps to the next prime (implementation adapted from The program that will find the next prime number).
- Every even number greater than \$2\$ maps to the previous even number.
- Every odd non-prime, and \$0\$, maps to itself.
The inverse of what the challenge asks, a bijection that maps a proper subset of the primes to the primes, would be much shorter (56 bytes).
^ # tail = N = input number
(?= # Atomic lookahead
(xx)\1+$ # \1 = 2 if N is even and >2, else \1 = unset
| # or
(xx+)\2+$ # N is composite
| # or
x$ # N == 1
| # or
# Find the smallest prime greater than N
(?* # Non-atomic lookahead (try all options until matching)
x(x*) # \3 = N - (P - N) = 2*N - P, for conjectured P > N
)
(?! # Negative lookahead - assert that this cannot match
(?* # Non-atomic lookahead (try all options until matching)
(xx+) # \4 = try all numbers from 2 through N-1
(x+$) # \5 = N - \4; assert \4 < N
)
(?= # Atomic lookahead (locks onto the first match)
\4*(x+) # \6 = N % \4, giving \4 instead of 0
)
.*(?=\5\6$) # tail = \5 + \6
\3 # tail -= \3
\4*$ # Assert tail is divisible by \4
)
)
\1?+ # tail -= \1, atomically, if \1 is set
\3? # Optionally, if \3 exists, tail = tail-\3 = P - N;
# the following will be evaluated for all options taken:
x+ # Add tail to the number of possible matches
Regex 🐘 (.NET), 99 93 87 bytes
(?=(xx)\1+$|(xx+)\2+$|x?$|(x)+?(x*$)(?<!(?=\6*(?<=(?=\4\6*$)\5))(^x+)(x+x)))\1?(?<3>x)*
Returns its output as the capture count of group \3.
The inverse of what the challenge asks, a bijection that maps a proper subset of the primes to the primes, would be much shorter (63 bytes)
# tail = N = input number
(?= # Lookahead
(xx)\1+$ # \1 = 2 if N is even and >2, else \1 = unset
| # or
(xx+)\2+$ # N is composite
| # or
x?$ # N ≤ 1
| # or
# Find the smallest prime greater than N
(x)+? # Assert N > 0; \3.captureCount += P - N;
(x*$) # \4 = N - (P - N) = 2*N - P
(?<! # Right-to-left negative lookbehind
(?= # Atomic lookahead
\6* # tail = Z = N % \6, giving \6 instead of 0
(?<= # Right-to-left atomic lookbehind
(?= # Atomic lookahead
\4\6*$ # Assert tail-\4, that is, \5+Z-\4, is divisible by \6
)
\5 # tail += \5
)
)
(^x+) # \5 = N - \6; assert \6 < N
(x+x) # \6 = try all numbers from 2 through N-1
)
)
\1? # tail -= \1, if \1 is set
(?<3>x)* # \3.captureCount += tail
Jelly, 12 bytes
Æn_ḍ@¡ÆP?2»0
How it works
Æn_ḍ@¡ÆP?2»0 Main link. Argument: n (non-negative integer)
ÆP? If the input is prime:
Æn Compute the next prime after n.
Else:
ḍ@¡ 2 Do once if n is divisible by 2, zero times if not.
_ 2 Subtract 2.
So far, we've mapped all primes to the next prime, all even integers
(except 2) to the previous even integer, and all composite, odd,
positive integers to themselves. In particular, 0 -> -2, but 0 doesn't
have a preimage, so we need 0 -> 0.
»0 Take the maximum of the result and 0, mapping 0 -> max(-2, 0) = 0.
MATL, 21 bytes
Thanks to Emigna for spotting a mistake, now corrected
tZp?_Yq}q:Zp~fX>sG~E+
This implements the following bijection. Write the primes in a row and the non-primes below:
2 3 5 7 11 13 17 ...
0 1 4 6 8 9 10 ...
Then the output is obtained by following the arrow from the input:
2 > 3 > 5 > 7 > 11 > 13 > 17 ...
^
0 < 1 < 4 < 6 < 8 < 9 < 10 ...
Explained code
t % Implicit input. Duplicate
Zp % Is it a prime? Gives true / false
? % If so
_Yq % Next prime
} % Else
q % Subtract 1
: % Range from 1 to that
Zp~ % Is each entry not a prime? Gives an array of true / false
f % Find non-zero entries, i.e. non-primes. Will be empty for input 1
X> % Maximum. This gives the greatest non-prime less than the input.
% Will be empty for input 1
s % Sum. This is to transform empty into 0
G~E % Push input, negate, times 2. This gives 2 for input 0, or 0 otherwise
E % Add. This handles the case of input 0, so that it outputs 2
% End (implicit). Display (implicit)
JavaScript (ES6), 82 77 75 bytes
Implements the same logic as Luis Mendo's answer.
f=(n,i=(P=(n,x=n)=>n%--x?P(n,x):x==1||-1)(x=n))=>x?x==n|P(n)-i?f(n+i,i):n:2
Formatted and commented
f = ( // given:
n, // - n = input
i = // - i = 'direction' to move towards
(P = (n, x = n) => // - P = function that returns:
n % --x ? // - 1 when given a prime
P(n, x) // - -1 when given a composite number
: //
x == 1 || -1 //
)(x = n) // - x = copy of the original input
) => //
x ? // if the input is not zero:
x == n | P(n) - i ? // if n equals the input or doesn't match its primality:
f(n + i, i) // do a recursive call in the chosen direction
: // else:
n // return n
: // else:
2 // return 2
Demo
f=(n,i=(P=(n,x=n)=>n%--x?P(n,x):x==1||-1)(x=n))=>x?x==n|P(n)-i?f(n+i,i):n:2
for(n = 0; n < 50; n++) {
console.log(n, '->', f(n));
}
Mathematica, 54 48 bytes
±(t=x_?PrimeQ)=NextPrime@x
±n_:=Abs[n-1]/.t:>x-1
Defines the following bijection:
n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ...
±n 1, 0, 3, 5, 2, 7, 4, 11, 6, 8, 9, 13, 10, 17, 12, 14, 15, 19, ...
The basic idea is to map each prime to the next, to ensure that they are mapped to a proper subset. This results in a "gap" at 2. To fill that gap, we want to map 4 to 2 and then each other composite number to the previous composite number, to "bubble up" the gap. Since 2 and 3 are the only two adjacent primes, we can express both of those mappings as "n-1 or if that's a prime then n-2". Finally, this mapping ends up sending 1 to 0 and we make it send 0 back to 1 by taking the absolute value of n-1.