Regex (ECMAScript), 64 62 bytes
^(?=(x((x{14})(x+)))(?=(\1*)\4\2*$)(\1*$\5))\6\3?(?!(xx+)\7+$)
Try it online!
Takes its input in unary, as a sequence of x
characters whose length represents the number.
This regex finds two numbers \$a\$ and \$a+14\$ such that \$n=a(a+14)\$. If it finds them, it then asserts that either \$a\$ or \$a+14\$ is prime.
The multiplication algorithm implemented here searches for two unknown factors which, when multiplied together, equal a known product. The regex for this is also essentially equivalent to that of the shortest form of multiplication for asserting that two known factors multiply to make a known product.
In many of my other posted regex answers, multiplication is implemented as finding the unknown product of two known factors; the shortest form of that is different. Both methods would work in both circumstances, but golf-wise, they're worse at doing each other's job.
Here is an explanation of how this form of multiplication works in general:
We have \$AB \stackrel{?}{=} C\$, where \$A \ge B\$. The steps to asserting \$AB=C\$ are (shown here in an order that's easier to explain conceptually; in the regex they're done in the order that results in the best golf):
- Assert that \$C-A \equiv 0 \pmod A\$
- This is equivalent to \$C \equiv 0 \pmod A\$, a direct consequence of \$C=AB\$
- Assert that \$C-A-(B-1) \equiv 0 \pmod {A-1}\$,
- This can be shown to result from \$C=AB\$:
\$\begin{aligned}C-A-(B-1) &= AB-A-(B-1) \\ &= A(B-1)-(B-1) \\ &= (A-1)(B-1)\end{aligned}\$
- Assert that there is no \$0<D<C\$ which satisfies both of the above with \$D\$ in place of \$C\$
This can be expressed as:
- Assert that the only \$0<E \le C-A\$ that satisfies the following moduli is \$E=C-A\$:
- \$E \equiv 0 \pmod A\$
- \$E \equiv B-1 \pmod {A-1}\$
We now have two coprime moduli, \$A\$ and \$A-1\$. By the Chinese remainder theorem, there is one and only one integer \$E\$ such that \$0 < E \le A(A-1)\$, or alternatively stated, \$0 < E+A \le A^2\$, and the above moduli are satisfied. And since we know \$B\le A\$, it follows that \$AB\le A^2\$.
The algebra above shows there is at least one \$E\$ satisfying the moduli: \$E=AB-A\$. The Chinese remainder theorem shows that there is exactly one \$E\$ satisfying the moduli within a certain range. The fact that \$B\le A\$ guarantees that \$AB-A\$ falls inside that range. We are not guaranteed that \$C\le A^2\$, but as long as we search for the smallest \$E\$ satisfying the moduli, we're guaranteed that \$E=AB-A\$, so if \$E=C-A\$, then \$AB=C\$.
The regex essentially searches for the smallest \$E\$ satisfying the moduli, then asserts that \$E=C-A\$. The assertion of \$C \equiv 0 \pmod A\$ is done afterward, making the regex a bit slower in the name of golf.
Also note that in regex, \$0 \equiv 0 \pmod 0\$, so the algorithm works for \$A=1\$ without any need for a special case.
In cases where we don't know whether \$A\ge B\$, and can't capture them at the source in such a way as to automatically sort them as such, we can simply assert both versions of each:
- \$C \equiv 0 \pmod A\$
- \$C \equiv 0 \pmod B\$
- \$C-B \equiv 0 \pmod {A-1}\$
- \$C-A \equiv 0 \pmod {B-1}\$
This makes for shorter golf than actually sorting \$A\$ and \$B\$ into lesser and greater after they've already been captured. But for this particular problem, only the two assertions need to be used, since by definition \$A=B+14\$.
And the regex, pretty-printed and commented:
# For the purposes of these comments, the input number = N.
^
# Find two numbers A and A+14 such that A*(A+14)==N.
(?=
(x((x{14})(x+))) # \1 = A+14; \2 = \1-1; \3 = 14; \4 = A-1; tail -= \1
(?= # Assert that \1 * (\4+1) == N.
(\1*)\4\2*$ # We are asserting that N is the smallest number satisfying
# two moduli, thus proving it is the product of A and A+14
# via the Chinese Remainder Theorem. The (\1*) has the effect
# of testing every value that satisfies the "≡0 mod \1"
# modulus, starting with the smallest (zero), against "\4\2*$",
# to see if it also satisfies the "≡\4 mod \2" modulus; if any
# smaller number satisfied both moduli, (\1*) would capture a
# nonzero value in \5. Note that this actually finds the
# product of \4*\1, not (\4+1)*\1 which what we actually want,
# but this is fine, because we already subtracted \1 and thus
# \4*\1 is the value of tail at the start of this lookahead.
# This implementation of multiplication is very efficient
# golf-wise, but slow, because if the number being tested is
# not even divisible by \1, the entire test done inside this
# lookahead is invalid, and the "\1*$" test below will only
# fail after this useless test has finished.
)
(\1*$\5) # Assert that the above test proved \1*(\4+1)==N, by
# asserting that tail is divisible by \1 and that \5==0;
# \6 = tool to make tail = \1
)
# Assert that either A or A+14 is prime.
\6 # tail = \1 == A+14
\3? # optionally make tail = A
(?!(xx+)\7+$) # Assert tail is prime. We don't need to exclude treating
# 1 as prime, because the potential false positive of N==15
# is already excluded by requiring \4 >= 1.
print 0
. All Rocco numbers are composite(n*..)
, so no primes in any range. \$\endgroup\$