Showing posts with label pool. Show all posts
Showing posts with label pool. Show all posts

Wednesday, September 17, 2008

Revamped Perl Script To More Evenly Distribute Number Pool Match Odds

Hey There,

It's been noted (and I know that it's true) that the spread-system used in the last portion of our Perl script (posted yesterday in our entry regarding maximizing guaranteed matches) was somewhat uneven. The end result, of course, being that your given set-numbers from pool-numbers (3 from 5, 4 from 6, etc) guaranteed that the sets would be included in the generated pools, but (as was noticed by a few people, including myself) the downside (?) ends up being that the front-numbers are more heavily weighted. That is to say that, given a situation where you've got 6 balls drawn, you want to guarantee matches of 3 and you're using a number pool of 8 different numbers (1, 2, 3, 4, 5, 6, 7 and 8 - for example), the first 3 return a higher percentage of the time than the numbers at the other end of the spectrum.

I actually chose to go with this sort of distribution for a particular reason. Well, reasoning, anyway. My reasoning was this: If I rewrite the distribution so that it ends up being more "fair" (The best I could get was a somewhat even distribution that would guarantee any given match set would come up only once or twice), this would probably seem like a better deal, since the odds are "spread out." This is where I, possibly, view things a little bit differently. In our original setup, even though the front numbers are more heavily weighted, the end numbers are guaranteed to contain match sets that all come up at least once or twice. Really, you've got the same thing as the more "fair" method, except for two strong distinctions (aside from the fact that the distributions are unequal in comparative outcomes):

1. In the "fair" distribution, your end number matched-sets have approximately the same odds of returning as they do in the "unfair" distribution. In the "fair" distribution, your end numbers tend to go back and forth between 1 and 2 match-sets guaranteed. In the "unfair" distribution, your end numbers are almost always going to be only 1 match set guaranteed. In neither case should you ever be getting back 0 match sets.

2. In the "fair" distribution, your front number matched-sets have the same odds of returning as your end number matched sets (1, and no more than 2 times guaranteed). In the "unfair" distribution, you'll find several match sets that will return matched sets over 10 times, and then a few more at 9 and some more at 8, a good amount of 4's and 3's and then down to 1's. Basically, your front numbers will be weighted to match not "more often," but "more heavily" if they do hit.

The heavy distribution differential can be easily drawn out, like this (using currency as the currency ;):

a. Front numbers.

1. Fair distribution: Matched set 123 is drawn. We match it twice. Each payout on a matched set it 5 dollars. We've made 10 dollars.
2. Unfair distribution: Matched set 123 is drawn. We match it 11 times. Each payout on a matched set is 5 dollars. We've made 55 dollars.

b. End numbers

1. Fair distribution: Matched set 789 is drawn. We may match it twice (rather than just once). Each payout on a matched set it 5 dollars. We've made 10 dollars.
2. Unfair distribution: Matched set 789 is drawn. We match it once. Each payout on a matched set it 5 dollars. We've made 5 dollars.

So, yes, I have to agree that a difference does exist (and would actually love to find the most economic way to make both ends of the distribution weigh in at 8 to 11 returns without having to run up too many combinations (At a certain point your expenses outweigh your gains... not to mention that those gains are only "possible" and not real until you, maybe, get lucky ;)

Although we went over this previously, I'll repost some data, with slight variations, so that the full code for both the "fair" and "unfair" distributions are covered.

Enjoy :)



FAIR:


@ball_draw_pool = qw(12345 12346 12347 12348 12356 12357 12358 12367 12368 12378 12456 12457 12458 12467 12468 12478 12567 12568 12578 12678 13456 13457 13458 13467 13468 13478 13567 13568 13578 13678 14567 14568 14578 14678 15678 23456 23457 23458 23467 23468 23478 23567 23568 23578 23678 24567 24568 24578 24678 25678 34567 34568 34578 34678 35678 45678);
@rev_ball_draw_pool = qw(45678 35678 34678 34578 34568 34567 25678 24678 24578 24568 24567 23678 23578 23568 23567 23478 23468 23467 23458 23457 23456 15678 14678 14578 14568 14567 13678 13578 13568 13567 13478 13468 13467 13458 13457 13456 12678 12578 12568 12567 12478 12468 12467 12458 12457 12456 12378 12368 12367 12358 12357 12356 12348 12347 12346 12345);

@ball_trap_pool = qw(123 124 125 126 127 128 134 135 136 137 138 145 146 147 148 156 157 158 167 168 178 234 235 236 237 238 245 246 247 248 256 257 258 267 268 278 345 346 347 348 356 357 358 367 368 378 456 457 458 467 468 478 567 568 578
678);

foreach $smaller (@ball_trap_pool) {
@smaller = split("",$smaller);
foreach $larger (@ball_draw_pool) {
print "$larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2]\n";
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
foreach $smaller (@ball_trap_pool) {
@smaller = split("",$smaller);
foreach $larger (@rev_ball_draw_pool) {
print "$larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2]\n";
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
$counter = 1;
foreach $key (sort keys %total_pool ) {
$total_poolkey = length $total_pool{$key};
if ( $total_poolkey <= 6 ) {
next;
}
print "Game $counter: $key -- $total_pool{$key}\n";
$counter++;
}



UNFAIR


@ball_draw_pool = qw(12345 12346 12347 12348 12356 12357 12358 12367 12368 12378 12456 12457 12458 12467 12468 12478 12567 12568 12578 12678 13456 13457 13458 13467 13468 13478 13567 13568 13578 13678 14567 14568 14578 14678 15678 23456 23457 23458 23467 23468 23478 23567 23568 23578 23678 24567 24568 24578 24678 25678 34567 34568 34578 34678 35678 45678);

@ball_trap_pool = qw(123 124 125 126 127 128 134 135 136 137 138 145 146 147 148 156 157 158 167 168 178 234 235 236 237 238 245 246 247 248 256 257 258 267 268 278 345 346 347 348 356 357 358 367 368 378 456 457 458 467 468 478 567 568 578 678);

foreach $smaller (@ball_trap_pool) {
@smaller = split("",$smaller);
foreach $larger (@ball_draw_pool) {
print "$larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2]\n";
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
$counter = 1;
foreach $key (sort keys %total_pool ) {
$total_poolkey = length $total_pool{$key};
if ( $total_poolkey <= 6 ) {
next;
}
print "Game $counter: $key -- $total_pool{$key}\n";
$counter++;
}


, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, September 16, 2008

Perl Script To Maximize Guaranteed Combinations Within Fixed Lists

Hey there,

Breaking tradition (or continuing it, depending on how often you read this blog ;) we're going to have part 2 of yesterday's two-parter tomorrow and put up our final Perl script to find the maximum guaranteed number sets, or lists, within larger number pools. There's not too much else to explain about it, but we will lay out this road map, so that you can see (or possibly revisit or avoid ;) all of the different topics we covered that are included in this script and/or are directly relevant (kind of a list of directions to this post and its attached script).

In order to get to this script, we've tackled:

1. Number Pools And Guaranteed Matches
2. Permuting Lists and Strings With Perl
3. Sorting Lists And Removing Duplicates With Perl
4. Unique Sorting Of Lists Within Lists Within Lists
5. Determining The Maximum Amount Of Pool Sets In Any Number Pool
6. Finding Overlapping Matches Using Lookahead Assertions
7. Evaluating Number Grids
8. Maximizing Number Set Probability Within Number Pools


And, so, without further ado, the culmination of all that effort (okay, that's a bit of a stretch... how about, the amalgamation of all those different concepts ;) - A simple Perl script that gets all its input interactively, so it can be run very simply, like so (sample run):

host # ./wheel.pl
Highest Number: 39
Number Of Balls Drawn: 5
How Many Numbers To Trap: 3
Enter your numbers
separated by space character : 1 2 3 4 5 6 7 19


Highest Number 39
Balls Drawn 5
How Many Numbers To Trap: 3
Actual Numbers To Seed: 1 2 3 4 5 6 7 19
Running 4 phase permute...


Game 1: 1 2 3 4 19
Game 2: 1 2 3 4 5
Game 3: 1 2 3 4 6
Game 4: 1 2 3 4 7
Game 5: 1 2 3 5 19
Game 6: 1 2 3 5 6
Game 7: 1 2 3 5 7
Game 8: 1 2 3 6 19
Game 9: 1 2 3 6 7
Game 10: 1 2 3 7 19
Game 11: 1 2 4 5 19
Game 12: 1 2 4 5 6
Game 13: 1 2 4 5 7
Game 14: 1 2 4 6 19
Game 15: 1 2 4 6 7
Game 16: 1 2 4 7 19
Game 17: 1 2 5 6 19
Game 18: 1 2 5 6 7
Game 19: 1 2 5 7 19
Game 20: 1 2 6 7 19

Output saved in file: output.1_2_3_4_5_6_7_19.091508.6504


Again, this script isn't meant to used for gambling purposes, although it could be. We only chose this scenario as so many facets of our state's lottery relate directly to the concepts we've been going over for the past 2 weeks and it made it fun for the author :)

In all seriousness, if you have a gambling problem (cards, roulette, lottery, whatever) call 1-800-GAM-BLER or visit 800gambler.org and get some help. Like pretty much everything, the lottery is only fun if it's not hurting you! And, oh yes, if it helps, this number picker does not increase the likelihood that any of the numbers it picks will match any random drawing. Luck, and however many other digits are involved in the number pool, make this a losing proposition, at best. To prove this, I ran a test against the Illinois Lottery's past-drawing numbers for 2008 and found that, for my modest investment of $5,040, I would have made $764 in return. In other words, unless you're lucky, this number selection system will only guarantee that you'll lose more than you gain. Like all the disclaimers all say; it's for entertainment purposes only!

Okay, we've done our part. The PSA is over. Enjoy the script (it, and its parts, can be useful for a variety of other purposes) :)

NOTE: The improved permutation subroutine was found online in an excerpt from the Perl Cookbook, by Tom Christiansen and Nathan Torkington - an excellent read :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# wheel.pl
# TODO: out of order numseeds do not make correct output
#
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

print "Highest Number: ";
chomp($highest_number=<STDIN>);

print "Number Of Balls Drawn: ";
chomp($num_balls=<STDIN>);
$array_num_balls=$num_balls - 1;

print "How Many Numbers To Trap: ";
chomp($num_trap=<STDIN>);
$array_num_trap=$num_trap - 1;

print "Enter your numbers\n";
print "separated by space character : ";
chomp($num_seeds=<STDIN>);
$num_seeds =~ s/ /,/g;
@number_seeds = split(/,/, $num_seeds);
$number_seeds = @number_seeds;

if ( $number_balls > $num_seeds ) {
print "--------------------------\n";
print "Your picks $num_seeds\n";
print "is larger than $num_balls nums picked\n";
print "Try again!\n";
print "--------------------------\n";
exit(1);
}
foreach $unique_num (@number_seeds) {
if ($seen{$unique_num}++) {
print "--------------------------\n";
print "Your Number set $num_seeds\n";
print "contains duplicate numbers! Try again!\n";
print "--------------------------\n";
exit(2);
} elsif ( $unique_num > $highest_number ) {
print "--------------------------\n";
print "Your Number set $num_seeds contains\n";
print "a number $unique_num greater than\n";
print "your highest number value: ${highest_number}. Try again!\n";
print "--------------------------\n";
exit(3);
}
}

print "\n\n";
print "Highest Number $highest_number\n";
print "Balls Drawn $num_balls\n";
print "How Many Numbers To Trap: $num_trap\n";
print "Actual Numbers To Seed: @number_seeds\n";

$|=1;

@sperms = permoot(@number_seeds);
print "Running 4 phase permute...\n";

$useless_counter=0;
foreach $unordered (@sperms) {
$unordered =~ s/\s/,/g;
@unsorted = split(/,/, $unordered);
@crazy = @unsorted[0 .. $array_num_balls];
$unsorted = join(" ", @crazy);
@temparray = split(" ", $unsorted);
@temparray = sort { $a <=> $b } (@temparray);
unshift(@sorted_perms, "@temparray");
}

$unik="0";
$last_unik="0";
$useless_counter=0;
foreach $s_p (@sorted_perms) {
@unik = split(" ", $s_p);
@unik = sort(@unik);
$seen2{$s_p}++;
if ( $seen2{$s_p} >= 2 ) {
next;
}
if ( $unik == $last_unik ) {
unshift(@ball_draw_pool,"$s_p");
@last_unik = @unik;
$last_unik++;
} elsif ( @unik == @last_unik ) {
$total = @unik;
$zero = $nope = 0;
while ( $zero < $total ) {
if ( "$unik[$zero]" ne "$last_unik[$zero]" ) {
$nope = 1;
last;
} else {
$zero++;
}
}
if ( $nope ) {
unshift(@ball_draw_pool,"$s_p");
@last_unik = @unik;
}
}
}


$useless_counter=0;
foreach $unordered (@sperms) {
$unordered =~ s/\s/,/g;
@unsorted = split(/,/, $unordered);
@crazy = @unsorted[0 .. $array_num_trap];
$unsorted = join(" ", @crazy);
@temparray = split(" ", $unsorted);
@temparray = sort { $a <=> $b } (@temparray);
unshift(@sorted_perms, "@temparray");
}

$useless_counter=0;
$unik="0";
$last_unik="0";
foreach $s_p (@sorted_perms) {
@unik = split(" ", $s_p);
@unik = sort(@unik);
$seen2{$s_p}++;
if ( $seen2{$s_p} >= 2 ) {
next;
}
if ( $unik == $last_unik ) {
unshift(@ball_trap_pool,"$s_p");
@last_unik = @unik;
$last_unik++;
} elsif ( @unik == @last_unik ) {
$total = @unik;
$zero = $nope = 0;
while ( $zero < $total ) {
if ( "$unik[$zero]" ne "$last_unik[$zero]" ) {
$nope = 1;
last;
} else {
$zero++;
}
}
if ( $nope ) {
unshift(@ball_trap_pool,"$s_p");
@last_unik = @unik;
}
}
}
print "\n";

foreach $smaller (@ball_trap_pool) {
@smaller = split(" ",$smaller);
foreach $larger (@ball_draw_pool) {
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}

chomp($date=`date +%m%d%y`);
$var = $$;
$con_num_seeds = $num_seeds;
$con_num_seeds =~ s/,/_/g;
$lfile_name = "output.${con_num_seeds}.${date}.${var}";
print "\n";
open(LFILE, ">$lfile_name") or die "Cannot open FILE";
print LFILE "Output File output.${con_num_seeds}.${var}\n";
print LFILE "--------------------------------\n";
print LFILE "$highest_number Ball Selection - Pick $num_balls - Trap $num_trap\n";
print LFILE "Seed Numbers: $number_seeds\n";
print LFILE "--------------------------------\n";

$counter = 1;
foreach $key (sort keys %total_pool ) {
print "Game $counter: $key\n";
$|=1;
print LFILE "Game $counter: $key\n";
$counter++;
}
close(LFILE);
print "\nOutput saved in file: $lfile_name\n";

sub permoot {
#
# The improved permutation subroutine was found online in an excerpt from the Perl Cookbook, by Tom Christiansen and Nathan Torkington
@DATA = @_;
foreach ("@DATA") {
my @data = split;
my $num_permutations = factorial(scalar @data);
for (my $i=0; $i < $num_permutations; $i++) {
@permutation = @data[n2perm($i, $#data)];
@sortperms = join(" ", @permutation);
push(@sperms, "@sortperms" );
}
}
return @sperms;

BEGIN {
my @fact = (1);
sub factorial($) {
my $n = shift;
return $fact[$n] if defined $fact[$n];
$fact[$n] = $n * factorial($n - 1);
}
}

sub n2pat {
my $i = 1;
my $N = shift;
my $len = shift;
my @pat;
while ($i <= $len + 1) {
push @pat, $N % $i;
$N = int($N/$i);
$i++;
}
return @pat;
}

sub pat2perm {
my @pat = @_;
my @source = (0 .. $#pat);
my @perm;
push @perm, splice(@source, (pop @pat), 1) while @pat;
return @perm;
}

sub n2perm {
pat2perm(n2pat(@_));
}
}


, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Friday, September 12, 2008

Maximizing Set Match Probability Using Perl On Linux Or Unix

Hey There,

As promised (I think ;), we're back today with some code (not the entire script that encompasses the last 2 weeks worth of posts, of course) to grind out the final concept in this string of surprisingly wide-ranging topics all centered around the concepts of number pools and guaranteed matches. We've covered a lot of different aspects of mathematics, regular expression matching, etc just moving toward our Objective. So, aside from the link to our initial introductory number pools post, we'll just suffice it so say that every post since then (excluding the weekend humour) has been directly related to this mini-series' stated Objective. I'd love to label this paragraph with a whole slew of hyperlinks, but I'm going to pretend you're like me and don't want to get zapped to some other page every 5 seconds just because your finger twitches while you're reading this column ;) You should be able to access any of the older posts via the side menu or by just clicking on the "older posts" link at the bottom of the post itself.

BTW, thanks to an anonymous reader who pointed out that I accidentally goofed when I was manually typing out the distribution of number sets in yesterday's post. The line, in the first grid, that read:

12478 124 127 128 147 148 178 247 248 258 358
should have read:

12478 124 127 128 147 148 178 247 248 278 478

I got sloppy while I was doing the manual typing of the 3-digit strings and accidentally re-typed the last 2 3-digit sets from the previous line. Hopefully, I've fixed it by the time you read this ;)

As I worked out this last part (the brain teaser being directly related here), I found that, although I could squeeze all 3-digit combinations of our 8 numbers into 8 5-digit lists of numbers, the ratio of match to payoff was fairly low (depends on what you're looking for, I suppose) as laid out in the statistics below:

FORMAT: List of 8 5-Digit Sets

12346 12358 12478 13678 14567 23457 25678 34568

FORMAT: Approx % of set pool == # of times matched == # of sets == list of 3-digit matches
41% == 2 == 23 == 123 124 128 136 138 146 147 167 178 234 235 247 257 258 278 345 346 358 368 456 457 567 568
59% == 1 == 33 == 125 126 127 134 135 137 145 148 156 157 158 168 236 237 238 245 246 248 256 267 268 347 348 356 357 367 378 458 467 468 478 578 678


Of course, the idea here is to get the maximum amount of unique matches in a 5-digit set, but it would be nice to have more than a single or double return on each hit (and a greater weighted percentage on the 3-digit sets that match more than once in different lines on the grid), so that the statistical difference is more in your favour (Note: This post is not about the Lottery. We neither recommend nor discourage you from gambling. It's not our place. If you must gamble, only bet what you can afford to lose. That's just good advice all around ;) This is pretty bad, with a 41%/59% ratio of above-single-match-hits vs. single-match-hits

If we took the following Perl code (runnable on any Linux or Unix distro that supports Perl 5.6 and up -- the behaviour of hashes changed slightly around the 5.6 release), which iterates through the 56 5-digit lists we started getting into on our posts on sorting Perl lists and finding the maximum number of pool sets using binomial coefficient theory. The 5-digit list while-loop is wrapped in another while-loop that iterates through all the possible 3-digit sets (since we want to match 3 digits minimum) and populates a hash with keys and values to determine what lists (in our 56 member 5-digit set list) are viable for matching all possible 3-digit matches and returning the highest probable yield. You'll notice that the output is a little skewed toward the lower numbers due to the matching algorithm:

foreach $smaller (@tri_set_pool) {
@smaller = split("",$smaller);
foreach $larger (@five_digit_pool) {
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger
=~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
$counter = 1;
foreach $key (sort keys %total_pool ) {
print "Game $counter: $key\n";
$counter++;
}


Note that this code would give us "20" 5-digit match strings (up from our original 8), but a disproportionately better chance of a larger return (closer to the beginning, as noted above, which could be counted as a flaw ;)

FORMAT: List of 20 5-Digit Sets
12345 12346 12347 12348 12356 12357 12358 12367 12368 12378 12456 12457 12458 12467 12468 12478 12567 12568 12578 12678

FORMAT: Approx % of set pool == # of times matched == # of sets == list of 3-digit matches
1% == 11 == 1 == 125
6% == 10 == 3 == 123 124 128
1% == 8 == 1 == 127
1 % == 5 == 1 == 126
50% == 4 == 28 == 134 135 136 137 138 145 146 147 148 156 157 158 178 234 235 236 237 238 245 246 247 248 256 257 258 267 268 278
4% == 3 == 2 == 167 168
37% == 1 == 20 == 345 346 347 348 356 357 358 367 368 378 456 457 458 467 468 478 567 568 578 678


So, that's obviously a much better distribution of multiple 3-digit match occurrences (i.e., if you matched 123, you'd match it 10 times!) This tips thing back to good with a 63%/37% ratio of above-single-match-hits vs. single-match-hits.

Finally, one simple addition of a reversed 5-digit list array in the code, attacking the 3-digit matches against both and stripping off all 5-digit numbers that only contain a single match (note that this does not mean that no single match occurrences were found for any given 3-digit list!), gives us the best (as in most even) odds so far, although possibly not the best return on a win (statistics below the additional code following - pardon the cheap editor tricks ;) - This is another 20 list return, but with favorable-match odds that make it worth going over the modest 8-list list we started out with. Note, also, that this revision takes out the humungous skew between beginning and end (from 11 matches to 1 match) that our last revision created:

@five_digit_pool = qw(12345 12346 12347 12348 12356 12357 12358 12367 12368 12378 12456 12457 12458 12467 12468 12478 12567 12568 12578 12678 13456 13457 13458 13467 13468 13478 13567 13568 13578 13678 14567 14568 14578 14678 15678 23456 23457 23458 23467 23468 23478 23567 23568 23578 23678 24567 24568 24578 24678 25678 34567 34568 34578 34678 35678 45678);
@rev_five_digit_pool = qw(45678 35678 34678 34578 34568 34567 25678 24678 24578 24568 24567 23678 23578 23568 23567 23478 23468 23467 23458 23457 23456 15678 14678 14578 14568 14567 13678 13578 13568 13567 13478 13468 13467 13458 13457 13456 12678 12578 12568 12567 12478 12468 12467 12458 12457 12456 12378 12368 12367 12358 12357 12356 12348 12347 12346 12345);
@tri_set_pool = qw(123 124 125 126 127 128 134 135 136 137 138 145 146 147 148 156 157 158 167 168 178 234 235 236 237 238 245 246 247 248 256 257 258 267 268 278 345 346 347 348 356 357 358 367 368 378 456 457 458 467 468 478 567 568 578 678);

foreach $smaller (@tri_set_pool) {
@smaller = split("",$smaller);
foreach $larger (@five_digit_pool) {
print "$larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2]\n";
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
foreach $smaller (@tri_set_pool) {
@smaller = split("",$smaller);
foreach $larger (@rev_five_digit_pool) {
print "$larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2]\n";
if ( $larger =~ $smaller[0] && $larger =~ $smaller[1] && $larger =~ $smaller[2] ) {
$total_pool{$larger} .= $smaller;
last;
$|=1;
}
}
}
$counter = 1;
foreach $key (sort keys %total_pool ) {
$total_poolkey = length $total_pool{$key};
if ( $total_poolkey <= 6 ) {
next;
}
print "$counter: $key -- $total_pool{$key}\n";
$counter++;
}


FORMAT: List of 20 5-Digit Sets
12345 12346 12347 12348 12356 12357 12358 12367 12368 12378 12678 13678 14678 15678 23678 24678 25678 34678 35678 45678

FORMAT: Approx % of set pool == # of times matched == # of sets == list of 3-digit matches
64% == 2 == 36 == 123 126 127 137 138 146 147 148 156 157 158 167 168 178 236 237 238 246 247 248 256 257 258 267 268 278 346 347 348 356 357 358 367 368 378 678
36% == 1 == 20 == 124 125 128 134 135 136 145 234 235 245 345 456 457 458 467 468 478 567 568 578


So, with this 64%/36% ratio of above-single-match-hits vs. single-match-hits, we've got about the same statistical odds as our last rendition. This version should get you above a single-match more often (since the other leaves you in single-match territory on all sets starting with 3 and up), but it does dampen your possible return (you'll never hit a 3-digit match that comes up more than twice).

Depending upon how you're using this sort of probabilistic determination, one version may appeal more to you than the other (And, again, if you use this to spread lottery picks, you still stand a really good chance of not having any of the numbers in your set match what they pick out of the air. I look at the lottery as straight 50% odds. They'll either pick my numbers or they won't, no matter how "overdue" any combinations may be (Believe me, if you live in Chicago and follow the Cubs, you can witness the fallacy of the "overdue win" in real-life every year ;) It's all random and the future can't be inferred from past events ...unless your local lottery is crooked ;)

Anyway, I hope you all have a great weekend, and I'll be sure to pop the cleaned up (and all put together) version of the script, that encompasses the last 2 weeks worth of post topics, as soon as I can next week. Here's hoping I can find you some more funny stuff for the weekend. I promise: No number jokes ;)

Cheers,

, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Monday, September 8, 2008

Determining Maximum Pool Sets Using Binomial Coefficients On Linux and Unix

Hey There,



How's this for some light Monday reading? ;) Actually, the title sounds a lot worse than the concept or its application. In fact, if you read the equation in its "native form," above, it looks like gibberish, unless you're really into mathematics or engineering ;) For our purposes, we'll reduce it to something that looks like regular mathematics (which it is) and tie it back into our series of posts from last week. This is what the derivation looks like in English, assuming n=4 and k=3 (no math involved ;). In fact, if you understand the concept of deriving factorials, this is really fairly basic:

The binomial coefficient of 4 over 3 is derived, in steps, by:

a. the factorial of 4 divided by the factorial of 3 times the factorial of 4 minus 3 (Complete statement)
b. 24 divided by 6 times 1.
c. 24 divided by 6.
d. 4

Maybe it's just as confusing. I can't tell ;)

Our objective in this whole set of exercises, again is: Given a Number Pool of "x through y," create the maximum possible Fixed List Length variations of our Fixed List that contain some variation of our Guaranteed Combination, without any duplication (i.e. 1, 2, 3 is equal to 2, 3, 1 and would only count as one match), and return the results. Please check out the original post on Number Pools And Guaranteed Combinations Within Fixed Lists for definitions of the different parts of our Objective.

On its face, this post doesn't seem to fit into what we've been doing lately, but (I promise) it will actually make a difference in the end :)

The equation, shown above (and in plain numerals and English below ;) has many practical applications. For our case (which I believe is what it's most commonly used for) we're going to use it to determine how many unique Y-length sets (or lists) we can derive from a X-length pool (or larger list). To put this into ordinary, and manageable perspective, you could use this equation to determine how many unique sets of 3 numbers you could find in a list of 6 numbers (1, 2, 3, 4, 5, and 6). The answer would be 20 and you could prove this to yourself easily (without mathematics) by just writing out the unique combinations on paper. Something like this, except with no computer or web browser involved ;)

123 124 125 126 = 4
134 135 136 = 7
145 146 = 9
156 = 10
234 235 236 = 13
245 246 = 15
256 = 16
345 346 = 18
356 = 19
456 = 20


We'll be using this equation, to check and ensure that we have the smallest reduced set of Fixed List Length variations of our Fixed List that contain some variation of our Guaranteed Combination, when we think we're finally finished. If we've done our job well, the numbers should match. If we haven't, well... it'll really all be my fault and I'll be sure to give myself a good mental lashing ;)

For the meantime, I've attached a simple Perl script, which should work on most distro's of Linux and/or Unix, to the bottom of this post so that you can check out the power of binomial coefficient mangling and, perhaps, put it to some good use (although we, in no way, endorse this as a method to improve your odds at gambling... So little time and so many disclaimers ;)

You can run the Perl script simply, without arguments, as it will prompt you for them (unless you retool it yourself, which is totally cool, if you want to), like so:

host # ./binco.pl
Enter Larger Pool Number: 6
Enter Smaller Set Number: 3
Binomial Coefficient of 6 over 3 = 20


Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# binco.pl - More fun with numbers :)
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

print "Enter Larger Pool Number: ";
chomp($x=(<STDIN>));
print "Enter Smaller Set Number: ";
chomp($y=(<STDIN>));
$z=$x - $y;

$fact1 = fact($x);
$fact2 = fact($y);
$fact3 = fact($z);
$fact4 = $fact3 * $fact2;

$binco = $fact1 / $fact4;
print "Binomial Coefficient of $x over $y = $binco\n";

sub fact {
my $number = @_[0];
$fact = $number;
for ($factless1 = $number -1; $factless1 > 1; $factless1--) {
$fact *= $factless1;
}
return $fact;
}


, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, September 2, 2008

Number Pools And Guaranteed Combinations Within Fixed Lists

Hey There,

It's been a while since we've taken any time to look at any formal systems or number systems (all the way back to The M I U Puzzle, so today we're going to kick off a quick beginner post that is, somewhat Linux and Unix independent(although we'll be scripting and using Linux/Unix tools to do this work for us in future posts). It's going to segue into something more complicated in a future post, but, for today, we're just going to lay the groundwork. In fact, the beginnings of this process will seem almost brain-dead simple. Which is okay, because they pretty much are ;)

Our topic for today, and for all the follow-ups, is going to be: Number Pools and Guaranteed Combinations within Fixed Strings.

We'll adhere to the following definitions (Followed by our Objective):

Number Pool: A pool of unique numbers of any given amount spanning any given start and end numeric parameters.

Fixed List: A string of numbers of no more than the total number of numbers in the Number Pool and not containing any duplicate numbers.

Fixed List Length: The number of numbers in our Fixed List.

Guaranteed Combination: A combination of unique numbers (restricted to the members of the Fixed List we've defined) with a minimum member count of 1 and a maximum member count of the total number of numbers in our Fixed String.

Guaranteed Combination Length: The number of numbers in our Guaranteed Combination.

Our Objective: Given a Number Pool of "x through y," create the maximum possible Fixed List Length variations of our Fixed List that contain some variation of our Guaranteed Combination, without any duplication (i.e. 1, 2, 3 is equal to 2, 3, 1 and would only count as one match), and return the results.

Hopefully, that didn't sound too convoluted or complicated. It's not. Here's what we'll do to prove that very quickly.

1. Our Number Pool for today will be defined as: 1-5 (i.e. 1, 2, 3, 4, 5).
2. Our Fixed List will be: 1, 2, 3, 4, 5
3. This gives us a Fixed List Length of 5.
4. Our Guaranteed Combination, will be: 1, 2, 3, 4, 5
5. This gives us a Guaranteed Combination Length of 5.

So, the question before us is: Given a Number Pool of "1, 2, 3, 4, 5," what are the maximum possible variations of the 5 digit Fixed List "1, 2, 3, 4, 5" that we can create which will contain our Guaranteed Combination, without any duplication? (and, remember, this post is just to get you started thinking about the theory we'll put into practice later)

Simple deduction will lead you to this answer, since there can be only one correct answer (Which, in a sense, is true of larger systems, as well) and our variables are equal. Our result would be 1 variation:

1, 2, 3, 4, 5 <-- Note that the list 5, 4, 2, 1, 3 would be equal and would also be a correct answer, but would not count as an additional variation since it is made up of numbers duplicated from the original variation of 1, 2, 3, 4, 5.

Think about this for a while. It's a good exercise for your head :) In future posts we'll be looking at different variable expansions and the number theory behind generating these sort of lists (For example, a Number Pool of "1 through 99" with a Fixed String of "1, 3, 4, 6, 8, 9, 13, 17, 18, 20, 33, 47, 56, 68, 77, 87, 93" and a Guaranteed Combination of "1, 4, 6, 47, 68" - There will be a lot more strings to produce given these circumstances, which is where Linux or Unix scripting, as mentioned above, will help tremendously). Of course, we'll attack each individual part separately before combining them all into one equation (which will actually be somewhat simpler, but I guess that's a matter of opinion ;)

Cheers,

, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, May 6, 2008

ZFS Command Sheet For Solaris Unix 10 - Pool And File System Creation

Hey There,

Today, we're going back to the Solaris 10 Unix well and slapping together a few useful commands (or, at least, a few commands that you'll probably use a lot ;). We've already covered ZFS, and Solaris 10 zones, in our previous posts on creating storage pools for ZFS and patching Solaris 10 Unix zones, but those were more specific, while this post is meant to be a little quick-stop command repository (and only part one, today). This series also is going to focus more on ZFS and less on the "zone" aspect of the Solaris 10 OS.

Apologies if the explanations aren't as long as my normal posts are. ...Then again, some of you may be thanking me for the very same thing ;)

So, without further ado, some Solaris 10-specific commands that will hopefully help you in a pinch :) Note that for all commands where I specify a virtual device or storage pool, you can get a full listing of all available devices/pools by "not specifying" any storage pool. I'm just trying to keep the output to the point so this doesn't get out of hand.

Today we're going to take storage pools and ZFS file systems and look at creation-based commands, tomorrow we'll look at maintenance/usage commands, and then we'll dig on destructive commands and cleaning up the mess :)

1. To create virtual devices (vdevs), which can, technically, be virtual (disk made from a part, or parts, of real disk) or "real" disk if you have it available to you, you can do this:

host # mkfile 1g vdev1 vdev2 vdev3
host # # ls -l vdev[123]
-rw------T 1 root root 1073741824 May 5 09:47 vdev1
-rw------T 1 root root 1073741824 May 5 09:47 vdev2
-rw------T 1 root root 1073741824 May 5 09:48 vdev3


2. To create a storage pool, and check it out, you can do the following:

# zpool create zvdevs /vdev1 /vdev2 /vdev3
# zpool list zvdevs
<--- Don't specify the name of the pool if you want to get a listing of all storage pools!
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
zvdevs 2.98G 90K 2.98G 0% ONLINE -


3. If you want to create a mirror of two vdev's of different size, this can be done, but you'll be stuck with the smallest possible mirror (as it would be physically impossible to put more information on one disk that it can contain. That seems like common sense ;)

host # zpool create -f vzdevs mirror /vdev1 /smaller_vdev <--- The mirrored storage pool will be the size of the "smaller_vdev"

4. If you want to create a mirror, with all the disks (or vdevs) the same size (like they should be :), you can do it like this:

host # zpool create zvdevs mirror /vdev1 /vdev2 /vdev3 /vdevn... <--- I haven't hit the max yet, but I know you can create a "lot" of mirrors in the same set. Of course, you'd be wasting a lot of disk and it would probably make data access slower...

# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
myzfs 95.5M 112K 95.4M 0% ONLINE -
host # zpool status -v zvdevs
pool: zvdevs
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
zvdevs ONLINE 0 0 0
mirror ONLINE 0 0 0
/vdev1 ONLINE 0 0 0
/vdev2 ONLINE 0 0 0
/vdev3 ONLINE 0 0 0

errors: No known data errors


5. You can create new directories, add file systems on them and mount them in your storage pool very easily. All you need to do is "create" them with the "zfs" command. Three tasks in one! (as easy as creating a pool with the zpool command):

host # zfs create zvdevs/vusers
host # df -h zvdevs/vusers
Filesystem size used avail capacity Mounted on
zvdevs/vusers 984M 24K 984M 1% /zvdevs/vusers


6. If you need to create additional ZFS file systems, the command is the same, just lather rinse and repeat ;)

host # zfs create zvdevs/vusers2
host # zfs create zvdevs/vusers3
host # zfs list |grep zvdevs
zvdevs 182K 984M 27.5K /zvdevs
zvdevs/vusers 24.5K 984M 24.5K /zvdevs/vusers
zvdevs/vusers2 24.5K 984M 24.5K /zvdevs/vusers2
zvdevs/vusers3 24.5K 984M 24.5K /zvdevs/vusers3


See you tomorrow, for more fun with Solaris 10 ZFS/Storage Pool maintenance/usage commands :)

Cheers,

, Mike

Thursday, April 24, 2008

Creating Storage Pools For Solaris ZFS

Hey there,

As a way of getting on to addressing Solaris 10 Unix issues beyond patching zones and migrating zones, today we're going to put together a slam-bang setup of a Solaris ZFS storage pool. For those of you unfamiliar with ZFS (and I only mention this because I still barely ever use it -- Lots of folks are stuck on either Solaris 8 or 9 and are having a hard time letting go ;), it simply stands for "Zettabyte File System."

A Zettabyte = 1024 Exabytes.
An Exabyte = 1024 Petabytes.
A Petabyte = 1024 Terabytes.
A Terabyte = 1024 Gigabytes.
A Gigabyte = 1024 Megabytes.


And, at about this point the number scale makes sense to most of us. And, even though a Zettabyte seems like it's an unbelievably large amount of space, the next generation of operating systems will require twice as much RAM and disk space in order to respond to your key presses in under a minute ;)

Anyway, now that we have that out of the way, let's set up a ZFS pool.

First we'll create the pool, in a pretty straightforward fashion, using the zpool command and adding the disks (which can be in either cXtXdX notation, or specified by slice with cXtXdXsX notation. You can also use full logical path notation if you want (e.g. /dev/disk/cXtXdXsX). We'll assume two entire disks (unmirrored), create them and mount them for use:

host # zpool create MyPoolName c0t0d0 c0t1d0

Note that you can run "zpool create -n" to do a dry-run. This will allow you to find any mistakes you may be making in your command line as zpool doesn't "really" create the pool when you run it with the "-n" flag.

We also won't have to do anything extra to create the mount point, as it defaults to the name of the disk group. So, in this case, we would have a storage pool with a default mount point of /MyPoolName. This directory has to either not exist (in which case it will be automatically created) or exist and be empty (in which case the root dataset will be mounted over the existing directory). If you want to specify a different mount point, you can use the "-m" flag for zpool, like so:

host # zpool create -m /pools/MyPool MyPoolName c0t0d0 c0t1d0

And your ZFS storage pool is created! You can destroy it just as easily by running:

host # zpool destroy MyPoolName

or, if the pool is in a faulted state (or you experience any other error, but know you want to get rid of it), you can always force the issue ;)

host # zpool destroy -f MyPoolName

And you're just about ready to use your new "device." All you need to do is ( just like you would when mounting a regular disk device ) create a filesytem on your storage pool. You can do this pretty quickly with the zfs command, like so:

host # zfs create /MyPoolName/MyFileSystem

Note that the pool name directory is the base of the storage pool and your file system is actually created at the next level up. Basically, /MyPoolName is not your file system, but /MyPoolName/MyFileSystem is. And you can manage this file system, in much the same way you manage a regular ufs file system, using the zfs command.

Again, you can always opt-out and destroy it if you don't like it (here, as well, you have the option to "force" if you want):

host # zfs destroy /MyPoolName/MyFileSystem

Aside from "-f" (to force execution), the most common flags to use with "zfs destroy" are "-r" to do a recursive destroy or "-R" to recursively destroy all the regular descendants in the file system tree, plus all cloned file systems outside of your target directory (Be careful with that switch!)

We've only just brushed on getting started with zfs, but, hopefully, it's been somewhat helpful and, at the very least, readable ;)

Enjoy,

, Mike