Divisibility by 7 is a Walk on a Graph (2009)
blog.tanyakhovanova.com
blog.tanyakhovanova.com
Where is this going? Behold, a 12,701 character regex for divisibility by 7: http://codegolf.stackexchange.com/questions/3503/hard-code-g...
This doesn't use any recursive features (it is a real Regular Expression in the theoretic sense) so it can be checked in linear time.
The original 32K regex pointed to in the stackexchange problem statement however is perfectly correct.
Test code:
open(F, '< /tmp/q.in');
$myre = <F>;
chomp($myre);
$myrecomp = qr/^(?:$myre)$/;
while (<>) {
chomp();
if (m/$myrecomp/) {
print "$_\n";
}
}
Examples of multiples of 7 not matched by the given regex: 70, 707, 7007, 11095(I spent all morning trying to find the bug in my regex compiler based on the assumption that the answer there was correct)
I wonder if that's the optimal regex or can be reduced further using some rules[1] like the ones which we(humans) generally use to do it manually.
(I have a regex -> DFA compiler here that I just threw your regex through. Seven states, connected as expected)
(I think I've read that finding the smallest one is not only NP-hard, but P-Space complete.)
Deleted comment
Of (a \star b \star ) \star and ( a ∪ b ) \star, which is the canonical form? The transformation from the former to the latter is nontrivial as a \star b \star is not equivalent with a ∪ b.
It remains PSPACE-complete if you're given a corresponding DFA: "Jiang and Ravikumar [7] show moreover that the minimization problem for ... regular expressions remains PSPACE-complete, even when specifying the regular language by a dfa" from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60....
In that sense, the grandparent is incorrect. It is unknown, in both practice and theory, how to find the shortest equivalent regex.
Heck, there might be an algorithm that works really well in practice. People who do model checking and verification laugh PSPACE completeness in the face and are not even really concerned with undecidability.
It also seems that regexes can't express accepting expressions like AB where A is accepted by itself (considering AB is accepted), which in the DFA is implemented by sending it to the initial state
B* does that.
Example: 325 becomes 32 - 10 = 22, which is obviously not divisibile by 7.
Better example: 8638 -> 863 - 16 = 847 -> 84 - 14 = 70 -> 7 - 0 -> 7, so we have a winner.
Learned this as a kid (forget where), but it took decades for me to realize why it obviously works.
Example: 325 becomes 32 + 20 = 52 which is divisible by 13. Example: 8632 -> 863 + 8 = 871 -> 87 + 4 = 91 which is divisible by 13.
It works because 39 = 40-1 is divisible by 13 (similarly to why the 7 test works because 21 = 20+1 is divisible by 7).
325 => 32 - 9 * 5 = 32 - 45 = -13
The method itself comes from the fact that what we're doing is really just modular arithmetic. Which has the wonderful property that, as long as all manipulations mod N don't fundamentally change the base we can keep repeating them.
Similar to my mod 7 breakdown:
AB = 0 (mod 13)
10*A + B = 0 (mod 13)
40*A + 4*B = 0 (mod 13)
A + 4*B = 0 (mod 13)
A - 9*B = 0 (mod 13) // because 4 = -9 (mod 13)
This is neat. A similar construction should be doable for any number.EDIT: I have a rule of not questioning down votes, but many of my comments that get down voted have something disagreeable in them (well, I agree with them, but it's typically political/management style/economics/etc.). But how does a break down of modular arithmetic become worth down voting?
(While it's a good general practice not to question downvotes, there are some cases that just leave you wondering what the other person was thinking. This is one of the explanations I've imagined, although usually I just assume big fingers on a tiny touchscreen.)
"A similar construction should be doable for any number." - yes, except 2 and 5. You just need to find a multiple of the number that's 1 more or less than a multiple of 10.
In fact, we can even come up with a test for divisibility by 3 (or 9) this way: just add the last digit to the rest of the number repeatedly until you can tell if the result is divisible by 3 (or 9):
4752 -> 475+2 = 477 -> 47+7 = 54 -> 5+4 = 9 is divisible by 3 and 9 3752 -> 375+2 = 377 -> 37+7 = 44 -> 4+4 = 8 isn't divisible by 3 or 9 4755 -> 475+5 = 480 -> 48+0 = 48 -> 4+8 = 12 -> 1+2 = 3 is divisible by 3 but not 9.
Of course this ends up being equivalent to the usual "add all the digits" test.
10*A + B = 0 (mod 2)
B = 0 (mod 2)
and: 10*A + B = 0 (mod 5)
B = 0 (mod 5)
Of course, these are trivially small cases and we've all learned the patterns. An interesting case with N = 4, the quick method I learned in grade school was to look at the last two digits. But using the approach I've adopted here, you get something more complex: 10*A + B = 0 (mod 4)
2*A + B = 0 or 2*A - 3*B = 0 (mod 4)
If we instead break N into ABC (A * 100 + B * 10 + C = N): 100*A + BC = 0 (mod 4)
BC = 0 (mod 4)
And we've got the method I learned in school.EDIT: Formatting.
I'm not sure the best way to express it, but here's what I've got:
Allow me to use a shorthand, N = AB where AB is shorthand for 10 * A + B, and B is the least significant digit. IF N is divisible by 7, then AB = 0 (mod 7). This allows us to do the following manipulations:
AB = 0 (mod 7)
10*A + B = 0 (mod 7)
3*A + B = 0 (mod 7)
5*(3*A + B) = 5*0 (mod 7) // EDIT: had -2 on the RHS, that was correct but confusing
A + 5*B = 0 (mod 7)
A - 2*B = 0 (mod 7)
So we've arrived at drfuchs' method. You only need to repeat the process until you've proven to yourself that A - 2 * B is divisible by 7 or not.That's all I've got. I ran a half-marathon yesterday, and I've been up for 16 hours today. My brain might work better tomorrow.
EDIT: changed the steps a bit, had some unneeded ones. Also, this shows that you can use addition instead of subtraction, but you won't be moving towards 0, but you still have to be able to recognize that the new number is divisible by 7.
You can then divide by zero because if X is a factor of 7 and ends in zero, X / 10 is a factor of 7 as well.
you are subtracting multiples of 21, then dividing by 10, which is coprime with 7
105 is a multiple of 21.
0.142857 = 1/7 0.285714 = 2/7 0.428571 = 3/7 0.571428 = 4/7 0.714285 = 5/7 0.857142 = 6/7
you can see the first digit after the decimal point increases in numerical order through the available numbers in the pattern, the proceeds to repeat in the same order
Some other prime denominators behave the same way. For example, 1/17th is 0.0588235294117647 and the first digit after the decimal point increases like 0,1,1,2,2,3,4,4,5,5,6,7,7,8,8,9 ... Where there are 2 of the same number in the sequence, the first time you encounter that number you start from it's first ocurrence so for example 3/17 is 0.2941176470588235
This makes for a pretty spooky party trick but I can tell you from experience it doesn't attract the opposite sex.
Label all of the nodes 0 through 6, starting with making the white node 0, and following the black arrows. We can consider each of these nodes to represent a congruence mod 7.
Let n be the first digit of the number, and nXXX be the entire number. After we walk n nodes by following the black arrows, we arrive at the node n' = n MOD 7. Notice that n'XXX = nXXX MOD 7. More specifically, nXXX is divisible mod 7 if and only if n'XXX is divisible by 7.
Let m be the second digit. At this point, we reduced the problem to testing n'mXX MOD 7. Notice that n'mXXX = (10n' + m)XX. [0] Notice that following the white arrow at an arbitrary node, k, is equivilent to following 10k black arrows. [1] This means that after following the white arrow, we have reduced the problem to mXX. At this point, we simply recurse to the first step until we are out of digits.
[0] This construction is slightly improper, in that it involves a single "digit" having a value greater than 10.
[1] This can be verified by considering the value of 10k MOD 7, and comparing it with the destination node.
Copied here for the lazy:
I wrote a small python script to generate DOT code for graphviz so that you can just input the base and the number to check division and automatically draw the graph. (The resulting graphs aren't as pretty as one made by a human, but it's kind of fun to poke around with it.)
Here's the script:
base = 10
divby = 7
print "digraph {"
print " 0 [shape=doublecircle]"
for i in xrange(0, divby):
print " ", i, "->", (i+1)%divby
print " ", i, "->", (base*i)%divby, "[arrowhead=empty]"
print "}"
Save it to a file such as `make_graph.py`. Then, as long as you have the graphviz binaries on path, you can render an image like: python make_graph.py > graph.dot
dot -Tpng graph.dot -o out.png
Here are some sample outputs:- [base = 3, divby = 11](http://imgur.com/cwUmnME)
- [base = 10, divby = 7](http://imgur.com/O7GYw17)
- [base = 10, divby = 10](http://imgur.com/k6xC0CQ)
- [base = 10, divby = 11](http://imgur.com/1SSXKcK)
- [base = 16, divby = 7](http://imgur.com/QZzSyva)
Not all the edges are actually reachable -- e.g. base 10, divby 10 has a black edge from 9 to 0 even though you can't ever wrap around to 0 since `(10 * anything)%10` is zero -- so the biggest you can get to is 9, then when you follow the white edge for 9x you start over at zero... There may also be other edge cases I haven't thought of ;)
An answer: Counter-examples are important in Maths.
Anecdote: Oliver Sacks wrote about autistic twins [1] who could not speak or communicate well to people but who could perform prodigious feats of calculation, including factorising large pimes. Sacks sat with them with a table of prime numbers, and swapped some really large ones after which they took him seriously. Sacks took their reaction to his large primes as proof of their arithmetical ability.
The mathematician John Conway (the game of life chap) was quoted on an online forum decades later as saying that Sacks should have suggested some large non-prime numbers as a test of the twins. I'm searching for a reference!
[1] http://math-frolic.blogspot.co.uk/2013/02/prime-savants-fasc...
http://www.pepijnvanerp.nl/articles/oliver-sackss-twins-and-...
The implication of a DFA for divisibility by 7 is that it's easy (with practice) to figure divisibility by 7 in your head for arbitrarily long numbers as fast as someone can say them. Nice party trick! ;) I've also been having debates with people about whether divisibility testing in your head is a simpler operation than long division in your head. When you break it down carefully, long division in your head for a single digit divisor is very similar, and also surprisingly easy to do, the main difference might be simply having to remember quotient digits, and nothing more.
I'm curious where the DFA for divisibility by 7 might have originally come from, but I'm pretty sure it was a homework problem in the text I used, "Elements of the theory of Computation" by Lewis and Papdimitriou, Prentice Hall, 1981.
https://gist.github.com/62553ded59ec7e289be6
Edit: s/division by 7/divisibility by 7
Thanks for pointing that out, omaranto!
As an example, consider 413: 4x9 + 1x3 + 3 = 36 + 3 + 3 = 42
42 is divisible by 7 therefore 413 is too.
10 = 3 (mod 7)
So this works because you're substituting the powers of 10 with powers of 3, and we're operating under mod 7 arithmetic. Conveniently, this can also be repeated like drfuchs' method if your numbers are too large to recognize as a multiple of 7 after the first pass. 413 => 4*9+1*3+3 = 42 => 4*3+2 = 14 => 1*3+4=7(That's for testing divisibility by n of numbers written in base 10; for others bases just replace the 10 above.)
If we're trying to compute 3256 % 7 and we know that 325 % 7 = 3, then 3256 % 7 = (325 * 10 + 6) % 7 = (3 * 10 + 6)
Computing 10 % 7, 20 % 7 etc generates the white arrows.
I think unless we're checking divisibility by primes, though, the white and black arrows won't share edges
N = 2
| state | 0 | 1 |
|-------+---+---|
| 0 | 0 | 1 |
| 1 | 0 | 1 |
N = 3
| state | 0 | 1 |
|-------+---+---|
| 0 | 0 | 1 |
| 1 | 2 | 0 |
| 2 | 1 | 2 |
N = 4
| state | 0 | 1 |
|-------+---+---|
| 0 | 0 | 1 |
| 1 | 2 | 3 |
| 2 | 0 | 1 |
| 3 | 2 | 3 |
Each state represents a potential result of I mod
N. Constructing it becomes mechanical, as in each state you can either
double it (input digit D = 0) or double it + 1 (input digit D = 1). So
in N = 4, determining the outputs of state 2: You can double it, and 4
mod 4 = 0, therefore the next state is 0; You can double it + 1, and 5
mod 4 = 1, therefore teh next state is 1.As to making this particular style graph, I'm currently playing around with it.
EDIT: Hmm, left something out. You can convert this to any base, you just end up with more transitions out of each state (for a base B, you need B transitions).
EDIT Again: omaranto has it correct for generating the article's style of graphs. Guess I should've refreshed before posting, but working it out myself was fun and successfully kept me from sleeping.
(1) 1 black then 1 white.
(6) 6 blacks then 1 white.
(0) 1 white.
(3) 3 blacks then 1 white.
And you end up at the bottom node, indicating it is divisible by 7.
(1) 1 white then 1 black, ending up in state 1
(6) 1 white then 6 blacks, ending up in state 2
(0) 1 white then 0 blacks, ending up in state 6
(3) 1 white then 3 blacks, ending up in state 0
The graph keeps track of ((the number so far) mod 7); following a white arrow multiplies your total by 10, and following a black arrow increases your total by 1.Your initial white doesn't change anything, since it brings you back to the starting node. Any whites after the the final digit either keep you on the starting node or keep you in the graph where.