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  [ 6 posts ] 
Author Message
PostPosted: Fri Mar 27, 2020 10:43 am 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
I am currently adding PLO to my solver and I have been doing some research on evaluators. The most common approach seems to be to take a 5 card evaluator and iterate over all possible combinations of board and holecards.
There are (4 choose 2) = 6 hole card combinations and (5 choose 3) board card combinations, resulting in 60 combinations to check. Being around 60 times slower than Hold'em doesn't sound like a great solution.
The evaluators that I have found so far that would support this approach are:

1. Poker-Eval
https://github.com/atinm/poker-eval

I was not able to compile it on my Windows machine so far.

2. Steve Brecher:
I am able to use it on my machine, I have used it for Hold'em before. But having to test all combinations is still slow.

I have also found code written by Pulser which does not require checking multiple combinations, it looks faster than the other approach.
viewtopic.php?f=26&t=2705
download/file.php?id=67

I was also thinking about creating a LUT. K. Waugh's isomorphism algorithm (viewtopic.php?f=25&t=2660) tells me there are 502,018,902 river indexes, if I store the rank as a 4 byte integer that would mean a 2GB LUT. It's doable but not perfect. Unlike Hold'em I think the distinction between the hole cards and board cards is important for omaha, so my indexer code looks like this:
Code:
   const uint8_t cards_per_round_river[2] = { 4, 5 };
   hand_indexer_init(2, cards_per_round_river, &riverIndexer);

instead of this
Code:
   const uint8_t cards_per_round_river[1] = { 9 };
   hand_indexer_init(1, cards_per_round_river, &riverIndexer);


I will see if I find better solutions and keep the thread updated. Is anyone else working on PLO and has any tips how to improve the performance?


Top
 Profile  
 
PostPosted: Fri Mar 27, 2020 10:15 pm 
Offline
Regular Member

Joined: Wed Mar 18, 2015 10:02 am
Posts: 80
I use the solution " card evaluator and iterate over all possible combinations of board and holecards.".
The trick i use in addition when evaluating equity of range vs range, is to first iterate over all hands in both ranges and find best combination of board and holecard and write in dictionary (for fast access later). This is quite fast. Then when calculating range over range, it simply compares for every hand vs hand, the best combination of board nad holecard of hand1 with hand2, no need to find best combination in every iteration when calculating range vs range equity.
Still the issue i have is that ranges in omaha are quite huge, and it still gets slow to calculate range vs range.


Top
 Profile  
 
PostPosted: Wed Apr 01, 2020 2:56 pm 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
pulser wrote:
Attached a standalone version of the code here, with a simple profiler running 10 mill random hands. Seems it only does 17M hands/s for me now, not sure if it's my compiler settings or if I did something wrong last time i tested it.

Didn't go through the comments, but guess they can be ignored for the most part :p

Quote:
Also if you dont mind sharing, how do you create ranges of cards, if you do? I mean for example from a string "AAhh:(23+,35+)", ie. PPT style. That is what I am working on now and it seems tougher than i thought.
Guess I could share code for this too, but don't think I'll do so publicly.

Anyway, I read in hands at a format similar to what you mentioned, creating Range-objects hierarchically, combined with and or or links. After connecting all the rules it feeds hands through the different Rule-filters, eventually storing the final range as Hand-objects in a vector.

In no way rocket science, but it allows for complex combination of rules and a fast final product.


I downloaded the code and the test with random hands looks good so far, however I am not sure what card each integer represents.
Is it like 0 = "2c", 1 = "2d", 2 = "2h", 3 = "2s", 4 = "3c" ...

After anylysing the code I assume that the second encoding is used but currently I am having problems with detecting straights. I am not sure if it's the evaluator code or if I'm using it incorrectly.
or is it like
0 = "2c", 1 = "3c", 2 = "4c", 3 = "5c", 4 = "6c" ...


Top
 Profile  
 
PostPosted: Wed Apr 01, 2020 2:57 pm 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
nbiresev wrote:
I use the solution " card evaluator and iterate over all possible combinations of board and holecards.".
The trick i use in addition when evaluating equity of range vs range, is to first iterate over all hands in both ranges and find best combination of board and holecard and write in dictionary (for fast access later). This is quite fast. Then when calculating range over range, it simply compares for every hand vs hand, the best combination of board nad holecard of hand1 with hand2, no need to find best combination in every iteration when calculating range vs range equity.
Still the issue i have is that ranges in omaha are quite huge, and it still gets slow to calculate range vs range.


This sound interesting, but I am not trying to compute equity. I need it for monte carlo cfrm and the board and cards are random in each iteration, so I don't think I could use that optimization.


Top
 Profile  
 
PostPosted: Wed Apr 01, 2020 3:02 pm 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
I tried Pulser's own benchmark code and set a breakpoint in the line that returns the rank of a straight. In 10 million hands not one seems to be recognised as a straight, I think the straight detection code is probably wrong.


Top
 Profile  
 
PostPosted: Wed Apr 01, 2020 6:13 pm 
Offline
Veteran Member

Joined: Wed Mar 20, 2013 1:43 am
Posts: 267
I think I found the error, I don't know if it was a bug, or maybe it was just not meant to be used in a 64 bit app, old code:
Code:
#define countBits(x) ((x * 0x200040008001ULL & 0x111111111111111ULL) % 0xf)

new code:
Code:
unsigned short countBits(uint64_t n) {
   return __popcnt64(n);
}

__popcnt64() is also a bit faster, but that might depend on the compiler and cpu.
I have also run some benchmarks and it seems that the code is around 5 times faster than testing all combinations with Steve Brecher's code. I will write some more tests tomorrow and try to compare a few mio random hands between both algorithms and check if they, and my usage, are correct.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 3 guests


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