Generate random PESEL number

5

1

From Wikipedia:

PESEL is the national identification number used in Poland since 1979. It always has 11 digits, identifies just one person and cannot be changed to another one.

It has the form of YYMMDDZZZXQ, where YYMMDD is the date of birth (with century encoded in month field), ZZZ is the personal identification number, X denotes sex (even number for females, odd number for males) and Q is a control digit, which is used to verify whether a given PESEL is correct or not.

Having a PESEL in the form of ABCDEF GHIJK, one can check the vailidity of the number by computing the following expression:

A*1 + B*3 + C*7 + D*9 + E*1 + F*3 + G*7 + H*9 + I*1 + J*3

Then the last digit of the result should be subtracted from 10. If the result of the last operation is not equal to the last digit of a given PESEL, the PESEL is incorrect. This system works reliably well for catching one-digit mistakes and digit swaps.

Provide a short program to generate random, valid PESEL number:

  1. It has to be a PESEL a person born in either 20th or 21st century
  2. The birth birth date has to be random but doesn't have to validate leap years or number of days in a month (i.e. the numbers representing the day number have to be between 01 and 31)
  3. All valid PESELs in this date range (01.01.1990-31.12.2099) must be possible
  4. The shortest code (i.e. complete program code), in bytes, wins.

syntagma

Posted 2014-04-13T08:47:08.033

Reputation: 151

2How random? eg, must all digits vary, must eg all 20th century birthdays be possible, and no others? Seems like this can be subverted by solutions that just coin toss between male and female. – bazzargh – 2014-04-13T09:29:06.553

@bazzargh, good point - let it be a PESEL for a person born in either 20th or 21st century. – syntagma – 2014-04-13T09:37:25.063

2Actually my point is more that 'random' can mean 'one of a fixed set of choices'. If you pick a PESEL of A001100000Q then Q=10-A, it's still 'random', with a random date, but way less code. Saying that all valid PESELs for your date range must be possible blocks tricks like this. – bazzargh – 2014-04-13T09:44:10.430

@bazzargh Changed the question once again. – syntagma – 2014-04-13T09:47:13.527

1

Please correct the algorithm: The current version allows the last digit to be 10. The Polish Wikipedia version uses a modulo 10 operation to get 0 in this case.

– Heiko Oberdiek – 2014-04-13T12:20:59.227

1The gender entry uses the full range 0 to 9 to encode male and female (1 bit). What's the purpose of this "random noise"? Or are there further specification on the gender field that I have missed? – Heiko Oberdiek – 2014-04-13T12:24:00.170

3

The century is encoded in the month field. This is neither specified in the question or links. For example, it is explained in the Polish Wikipedia article.

– Heiko Oberdiek – 2014-04-13T12:26:13.403

1Please clarify the restrictions on the date. The question says, that all dates of the 20th and 21st century must be possible. It is unclear, if invalid dates are allowed. It makes a huge difference in a code golf competition, if the date has to be validated, e.g. excluding YYYY-02-29 with YYYY not being a leap year. – Heiko Oberdiek – 2014-04-13T12:34:41.007

See http://en.wikipedia.org/wiki/PESEL for an explanation, in English, of the PESEL encoding.

– DavidC – 2014-04-13T14:24:55.380

The control digit is found by taking the remainder of the number modulus 10. It is not found by subtraction. – DavidC – 2014-04-13T14:57:03.930

@DavidCarraher: Missed that, the Polish version has a nice table instead. – Heiko Oberdiek – 2014-04-13T16:15:22.430

@DavidCarraher: The result of the expression in the question is subtracted from 10 and then the control digit is the remainder of the number modulus 10. – Heiko Oberdiek – 2014-04-13T16:19:51.673

Isn't that the same as finding the remainder of division by 10. (I.e. the subtraction is unnecessary.) – DavidC – 2014-04-13T16:51:43.867

@DavidCarraher: 136 % 10 = 7 is different from (10 - (137 % 10)) % 10 = 3. (Of course there is room for optimization in the calculation of the control digit.) – Heiko Oberdiek – 2014-04-13T17:31:23.000

you are correct (of course)! – DavidC – 2014-04-13T19:01:04.653

Answers

2

Perl, 162 bytes

@a=map{$==rand 10}0..9;$"='';$a[5]%=2if($a[4]%=4)==3;"@a[4,5]"||$a[5]++;$a[3]=($a[2]%=4)%2?$a[3]%3:1+$a[3]%9;$f=9;for(@a){$x+=$f*$_;$f-=$f%10==7?4:2}print@a,$x%10

Ungolfed:

# Array with random digits
# ------------------------
@a = map { $= = rand 10} 0..9;
# do not insert a space, if arrays are interpolated into strings
$" = ''; #"

# Day correction
# --------------
# The day must be in the range of "01" to "31":
# * map first digit to "0" to "3": $a[4] %= 4
# * map second digit to "0" to "1" if first digit is "3"
$a[5] %= 2 if ($a[4] %= 4 ) == 3;
# * set day to "01" if day is "00"
"@a[4,5]" || $a[5]++;

# Month correction
# ----------------
# The month must be in the range "01" to "12" or "21" to "32"
# to get a valid month and century:
# * map the month to "00" to "39"
# * if the first digit is odd (catching both centuries at once)
#   * then map the second digit to "0" to "2"      (for months: 10..12)
#   * otherwise map the second digit to "1" to "9" (for months: 01-09)
$a[3] = ($a[2] %= 4) % 2 ? $a[3] % 3: 1 + $a[3] % 9;

# Calculate the control digit
# ---------------------------
# Because of the modulo 10 operations, the formula for the calculation
# of the control digit is rewritten from
# Q = (10 - ((A + 3B + 7C + 9D + E + 3F + 7G + 9H + I + J) % 10)) % 10
# to
# Q = (9A + 7B + 3C + D - E - 3F -7G - 9H - 11I - 11J) % 10
$f = 9;
for (@a) {
    $x += $f * $_;
    $f -= $f % 10 == 7 ? 4 : 2
}

# Print the result and control digit
print @a, $x % 10


# TEST section
# ------------

;$Q = $x % 10; # remember control digit in $Q

# Pretty print PESEL
print "\n\n",
  "YY MM DD ZZZ X Q\n",
  "@a[0,1] @a[2,3] @a[4,5] @a[6,7,8] $a[9] $Q\n";
print "\n";

# Pretty print the date
$month = "@a[2,3]";
$century = "??";
$century = "19" if $month >= 1 and $month <= 12;
$century = "20" if $month >= 21 and $month <= 32;
printf "Date: $century@a[0,1]-%02d-@a[4,5]\n", $month % 20;
print "\n";

# Pretty print the gender
print "Gender: ", $a[9] % 2 ? "male" : "female", "\n";
print "\n";

# Calculate the control date the official way
print "Control digit:\n";
$sum = 0;
$f = 0;
for (my ($i, $f) = (0, 1); $i<10; $i++, $f+=2) {
    $f %= 10;
    $f += 2 if $f == 5;
    printf "  $a[$i] * $f = %2d\n", $a[$i] * $f;
    $sum += $a[$i] * $f;
}
print "  ", "-" x 10, "\n";
printf "  %10d\n", $sum;
printf "  $Q = (10 - ($sum % 10)) % 10 = %d\n", (10 - ($sum % 10)) % 10;

Examples

83102570819

YY MM DD ZZZ X Q
83 10 25 708 1 9

Date: 1983-10-25

Gender: male

Control digit:
  8 * 1 =  8
  3 * 3 =  9
  1 * 7 =  7
  0 * 9 =  0
  2 * 1 =  2
  5 * 3 = 15
  7 * 7 = 49
  0 * 9 =  0
  8 * 1 =  8
  1 * 3 =  3
  ----------
         101
  9 = (10 - (101 % 10)) % 10 = 9
20233143600

YY MM DD ZZZ X Q
20 23 31 436 0 0

Date: 2020-03-31

Gender: female

Control digit:
  2 * 1 =  2
  0 * 3 =  0
  2 * 7 = 14
  3 * 9 = 27
  3 * 1 =  3
  1 * 3 =  3
  4 * 7 = 28
  3 * 9 = 27
  6 * 1 =  6
  0 * 3 =  0
  ----------
         110
  0 = (10 - (110 % 10)) % 10 = 0

Heiko Oberdiek

Posted 2014-04-13T08:47:08.033

Reputation: 3 841

1

Mathematica 247 270

A bit long but there are many details to take into consideration:

  • Allow any valid birth date between Jan. 1, 1900 and Dec. 31, 2099; Feb. 29 included in leap years.
  • Pad all numbers left with zeros: e.g. Month 3 becomes "03" so any PESEL will have exactly 11 digits.
  • Add 20 to month if in 21st century (2000-2099)

Ungolfed

Below the components are named for convenience.

g:=Module[{year,month,day,centuryIncrement,id,controlDigit,pesel},
{year,month,day}=DatePlus[{1900,1,1},RandomInteger[73048]];
centuryIncrement=20*Boole[year>= 2000];
Print[Row@{{year,month,day},"  ",DateString[{year,month,day},{"MonthName"," ","Day",", ","Year"}]},
"\ncentury increment: ",centuryIncrement,
"\nID: ",id=PadLeft[IntegerDigits@RandomInteger[999],3],
"\nsex: ",sex=RandomInteger[1]];
f=Flatten[{{IntegerDigits@year,PadLeft[IntegerDigits[month+centuryIncrement],2],
PadLeft[IntegerDigits@day,2]},id,sex}][[3;;12]];
Print["control digit: ",controlDigit=Mod[10-IntegerDigits[Tr@Thread[Times[f,{1,3,7,9,1,3,7,9,1,3}]]][[-1]],10],
"\nPESEL: ",""<>ToString/@PadLeft[Append[f,controlDigit]]]]

Examples

g

{1931,2,9} February 09, 1931
century increment: 0
ID: {0,8,8}
sex: 0
control digit: 9
PESEL: 31020908809


g

{2067,6,27} June 27, 2067
century increment: 20
ID: {9,0,8}
sex: 0
control digit: 1   PESEL: 67262790801  


g

{1967,9,5} September 05, 1967
century increment: 0
ID: {5,0,0}
sex: 0
control digit: 2
PESEL: 67090550002


Golfed

g:=Module[{y,m,d,i=IntegerDigits,p=PadLeft,r=RandomInteger},{y,m,d}=DatePlus[{1900,1,1},r[73048]];
f=Flatten[{{i@y,p[i[m+20*Boole[y>= 2000]],2],p[i@d,2]},p[i@r[999],3],r[1]}][[3;;12]];
""<>ToString/@p[Append[f,Mod[10-i[Tr@Thread[Times[f,{1,3,7,9,1,3,7,9,1,3}]]][[-1]],10]]]]

DavidC

Posted 2014-04-13T08:47:08.033

Reputation: 24 524

0

PHP, 151

echo($n=date("ymd",rand(-2e9,4e9)).rand(101,999).rand()%10).(10-($n[0]+3*$n[1]+7*$n[2]+9*$n[3]+$n[4]+3*$n[5]+7*$n[6]+9*$n[7]+$n[8]+3*$n[9])%10);

See it in action: http://ideone.com/DYeXf9

Mathieu Rodic

Posted 2014-04-13T08:47:08.033

Reputation: 1 170

1It doesn't generate valid PESEL number. – syntagma – 2014-04-13T09:32:50.207

Oh, ok... fixing it. – Mathieu Rodic – 2014-04-13T09:34:16.133

1The output it too long: 14 digits instead of 11. – syntagma – 2014-04-13T09:35:49.810

How do you ensure the validity of a date? – DavidC – 2014-04-13T14:36:19.503

0

Mathematica, 220

This generates random date between 1900-01-01 and 2099-12-31, but it does not check whether the number of days in the month is valid.

Value for gender ranges from 0 - 9.

This is as few characters as I could get it:

r=RandomInteger;a=r@9;b=r@9;m=r@11+1+r@1*20;c=Floor[m/10];d=m~Mod~10;n=r@30+1;e=Floor[n/10];f=n~Mod~10;g=r@9;h=r@9;i=r@9;j=r@9;k=Mod[10-Mod[a+3b+7c+9d+e+3f+7g+9h+i+3j,10],10];StringJoin[ToString/@{a,b,c,d,e,f,g,h,i,j,k}]

Sample output:

04020506179
34230487249
26321891950
45260298217

Ungolfed:

r=RandomInteger;

a=r@9; (*year*)
b=r@9;

month=r@11+1+r@1*20;
c=Floor[month/10];
d=month~Mod~10;

day=r@30+1;
e=Floor[day/10];
f=day~Mod~10;

g=r@9; (*personal ID*)
h=r@9;
i=r@9;

j=r@9; (*gender*)

k=Mod[10-Mod[a+3b+7c+9d+e+3f+7g+9h+i+3j,10],10]; (*control digit*)

StringJoin[ToString/@{a,b,c,d,e,f,g,h,i,j,k}]

kukac67

Posted 2014-04-13T08:47:08.033

Reputation: 2 159

day=r@30+1 assumes that any month can have 31 days? – DavidC – 2014-04-14T00:58:43.510

0

JavaScript - 246

Basic JS generator:

z=Math.random;y=(z()*200|0)+1900;o=(""+y).slice(-2)+("0"+(z()*12|0+(y>1999?21:1))).slice(-2);o+=("0"+(z()*31|0+1)).slice(-2);o+=("00"+(z()*999|0)).slice(-3);o+=z()*10|0;o+=(o[0]*1+o[1]*3+o[2]*7+o[3]*9+o[4]*1+o[5]*3+o[6]*7+o[7]*9+o[8]*1+o[9]*3)%10

Edit: was a bug in the 0 padding of the random 3 digit ID. Edit: Bug in the checksum and generation of all possible dates fixed.

Matt

Posted 2014-04-13T08:47:08.033

Reputation: 777

There are still some errors. E.g. generated incorrect pesel numbers: 44211950174, 81070127743, 32051356638... – Wojciech Jasiński – 2014-11-25T11:17:24.407

0

Mathematica, 157 chars

""<>ToString/@Join[#,{Mod[-#.{1,3,7,9,1,3,7,9,1,3},10]}]&@Flatten@{IntegerDigits[#,10,2]&/@RandomChoice@DateRange[{1990,1,1},{2099,12,31}],9~RandomInteger~4}

alephalpha

Posted 2014-04-13T08:47:08.033

Reputation: 23 988

0

Matlab, 156 bytes

a=datestr(693961+randi(73049),'yyyymmdd');a(5)=a(5)+2*(a(1)>49);A=a(3:8)-48;b=randi(10,1,4);[[A b mod(10-mod(sum(('1379137913'-48).*[A b]),10),10)]+48 '']

Ungolfed with some explanation:

a=datestr(693961+randi(73049),'yyyymmdd');
  -- generates date serial number in desired range and converts do string
a(5)=a(5)+2*(a(1)>49);
  -- modifies the first digit of the month if year >= 2000 (first digit >1)
A=a(3:8)-48;
  -- gets the "YYMMDD" part and converts from string to array of numbers
b=randi(10,1,4)-1;
  -- gets remaining 4 random digits ("ZZZX")
[[A b mod(10-mod(sum(('1379137913'-48).*[A b]),10),10)]+48 '']
  -- computes the last digit and converts the whole thing to string

pajonk

Posted 2014-04-13T08:47:08.033

Reputation: 2 480