Poker-AI.org

Poker AI and Botting Discussion Forum
It is currently Mon Nov 13, 2023 1:58 pm

All times are UTC




Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Dec 09, 2013 1:43 am 
Offline
Junior Member
User avatar

Joined: Sun Dec 08, 2013 4:22 pm
Posts: 15
A Fast and Optimal Hand Isomorphism Algorithm
by: Kevin Waugh

Abstract

In a section of their 2007 paper, Gilpen et. al. outline a technique for indexing poker hands that accounts for suit isomorphisms. Their implementation is specific to Texas Hold'em as it requires a large case analysis, and is not optimal as many cases are omitted. In this paper, we build on their ideas and provide a fast and optimal technique that generalizes beyond Texas Hold'em as well as provide an inverse mapping from an index to a canonical hand.

Link: https://www.aaai.org/ocs/index.php/WS/A ... /7042/6491


Top
 Profile  
 
PostPosted: Mon Dec 09, 2013 11:17 am 
Offline
Regular Member
User avatar

Joined: Sat May 25, 2013 7:36 am
Posts: 73
Once again this post gives a great insight to isomorphic hand-board-constellations

http://poker-ai.org/archive/www.pokerai ... view=print


Top
 Profile  
 
PostPosted: Mon Dec 09, 2013 5:38 pm 
Offline
Senior Member

Joined: Mon Mar 11, 2013 10:24 pm
Posts: 216
Does anyone know the actual meaning of the numbers in the table? For instance, they list the perfect turn indexing with ~55M entries, while a typical turn LUT only has ~15M entries. Hence, I wonder which information they additionally store. Is their approach considering different transitions from flops to the same turn, i.e. AsKhQd2s != 2sAsKhQd?


Top
 Profile  
 
PostPosted: Fri Dec 13, 2013 5:41 am 
Offline
Junior Member
User avatar

Joined: Sun Dec 08, 2013 4:22 pm
Posts: 15
I only skimmed the paper so I hope I got this right

Quote:
Is their approach considering different transitions from flops to the same turn, i.e. AsKhQd2s != 2sAsKhQd?


For example

AsKhQd|2s = KhAsQd|2s = AhQcKd|2h

The 3 card configurations above result in the same index. Your 2 examples result in a different index (if we assume the cards represent 3 flop cards and 1 turn card). It depends on how you group the cards. If we look at hole cards and flops instead of flops and turns we have the following grouping:

h1 h2 | f1 f2 f3 (and that's the grouping they use in their examples in the paper)

A complete Hold'em hand:

h1 h2 | f1 f2 f3 | t1 | r1

An Omaha hand:

h1 h2 h3 h4 | f1 f2 f3 | t1 | r1

Some weird Hold'em games deal another card after the river, called the 'ocean'. So then the grouping would be:
h1 h2 | f1 f2 f3 | t1 | r1 | o1

You get the point. This method generalizes earlier approaches that could only be used for Hold'em.
--------

Unrelated to the above question: They state that their indexing procedure leaves no holes. I don't know if this is true for other methods as well, but it is a nice property. For example, assume that N is the number of strategically different holecard/flop combinations. In order to enumerate all possible combinations, it is sufficient to loop from 1 to N, since every number represents exactly 1 combination.


Top
 Profile  
 
PostPosted: Fri Dec 13, 2013 5:53 pm 
Offline
New Member

Joined: Tue Dec 10, 2013 6:13 pm
Posts: 8
Great about Kevin Waugh is he has some code published:

https://github.com/kdub0/hand-isomorphism


Top
 Profile  
 
PostPosted: Sat Dec 14, 2013 9:46 am 
Offline
Junior Member
User avatar

Joined: Sun Dec 08, 2013 4:22 pm
Posts: 15
proud2bBot wrote:
Does anyone know the actual meaning of the numbers in the table? For instance, they list the perfect turn indexing with ~55M entries, while a typical turn LUT only has ~15M entries. Hence, I wonder which information they additionally store. Is their approach considering different transitions from flops to the same turn, i.e. AsKhQd2s != 2sAsKhQd?


I thought about this some more. In your example, if the 2 boards resulted in the same index, wouldn't this be a lossy abstraction? We 'forget' in which order the cards fell, so in a way we have imperfect recall (regarding the cards, not the betting in earlier rounds). Is this the standard way of building a typical turn LUT with 15M entries? In this case, for a given set of 4 cards, any one of them could be the turn card, so we need 4 times more entries if we want to remember which one the turn card was. We see this factor of 4 in your 15M number vs. the 55M number in the paper.

I always assumed the order has to be preserved. After all, different turn cards often have different strategic implications.

Quote:
Great about Kevin Waugh is he has some code published:

https://github.com/kdub0/hand-isomorphism


For Rhode Island Hold'em this implementation results in LUT sizes 13, 325, 9997 for preflop, flop and turn respectively.


Top
 Profile  
 
PostPosted: Sat Dec 14, 2013 11:29 am 
Offline
Site Admin
User avatar

Joined: Sun Feb 24, 2013 9:39 pm
Posts: 642
Quote:
Is this the standard way of building a typical turn LUT with 15M entries?
Probably, yes. AFIK most people deal with the imperfect/perfect recall issue in other ways. Imperfect recall is known to be am effective way of reducing the problem size.


Top
 Profile  
 
PostPosted: Sat Dec 14, 2013 5:34 pm 
Offline
Senior Member

Joined: Mon Mar 11, 2013 10:24 pm
Posts: 216
It always depends on which kind of data you store in the LUT. For instance, storing EHS2 values on the turn, a reduced LUT is sufficient. However, I wanted to store bucket information, in which case the order of the public board is actually relevant for me and then you want to have a LUT like the one in the paper. The cool thing about their approach is that you can easily create both indexing schemes.


Top
 Profile  
 
PostPosted: Thu Dec 19, 2013 12:06 am 
Offline
Junior Member

Joined: Thu May 23, 2013 11:35 pm
Posts: 23
amago wrote:
Great about Kevin Waugh is he has some code published:

https://github.com/kdub0/hand-isomorphism


I tried to run check.exe and got an assertion error. Anyone else get this?
(note there was a compile warning)

$ make check
cc -std=c99 -Wall -g -O2 -c -o src/check-main.o src/check-main.c
cc -std=c99 -Wall -g -O2 -c -o src/deck.o src/deck.c
cc -std=c99 -Wall -g -O2 -c -o src/hand_index.o src/hand_index.c
src/hand_index.c: In function ‘hand_index_ctor’:
src/hand_index.c:25:5: warning: suggest parentheses around ‘-’ in operand of ‘&’ [-Wparentheses]
for(uint_fast32_t j=0, set=~i&(1<<RANKS)-1; j<RANKS; ++j, set&=set-1) {
^
cc -o src/check src/check-main.o src/deck.o src/hand_index.o
./src/check
testing hand-isomorphism...
sizes: 169 1286792 55190538 2428287420
configurations: 2 15 46 158
permutations: 19 1315 8227 63523
preflop table:
A K Q J T 9 8 7 6 5 4 3 2
A 3053826047 7149443039322 7149443039321 7149443039320 7149443039319 7149443039318 7149443039317 7149443039316 7149443039315 7149443039314 7149443039313 7149443039312 7149443039311
K 3053826046 3053826034 7149443039310 7149443039309 7149443039308 7149443039307 7149443039306 7149443039305 7149443039304 7149443039303 7149443039302 7149443039301 7149443039300
Q 3053826045 3053826033 3053826022 7149443039299 7149443039298 7149443039297 7149443039296 7149443039295 7149443039294 7149443039293 7149443039292 7149443039291 7149443039290
...
...
full preflop...
assertion "index < size" failed: file "src/check-main.c", line 30, function: test_full


Top
 Profile  
 
PostPosted: Thu Dec 19, 2013 2:09 am 
Offline
Junior Member
User avatar

Joined: Sun Dec 08, 2013 4:22 pm
Posts: 15
algonoob wrote:
amago wrote:
Great about Kevin Waugh is he has some code published:

https://github.com/kdub0/hand-isomorphism


I tried to run check.exe and got an assertion error. Anyone else get this?


I did not get this error.

Quote:
(note there was a compile warning)

[...]
src/hand_index.c:25:5: warning: suggest parentheses around ‘-’ in operand of ‘&’ [-Wparentheses]
for(uint_fast32_t j=0, set=~i&(1<<RANKS)-1; j<RANKS; ++j, set&=set-1) {
^
cc -o src/check src/check-main.o src/deck.o src/hand_index.o


The line where the warning is thrown is interpreted wrong by your compiler. It's supposed to interpret it like so
set=~i&((1<<RANKS)-1);

but it interprets it like so:
set=(~i&(1<<RANKS))-1;

Add brackets like in the first example, that should fix it.


Top
 Profile  
 
PostPosted: Thu Dec 19, 2013 2:25 am 
Offline
Junior Member

Joined: Thu May 23, 2013 11:35 pm
Posts: 23
Thank you for the reply,
After modifying that line as you described, different numbers show but it's still an assert error.
I also tried different combinations of parentheses with no success.
What compiler are you using?

Here's the new table generated
A K Q J T 9 8 7 6 5 4 3 2
A 8280 6408570 6168251 5934016 5705787 5483486 5267035 5056356 4851371 4652002 4458171 4269800 4086811
K 8280 7084 3909126 3736667 3569356 3407115 3249866 3097531 2950032 2807291 2669230 2535771 2406836
Q 8280 7084 5980 2282347 2162226 2046395 1934776 1827291 1723862 1624411 1528860 1437131 1349146
J 8280 7084 5980 4968 1264827 1184096 1106875 1033086 962651 895492 831531 770690 712891
T 8280 7084 5980 4968 4048 658056 606107 556966 510555 466796 425611 386922 350651
9 8280 7084 5980 4968 4048 3220 316720 285051 255566 228187 202836 179435 157906
8 8280 7084 5980 4968 4048 3220 2484 138171 120152 103771 88950 75611 63676
7 8280 7084 5980 4968 4048 3220 2484 1840 53067 43706 35515 28416 22331
6 8280 7084 5980 4968 4048 3220 2484 1840 1288 17182 12891 9380 6571
5 8280 7084 5980 4968 4048 3220 2484 1840 1288 828 4386 2747 1576
4 8280 7084 5980 4968 4048 3220 2484 1840 1288 828 460 795 326
3 8280 7084 5980 4968 4048 3220 2484 1840 1288 828 460 184 91
2 8280 7084 5980 4968 4048 3220 2484 1840 1288 828 460 184 0
full preflop...
assertion "index < size" failed: file "src/check-main.c", line 30, function: test_full
Makefile:27: recipe for target `check' failed
make: *** [check] Aborted (core dumped)

edit: nevermind, the table generated doesn't change, I misread your post. The above table is generated using the incorrect order of operations. So it seems the compiler was treating it correctly the first time, which still gives the assertion error.


Top
 Profile  
 
PostPosted: Thu Dec 19, 2013 2:40 am 
Offline
Junior Member
User avatar

Joined: Sun Dec 08, 2013 4:22 pm
Posts: 15
ok, so the failed assertion doesn't have anything to do with the compiler warning. don't know what else could be the reason. i use gcc and it compiles just fine.


Top
 Profile  
 
PostPosted: Sat Jan 04, 2014 6:36 am 
Offline
Junior Member

Joined: Wed Jul 17, 2013 10:52 pm
Posts: 21
This is very nifty code... I wish I had a way to run k-means with 2 billion entries but I think my computer would explode.

You can still cut down on the number of indexes if you're thinking about Hold'em/Omaha because suits can become irrelevant eventually. e.g. on a three heart flop, if your hole cards don't contain a heart, it doesn't matter if your hole cards are suited or not. Like 7s6s on 2h3h4h is the same as 7d6c on 2h3h4h. Taking that into account, you can collapse a huge number of rivers together because oftentimes all suits become irrelevant because no flushes are possible. I wonder if there is a way to keep this setup as general/elegant as it is but add in a way to collapse suits when they can no longer make flushes.


Top
 Profile  
 
PostPosted: Fri Jan 31, 2014 11:19 am 
Offline
Junior Member

Joined: Wed Dec 04, 2013 12:40 am
Posts: 49
I was porting this to a JNI dll (first time!).
I get the method executed, but get the same assertion error...
It may have something to do with compilation chain options or flags I think, but I'm very bad at that (lazy Java guy).

I'll let you know if I find out what this mess is, please do the same ;)


Top
 Profile  
 
PostPosted: Sat Feb 01, 2014 11:39 pm 
Offline
Junior Member

Joined: Wed Jul 17, 2013 10:52 pm
Posts: 21
The grid of numbers that's displayed is supposed to be a table of all the holdem preflop indexes (from 0-168). The assertion error occurs because the table is wrong. First line should be:

90 168 167 166 165 164 163 162 161 160 159 158 157

I do think it's some compiler option causing the strange output. When compiling in "Release" mode in Visual Studio 2012, I got an incorrect grid of huge numbers like above, but when compiling in "Debug" mode I got the proper output. (I thought I made sure none of the initialization was done inside assert macros as well.)


Top
 Profile  
 
PostPosted: Sun Feb 02, 2014 2:03 am 
Offline
Junior Member

Joined: Wed Jul 17, 2013 10:52 pm
Posts: 21
Eventually, I just refactored the code my own way and specialized it for the most common indexes I use. Be warned when testing that both examples at the end of the paper have mistakes in them...

In the step from Equation (13) to Equation (14), he incorrectly has C(12,2) = 72 when actually it's 66, so the index within that suit configuration Equation (19) should actually be 55212.

The next example he tries to illustrate changing a hand to canonical form, but unfortunately changes one hand into a completely different hand when they are NOT isomorphic. You can tell that 6dTc|Jc7dKh is not the same as Ts6h|7sJhKd because in the first version the 6 in the hand and 7 on the board are the same suit, but not in the second version. (Same goes for the T in hand and J on board being suited in the first version, then not so in the second.)


Top
 Profile  
 
PostPosted: Sun Feb 02, 2014 4:48 pm 
Offline
Junior Member

Joined: Wed Dec 04, 2013 12:40 am
Posts: 49
+1 for the assertion failure origin :
I had
CFLAGS ?=-m64 -Wl, -std=c99 -Wall -g -O2

Now it's ok with
CFLAGS ?=-O0 -g3 -Wall -c -fmessage-length=0 -std=c99

Don't know what every flag means, but it works this way :)


Top
 Profile  
 
PostPosted: Fri Feb 14, 2014 12:50 pm 
Offline
Junior Member

Joined: Wed Dec 04, 2013 12:40 am
Posts: 49
Hi there,

I wrapped the C code into a x64 JNI dll, making some of the methods available to build Hold'em hands perfect recall and imperfect recall indexers, and a boards imperfect recall indexer.
You have to put the dll in the path of your x64 JVM, (using -Djava.library.path=path/to/the/library/directory for example).

The packages names are arbitrary, but you can't change com.pokertricks.HandIndexing's package because of JNI mecanism.

Look at com.pokertricks.HoldemIRHandIndexer, HoldemPRHandIndexer, and HoldemIRBoardIndexer to see how this intends to be used.

Didn't produce any benchmark.
Let me know if you need another native linking to have better indexers (other native methods for incremental indexing for example).
But keep the JNI cost in mind : a hand or board should be indexed for each round in one call.

Here are the sizes for hand indexers :

Imperfect recall :
[169, 1286792, 13960050, 123156254]

Perfect recall :
[169, 1286792, 55190538, 2428287420]

And for board IR indexer :

[1755, 16432, 134459]

Hope it can be helpful ! Tell me about any bug/potential improvement please.

Cheers


Attachments:
HandIndexing.rar [110.15 KiB]
Downloaded 2577 times
Top
 Profile  
 
PostPosted: Mon Feb 24, 2014 6:46 pm 
Offline
Junior Member

Joined: Wed Dec 04, 2013 12:40 am
Posts: 49
I see some of you downloaded the jni wrapper.

I just wanted to say I'm interested in any feedback (even : "It's useless, pointless and stupid, hope I didn't read your post at all you poor miserable Java demon").


Top
 Profile  
 
PostPosted: Tue Oct 07, 2014 5:43 am 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
How did you come up with those numbers? I have different numbers for imperfect hand indexing. Basically imperfect hand indexing on the turn let's say, would just be indexing of 6 cards, 1 round. My number is much smaller.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group