Open Side Menu Go to the Top
Register
Will Tipton Video Pack 2 - Solving Poker Will Tipton Video Pack 2 - Solving Poker

10-03-2014 , 04:32 AM
thanks, it was an error in getMaxEVStrat
Will Tipton Video Pack 2 - Solving Poker Quote
10-03-2014 , 11:32 AM
How close in concept is the fictitious play algorithm to the idea of minimizing counterfactual regret?
Will Tipton Video Pack 2 - Solving Poker Quote
10-03-2014 , 10:34 PM
Quote:
Originally Posted by MixedUp Strategy
Yep thanks, I'd be interested in taking a look at it!
Flop Tree builder, a full flop tree for LHE, bets are measured in small bets or BB's.

Code:
# Flop tree builder
#Inputs: sln = 'name of solution', pot = starting pot size in SB, index = starting index number, array = 'name of array'


def flopTreeBldr (sln, pot, index, array):
    node = index
    # leaf = final decision point, 'Nature' if another street in Game Tree, 'Leaf' if final DecPt
    leaf = 'Nature'
    for i in range(27):
        sbCIP = pot/2.0
        bbCIP = pot/2.0
        if i == 0:
            player = 'BB'
            action = ""
        elif i == 1:
            player = 'SB'
            action = 'check'
        elif i == 2:
            player = leaf
            action = 'check'
        elif i == 3:
            player = 'BB'
            action = 'bet'
            sbCIP += 1.0
        elif i == 4:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 1.0
        elif i == 5:
            player = leaf
            action = 'call'
            sbCIP += 1.0
            bbCIP += 1.0
        elif i == 6:
            player = 'SB'
            action = "raise"
            sbCIP += 1.0
            bbCIP += 2.0
        elif i == 7:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 1.0
            bbCIP += 2.0
        elif i == 8:
            player = leaf
            action = 'call'
            sbCIP += 2.0
            bbCIP += 2.0
        elif i == 9:
            player = 'BB'
            action = 'raise'
            sbCIP += 3.0
            bbCIP += 2.0
        elif i == 10:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 3.0
            bbCIP += 2.0
        elif i == 11:
            player = leaf
            action = 'call'
            sbCIP += 3.0
            bbCIP += 3.0
        elif i == 12:
            player = 'SB'
            action = 'raise'
            sbCIP += 3.0
            bbCIP += 4.0
        elif i == 13:
            player = 'Leaf'
            action = "fold"
            sbCIP += 3.0
            bbCIP += 4.0
        elif i == 14:
            player = leaf
            action = 'call'
            sbCIP += 4.0
            bbCIP += 4.0
        elif i == 15:
            player = 'SB'
            action = 'bet'
            sbCIP += 0.0
            bbCIP += 1.0
        elif i == 16:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 0.0
            bbCIP += 1.0
        elif i == 17:
            player = leaf
            action = 'call'
            sbCIP += 1.0
            bbCIP += 1.0
        elif i == 18:
            player = 'BB'
            action = 'raise'
            sbCIP += 2.0
            bbCIP += 1.0
        elif i == 19:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 2.0
            bbCIP += 1.0
        elif i == 20:
            player = leaf
            action = "call"
            sbCIP += 2.0
            bbCIP += 2.0
        elif i == 21:
            player = 'SB'
            action = 'raise'
            sbCIP += 2.0
            bbCIP += 3.0
        elif i == 22:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 2.0
            bbCIP += 3.0
        elif i == 23:
            player = leaf
            action = 'call'
            sbCIP += 3.0
            bbCIP += 3.0
        elif i == 24:
            player = 'BB'
            action = 'raise'
            sbCIP += 4.0
            bbCIP += 3.0
        elif i == 25:
            player = 'Leaf'
            action = 'fold'
            sbCIP += 4.0
            bbCIP += 3.0
        elif i == 26:
            player = leaf
            action = 'call'
            sbCIP += 4.0
            bbCIP += 4.0
        else:
            print ("ERROR in Tree")
        print ("point" + str(node) + "= DecPt ('" + str(player) + "', " + str(sbCIP) + ", " + str(bbCIP) + ", " + \
               str(array) + ", '" + action + "')")
        node += 1

    child = index
    print (" ")
    print (str(sln) + " = Tree (S, point0)")

    for i in range(27):
        n = i + index
        if i == 0:
            print (" ")
        elif i == 1 or i == 2 or i == 4 or i == 7 or i == 10 or i == 13 or i == 16 or i == 19 or i == 22 or i == 25:
            child = n - 1
            print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
        elif i == 3 or i == 5 or i == 8 or i == 11 or i == 14 or i == 17 or i == 20 or i == 23 or i == 26:
            child = n - 2
            print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
        elif i == 6 or i == 9 or i == 12  or i == 18 or i == 21 or i == 24:
            child = n - 3
            print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
        elif i == 15:
            child = n - 15
            print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
        else:
            print ("ERROR in Tree")
        child += 1
Turn Tree for 13 flop nature cards

Code:
# Turn tree builder
#Inputs: pot = starting pot size in SB, node = starting node number, 
# array = EQarray 

def turnTreeBldr (sln, pot, index, startArray, parent):
    node = index
    leaf = 'Leaf'
    for j in range(13):
        array = startArray + str(j)
        for i in range(26):
            sbCIP = pot/2.0
            bbCIP = pot/2.0
            i += 1
            if i == 1:
                player = 'SB'
                action = 'check'
            elif i == 2:
                player = leaf
                action = 'check'
            elif i == 3:
                player = 'BB'
                action = 'bet'
                sbCIP += 2.0
            elif i == 4:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 2.0
            elif i == 5:
                player = leaf
                action = 'call'
                sbCIP += 2.0
                bbCIP += 2.0
            elif i == 6:
                player = 'SB'
                action = "raise"
                sbCIP += 2.0
                bbCIP += 4.0
            elif i == 7:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 2.0
                bbCIP += 4.0
            elif i == 8:
                player = leaf
                action = 'call'
                sbCIP += 4.0
                bbCIP += 4.0
            elif i == 9:
                player = 'BB'
                action = 'raise'
                sbCIP += 6.0
                bbCIP += 4.0
            elif i == 10:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 6.0
                bbCIP += 4.0
            elif i == 11:
                player = leaf
                action = 'call'
                sbCIP += 6.0
                bbCIP += 6.0
            elif i == 12:
                player = 'SB'
                action = 'raise'
                sbCIP += 6.0
                bbCIP += 8.0
            elif i == 13:
                player = 'Leaf'
                action = "fold"
                sbCIP += 6.0
                bbCIP += 8.0
            elif i == 14:
                player = leaf
                action = 'call'
                sbCIP += 8.0
                bbCIP += 8.0
            elif i == 15:
                player = 'SB'
                action = 'bet'
                sbCIP += 0.0
                bbCIP += 2.0
            elif i == 16:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 0.0
                bbCIP += 2.0
            elif i == 17:
                player = leaf
                action = 'call'
                sbCIP += 2.0
                bbCIP += 2.0
            elif i == 18:
                player = 'BB'
                action = 'raise'
                sbCIP += 4.0
                bbCIP += 2.0
            elif i == 19:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 4.0
                bbCIP += 2.0
            elif i == 20:
                player = leaf
                action = "call"
                sbCIP += 4.0
                bbCIP += 4.0
            elif i == 21:
                player = 'SB'
                action = 'raise'
                sbCIP += 4.0
                bbCIP += 6.0
            elif i == 22:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 4.0
                bbCIP += 6.0
            elif i == 23:
                player = leaf
                action = 'call'
                sbCIP += 6.0
                bbCIP += 6.0
            elif i == 24:
                player = 'BB'
                action = 'raise'
                sbCIP += 8.0
                bbCIP += 6.0
            elif i == 25:
                player = 'Leaf'
                action = 'fold'
                sbCIP += 8.0
                bbCIP += 6.0
            elif i == 26:
                player = leaf
                action = 'call'
                sbCIP += 8.0
                bbCIP += 8.0
            else:
                print ("ERROR in Tree")
            print ("point" + str(node) + "= DecPt ('" + str(player) + "', " + str(sbCIP) + ", " + str(bbCIP) + ", " + \
                   str(array) + ", '" + action + "')")
            node += 1
        array = startArray
    index = index - 1
    count = 0
    
    for j in range(13):
        for i in range(27):
            n = i + index + count
            if i == 0:
                pass
            elif i == 2 or i == 4 or i == 7 or i == 10 or i == 13 or i == 16 or i == 19 or i == 22 or i == 25:
                child = n - 1
                print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
            elif i == 3 or i == 5 or i == 8 or i == 11 or i == 14 or i == 17 or i == 20 or i == 23 or i == 26:
                child = n - 2
                print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
            elif i == 6 or i == 9 or i == 12  or i == 18 or i == 21 or i == 24:
                child = n - 3
                print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
            elif i == 15 or i == 1:
                child = parent
                print (str(sln) + ".addDecPt(point" + str(n) + ", point" + str(child) + ")")
            else:
                print ("ERROR in Tree")
        count += 26
        parent += 1
River is same as turn with a few minor adjustments
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 10:33 PM
Quote:
Originally Posted by Paul Hindemith
I'm having trouble making the optimisation to the EquityArray class mentioned above, namely to store equities in a 2-dimensional NUM_HANDS by NUM_HANDS array. I've tried two implementations and both are functional but 100x times slower than the original.

My first attempt involved changing the Range class to store ranges as lists of length(NUM_HANDS). This allowed me to perform get_equity_vs_range() effectively. One can store equities in a list:

equities = ea.equity_array[hand_index, :]

and then at the end of the function multiply using numpy.multiply(equities, villain_range) as villain_range is also a list of the same length.

The problem with this is finding hand conflicts. set_hands_with_conflicts() is so fast in the original code because the hand_array it takes is 2-dimensional and can be searched by single card. Now I see what Will meant when he said it would be "convenient" to use that data structure. After all, single cards are the relevant unit when it comes to finding conflicts. Re-writing set_hands_with_conflicts() to deal with ranges as lists of length(NUM_HANDS) has made it 100x slower.

So my second attempt was to keep the range data as a 2-dimensional array. Then the problem is in get_equity_vs_range(). How can we multiply each equity in a list of length(NUM_HANDS) by each item in the top right corner of villain_range? In other words by each of villain_range[i][j] for i < j.

I can only think of translating the 2-d villain_range into a list using

Code:
villain_range_list = []
for i in range (0, NUM_CARDS):
    for j in range (i+1, NUM_CARDS):
        villain_range_list.append(villain_range[i][j])
And then using numpy.multiply on the two lists. But again this is really slow when called by do_fp.

Any thoughts are much appreciated.
Sorry for the long delay here. So... I've gone with method 1.

So, IIRC, the reason we used set_hands_with_conflicts() was, in the end, to find out the number of hands in Villain's range for all of our possible holdings. There are a lot of ways to do that, many of which are slow. Here's one idea for doing it fast:

- For each of the 52 cards, have a list of all the hands that conflict with that card. (You only have to make these lists once.) (Notice that there are 51 such hands for each card.) (When I say a list of hands, I mean a list of indexes into your array of length NUM_HANDS.)

Then, when we want to know how big a particular villain range is for each of our holdings (e.g. if we put that answer in an array of length 1326 named result):
- Initialize all entries of result to be the number of hands in Villain' range without card removal effects considered (i.e. just summing up all the fractions).
- For each of the 52 cards
- Count the number of hands in Villain's range it conflicts with using your pre-computed lists of conflicting hands.
- Then subtract off that count from each entry in answer that conflicts with that hand, again using your precomputed list.
- Finally, add back to each entry of answer the fraction of hand in villain's range (that is, in vector notation answer = answer + villainRange), since we subtracted that fraction off twice.

Previously, I think we called something like getNumHandsWithoutConflicts() for each hero hand, and that function added up all the entries in Villain's range, checking each time for a conflict. So, those operations in total took time proportional to NUM_HANDS squared. This method takes time proportional to just NUM_HANDS. Much faster.
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 10:36 PM
Quote:
Originally Posted by tmfs
strats.dump(), would display all of the SB's actions at each index, correct?
Yes.
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 10:48 PM
Quote:
Originally Posted by klondi
Hi
I dident finish the video serie's for a long time.

But now started again. In video 8 i seem to have a diferent result from Tiptons with the plotEqDistn

my code
Code:
board = pe.string2card(['8d', '6s', '3h', 'Kd', 'Jd'])
range1 = Range(1.0)
range1.setToTop(0.2, board)
range2 = Range(1.0)
range2.setToTop(0.8, board)
plotEqDistn(range2,range1,board)
i get this result, but compared to Tiptons, he get a diferent curve. with a much more vertical line.

http://i.imgur.com/EOuFsOX.png




Any ideas ?
Ok well, think about this from a poker perspective for a minute. We're comparing the top 80% of hands on some river board to the top 20% of hands on that river board. Some card removal/chopping effects aside, the bottom 3/4 of that 80% range will lose to every hand in the 20% range. So, the bottom 3/4 of your equity distribution should be stuff with 0% equity. And that's what the correct ED shows:



That said, there are lots of things that could lead to an incorrect graph. The ranges could be wrong, the equity calcs could be wrong, the plotting function could be wrong. I wrote up some notes about debugging here:

http://willtipton.com/coding/2014/10/05/debugging.html

(it's an edited version of something I wrote earlier in this thread). Please give that stuff a shot, and if it doesn't fix the problem, it'll lead you to gather some information that will help us figure out what's going on.
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 10:56 PM
Quote:
Originally Posted by tmfs
Is anybody else having issues with future cards tainting earlier streets results. Going back through the videos it seems like the same issue is happening with Will's results. For example, reviewing the results for soln2, with both rivers being a 6, the output had betting pocket 6's. Will noted that will the rivers might be affecting the issue of betting 6's but didn't further address the issue.

Im having similar results and just doesn't seem, like you can have correct results if future cards are tainting decisions. For example in a full flop/turn scenario LHE problem on a Qd7c5c flop, the results returned are bet/calling with hands like J4o and J8o. Well one of the turns is the Jh, the other turn is the 6h and at least some percentage of the time the results are showing bet/3bet with 66.
Well, that's working as intended. The software doesn't magically know the rules of holdem -- the decision tree defines the game we're playing. If we make a decision tree where a 6 always comes on the river, then in the game we're playing, a 6 always comes on the river. And, one pair hands with a 6 in them on the turn will be effectively 2 pair hands as long as they're played in such a way as to make it to the river, since they will always pair up there.

The way to lesson/remove this effect is to add more/all possible rivers to your decision tree.

Quote:
I am quite sure I have my flop and turn equity arrays set up identical to Will's in videos. Would using an Equity Array of (['5d','7c','Qd','__','__'])); on the turn instead of (['5d','7c','Qd','Jh','__'])); and (['5d','7c','Qd','6h','__'])); respectively solve this issue?
No
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 11:28 PM
Quote:
Originally Posted by Befeltingu12
I recently was looking at a game tree and was getting some weird results. I wanted to look at a river situation where the river brings four to a straight and the SB has a stronger range then the BB but that the BB still has a decent amount of rivered straights. I gave the BB 3 strategic options. Donk bet 1/3 pot, Donk full pot and check decide. I just wanted to see what the ev difference would be between this and just playing a forced check by the BB.
The wierd part of the result that im getting is that when the BB plays Donk 1/3 Pot that the SB ends up folding 48% of the time. Im not sure whats going on here.
Board: 8s7d6h2c5d
sbStartingRange: AA,KK,QQ,JJ,TT,A9o,A5o,K5o,Q5o,J5o,T9o,T6o,T5o,A9s ,J6s,T9s,T6s
bbStartingRange: A9o,K9o,K8o,K7o,K6o,Q8o,Q7o,Q6o,J8o,J7o,T8o,T7o,A9 s,K9s,K8s,K7s

equity dist:


As you can see bb straights have a large amount of equity with the majority of his range having around 50% equity and then a small portion being total air

Here is the tree:
Pot = 18
Block bet = 6
stacks = 18



maybe I just have an error in the tree im not seeing but the average Evs are

SB average EV:19.1639331148
BB average EV:19.3592594477

So the BB actually has an advantage which is obviously false.
At point 6 in the game tree the SB is folding about 48.38%

Dont really know how anyone can help except maybe someone sees something wrong with my tree?
Maybe I'm misunderstanding, but I think BB does actually have the stronger range here, by a decent margin? Both in terms of average equity
Spoiler:

equity win tie pots won pots tied
Hand 0: 41.818% 40.98% 00.84% 5544 114.00 { TT+, J6s, T9s, T6s, A9o, A5o, K5o, Q5o, J5o, T9o, T6o-T5o }
Hand 1: 58.182% 57.34% 00.84% 7758 114.00 { K9s-K7s, A9o, K9o-K6o, Q8o-Q6o, J8o-J7o, T8o-T7o }

and in it's distribution. Your ED shows that BB's range is quite polarized, so it's no surprise he leads river a lot.

That said, your EVs look weird. Is the situation here is that there's 18 in the pot and 18 behind at the beginning of the street? Then there's 54BB in play, and your average EVs should add up to just about 54BB as well, but they don't. Check that you aren't affected by the errata, but there may be some other issue here as well.

Quote:
Originally Posted by Befeltingu12
So I think I figured out what was going on with my original model. The SB in that model just had too many 0% equity hands in his range so even though his range had an overall equity advantage over the BB when the BB chose to have a block bet as part of his strategy the SB was forced to fold a large amount (~ 42% over 300 iterations). Then He chose the rest to bluff raise with. When I did a different simulation on the same board with different ranges where the worst part of the SB range actually had some equity than I got a lot more reasonable results. Even with a more realistic range however I did find that the BB even with a equity disadvantage greatly increased his EV by including a block betting range on this board texture.
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 11:32 PM
Quote:
Originally Posted by Befeltingu12
I believe it was a different error message although it was a couple weeks ago that I tried so I cant remember exactly. I did follow all of the steps Will laid out and everything seemed to go smooth but I got the error when I tried to import pokereval as well. fwiw I am using anaconda and didnt try and do the installation with a different version.
Well, to be fair, using anaconda is something I explicitly said not to do because it causes problems, so it's a bit misleading to say that you followed my instructions, and it didn't work.
Will Tipton Video Pack 2 - Solving Poker Quote
10-05-2014 , 11:53 PM
Quote:
Originally Posted by WiltOnTilt
Anyone manage to get pokereval and ipython running together on mac? I followed Will's instructions above twice and still at the end I was unable to "import pokereval" without errors.

First, when trying to import pokereval I got ImportError: No module named pokereval.

Then it seemed like perhaps pokereval wasn't in the PYTHONPATH, so I put /Library/Python/2.7/site-packages into $PYTHONPATH and then when I import pokereval I get this:

>>> import pokereval
Fatal Python error: PyThreadState_Get: no current thread
Abort trap: 6

I also tried going directly to /Library/Python/2.7/site-packages and executing pokereval.py and I got the same error:

aaron@/Library/Python/2.7/site-packages $: python2 pokereval.py
Fatal Python error: PyThreadState_Get: no current thread
Abort trap: 6

Anyone have any ideas?

edit: I should probably point out that I'm using anaconda python. I installed it before I noticed Will saying it caused issues, so perhaps this is what he was referring to? But then I uninstalled anaconda and used the base python 2.7 installed by osx and I got the same error when executing it in the terminal.
Quote:
Originally Posted by WiltOnTilt
Thanks for letting me know, Paul. Based on some googling I wonder if I have some conflict with homebrew, macports, anaconda, and mavericks all having some versions of python installed on my machine. Quite odd that developing on windows has been more straight forward :-)
Linux is the easiest. But anyway, yea it sounds like there might be an issue with conflicting versions of things.

So first, you can check which binary runs when you type a command into the terminal with the which command, e.g.

Code:
[wtipton@everett ~]$ which python
/usr/bin/python
and second, I think the copies of python which show up in /usr/bin/ on macs are often symlinks to elsewhere, e.g.

Code:
[wtipton@everett ~]$ ls -l /usr/bin/python2.7
lrwxr-xr-rx  1 root  whieel  75 Feb 25  2014 /usr/bin/python2.7 -> /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
And, on my system. that happens to be the one that ipython2 uses. First, run 'which ipython2' to find the ipython2 you're running, and then open that file in a text editor. The first line, starting with #!, says which python interpreter that ipython will be using under the covers. On my computer, it shows the /System/Library/.../Python one, so I think that's the right answer. What does yours show?
Will Tipton Video Pack 2 - Solving Poker Quote
10-06-2014 , 12:41 AM
Quote:
Originally Posted by Rise of The Icarus
Hi there,

I believe there might be an error in the card removal calculations for the setMaxExplEVsAtNatureDP() function. Could anyone confirm it, for my ease of mind (who knows, I might be missing something terribly obvious)?

In short, the code does not seem to incorporate the (removal) effect of Villain Range in the probability of a new card being dealt, as it only checks for conflicts with our hand [i, j], but not with the new card being dealt (it does also check for conflicts between our hand and the board but not villain's range).

The line of code were I think the error might be is:

Code:
comboCounts[iChild] = villainRange.getNumHandsWithoutConflicts([i,j]) * tree.decPts[iChild].newCardFreq
As you can see villainRange.getNumHandsWithoutConflicts([i,j]) only calls our hand ([i, j]) but not the new card/board.

I believe the right code should be something like this:

Code:
conflictCards = newBoard + [i,j]
comboCounts[iChild] = VillainRange.getNumHandsWithoutConflicts(conflictCards) * tree.decPts[iChild].newCardFreq
I know that Will spent close to 20 minutes on this issue, so it seems strange that an error like this occurred. Any ideas?

Thanks in advance!
Yes, I believe you are correct. Thanks.

Btw, I mention in the video that that function's an approximation already. Anybody done any work on the full version?
Will Tipton Video Pack 2 - Solving Poker Quote
10-06-2014 , 05:59 AM
Quote:
Originally Posted by yaqh
Sorry for the long delay here. So... I've gone with method 1.

So, IIRC, the reason we used set_hands_with_conflicts() was, in the end, to find out the number of hands in Villain's range for all of our possible holdings. There are a lot of ways to do that, many of which are slow. Here's one idea for doing it fast:

- For each of the 52 cards, have a list of all the hands that conflict with that card. (You only have to make these lists once.) (Notice that there are 51 such hands for each card.) (When I say a list of hands, I mean a list of indexes into your array of length NUM_HANDS.)

Then, when we want to know how big a particular villain range is for each of our holdings (e.g. if we put that answer in an array of length 1326 named result):
- Initialize all entries of result to be the number of hands in Villain' range without card removal effects considered (i.e. just summing up all the fractions).
- For each of the 52 cards
- Count the number of hands in Villain's range it conflicts with using your pre-computed lists of conflicting hands.
- Then subtract off that count from each entry in answer that conflicts with that hand, again using your precomputed list.
- Finally, add back to each entry of answer the fraction of hand in villain's range (that is, in vector notation answer = answer + villainRange), since we subtracted that fraction off twice.

Previously, I think we called something like getNumHandsWithoutConflicts() for each hero hand, and that function added up all the entries in Villain's range, checking each time for a conflict. So, those operations in total took time proportional to NUM_HANDS squared. This method takes time proportional to just NUM_HANDS. Much faster.
my mind blows; I tried that approach and I don't even come close to the speed you mentioned.
I'll share my cython code:
Code:
#!python
#cython: boundscheck=False
#cython: wraparound=False

import numpy as np
cimport numpy as np
FTYPE = np.float
ctypedef np.float_t FTYPE_t
ITYPE = np.int
ctypedef np.int_t ITYPE_t


r1con={0:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
       1:[0, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100],
       2:[1, 51, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149],
       3:[2, 52, 101, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197],
       4:[3, 53, 102, 150, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244],
       5:[4, 54, 103, 151, 198, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290],
       6:[5, 55, 104, 152, 199, 245, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335],
       7:[6, 56, 105, 153, 200, 246, 291, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379],
       8:[7, 57, 106, 154, 201, 247, 292, 336, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422],
       9:[8, 58, 107, 155, 202, 248, 293, 337, 380, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464],
       10:[9, 59, 108, 156, 203, 249, 294, 338, 381, 423, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505],
       11:[10, 60, 109, 157, 204, 250, 295, 339, 382, 424, 465, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545],
       12:[11, 61, 110, 158, 205, 251, 296, 340, 383, 425, 466, 506, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584],
       13:[12, 62, 111, 159, 206, 252, 297, 341, 384, 426, 467, 507, 546, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622],
       14:[13, 63, 112, 160, 207, 253, 298, 342, 385, 427, 468, 508, 547, 585, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659],
       15:[14, 64, 113, 161, 208, 254, 299, 343, 386, 428, 469, 509, 548, 586, 623, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695],
       16:[15, 65, 114, 162, 209, 255, 300, 344, 387, 429, 470, 510, 549, 587, 624, 660, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730],
       17:[16, 66, 115, 163, 210, 256, 301, 345, 388, 430, 471, 511, 550, 588, 625, 661, 696, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764],
       18:[17, 67, 116, 164, 211, 257, 302, 346, 389, 431, 472, 512, 551, 589, 626, 662, 697, 731, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797],
       19:[18, 68, 117, 165, 212, 258, 303, 347, 390, 432, 473, 513, 552, 590, 627, 663, 698, 732, 765, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829],
       20:[19, 69, 118, 166, 213, 259, 304, 348, 391, 433, 474, 514, 553, 591, 628, 664, 699, 733, 766, 798, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860],
       21:[20, 70, 119, 167, 214, 260, 305, 349, 392, 434, 475, 515, 554, 592, 629, 665, 700, 734, 767, 799, 830, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890],
       22:[21, 71, 120, 168, 215, 261, 306, 350, 393, 435, 476, 516, 555, 593, 630, 666, 701, 735, 768, 800, 831, 861, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919],
       23:[22, 72, 121, 169, 216, 262, 307, 351, 394, 436, 477, 517, 556, 594, 631, 667, 702, 736, 769, 801, 832, 862, 891, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947],
       24:[23, 73, 122, 170, 217, 263, 308, 352, 395, 437, 478, 518, 557, 595, 632, 668, 703, 737, 770, 802, 833, 863, 892, 920, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974],
       25:[24, 74, 123, 171, 218, 264, 309, 353, 396, 438, 479, 519, 558, 596, 633, 669, 704, 738, 771, 803, 834, 864, 893, 921, 948, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000],
       26:[25, 75, 124, 172, 219, 265, 310, 354, 397, 439, 480, 520, 559, 597, 634, 670, 705, 739, 772, 804, 835, 865, 894, 922, 949, 975, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025],
       27:[26, 76, 125, 173, 220, 266, 311, 355, 398, 440, 481, 521, 560, 598, 635, 671, 706, 740, 773, 805, 836, 866, 895, 923, 950, 976, 1001, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049],
       28:[27, 77, 126, 174, 221, 267, 312, 356, 399, 441, 482, 522, 561, 599, 636, 672, 707, 741, 774, 806, 837, 867, 896, 924, 951, 977, 1002, 1026, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072],
       29:[28, 78, 127, 175, 222, 268, 313, 357, 400, 442, 483, 523, 562, 600, 637, 673, 708, 742, 775, 807, 838, 868, 897, 925, 952, 978, 1003, 1027, 1050, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094],
       30:[29, 79, 128, 176, 223, 269, 314, 358, 401, 443, 484, 524, 563, 601, 638, 674, 709, 743, 776, 808, 839, 869, 898, 926, 953, 979, 1004, 1028, 1051, 1073, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115],
       31:[30, 80, 129, 177, 224, 270, 315, 359, 402, 444, 485, 525, 564, 602, 639, 675, 710, 744, 777, 809, 840, 870, 899, 927, 954, 980, 1005, 1029, 1052, 1074, 1095, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135],
       32:[31, 81, 130, 178, 225, 271, 316, 360, 403, 445, 486, 526, 565, 603, 640, 676, 711, 745, 778, 810, 841, 871, 900, 928, 955, 981, 1006, 1030, 1053, 1075, 1096, 1116, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154],
       33:[32, 82, 131, 179, 226, 272, 317, 361, 404, 446, 487, 527, 566, 604, 641, 677, 712, 746, 779, 811, 842, 872, 901, 929, 956, 982, 1007, 1031, 1054, 1076, 1097, 1117, 1136, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172],
       34:[33, 83, 132, 180, 227, 273, 318, 362, 405, 447, 488, 528, 567, 605, 642, 678, 713, 747, 780, 812, 843, 873, 902, 930, 957, 983, 1008, 1032, 1055, 1077, 1098, 1118, 1137, 1155, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189],
       35:[34, 84, 133, 181, 228, 274, 319, 363, 406, 448, 489, 529, 568, 606, 643, 679, 714, 748, 781, 813, 844, 874, 903, 931, 958, 984, 1009, 1033, 1056, 1078, 1099, 1119, 1138, 1156, 1173, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205],
       36:[35, 85, 134, 182, 229, 275, 320, 364, 407, 449, 490, 530, 569, 607, 644, 680, 715, 749, 782, 814, 845, 875, 904, 932, 959, 985, 1010, 1034, 1057, 1079, 1100, 1120, 1139, 1157, 1174, 1190, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220],
       37:[36, 86, 135, 183, 230, 276, 321, 365, 408, 450, 491, 531, 570, 608, 645, 681, 716, 750, 783, 815, 846, 876, 905, 933, 960, 986, 1011, 1035, 1058, 1080, 1101, 1121, 1140, 1158, 1175, 1191, 1206, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234],
       38:[37, 87, 136, 184, 231, 277, 322, 366, 409, 451, 492, 532, 571, 609, 646, 682, 717, 751, 784, 816, 847, 877, 906, 934, 961, 987, 1012, 1036, 1059, 1081, 1102, 1122, 1141, 1159, 1176, 1192, 1207, 1221, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247],
       39:[38, 88, 137, 185, 232, 278, 323, 367, 410, 452, 493, 533, 572, 610, 647, 683, 718, 752, 785, 817, 848, 878, 907, 935, 962, 988, 1013, 1037, 1060, 1082, 1103, 1123, 1142, 1160, 1177, 1193, 1208, 1222, 1235, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259],
       40:[39, 89, 138, 186, 233, 279, 324, 368, 411, 453, 494, 534, 573, 611, 648, 684, 719, 753, 786, 818, 849, 879, 908, 936, 963, 989, 1014, 1038, 1061, 1083, 1104, 1124, 1143, 1161, 1178, 1194, 1209, 1223, 1236, 1248, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270],
       41:[40, 90, 139, 187, 234, 280, 325, 369, 412, 454, 495, 535, 574, 612, 649, 685, 720, 754, 787, 819, 850, 880, 909, 937, 964, 990, 1015, 1039, 1062, 1084, 1105, 1125, 1144, 1162, 1179, 1195, 1210, 1224, 1237, 1249, 1260, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280],
       42:[41, 91, 140, 188, 235, 281, 326, 370, 413, 455, 496, 536, 575, 613, 650, 686, 721, 755, 788, 820, 851, 881, 910, 938, 965, 991, 1016, 1040, 1063, 1085, 1106, 1126, 1145, 1163, 1180, 1196, 1211, 1225, 1238, 1250, 1261, 1271, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289],
       43:[42, 92, 141, 189, 236, 282, 327, 371, 414, 456, 497, 537, 576, 614, 651, 687, 722, 756, 789, 821, 852, 882, 911, 939, 966, 992, 1017, 1041, 1064, 1086, 1107, 1127, 1146, 1164, 1181, 1197, 1212, 1226, 1239, 1251, 1262, 1272, 1281, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297],
       44:[43, 93, 142, 190, 237, 283, 328, 372, 415, 457, 498, 538, 577, 615, 652, 688, 723, 757, 790, 822, 853, 883, 912, 940, 967, 993, 1018, 1042, 1065, 1087, 1108, 1128, 1147, 1165, 1182, 1198, 1213, 1227, 1240, 1252, 1263, 1273, 1282, 1290, 1298, 1299, 1300, 1301, 1302, 1303, 1304],
       45:[44, 94, 143, 191, 238, 284, 329, 373, 416, 458, 499, 539, 578, 616, 653, 689, 724, 758, 791, 823, 854, 884, 913, 941, 968, 994, 1019, 1043, 1066, 1088, 1109, 1129, 1148, 1166, 1183, 1199, 1214, 1228, 1241, 1253, 1264, 1274, 1283, 1291, 1298, 1305, 1306, 1307, 1308, 1309, 1310],
       46:[45, 95, 144, 192, 239, 285, 330, 374, 417, 459, 500, 540, 579, 617, 654, 690, 725, 759, 792, 824, 855, 885, 914, 942, 969, 995, 1020, 1044, 1067, 1089, 1110, 1130, 1149, 1167, 1184, 1200, 1215, 1229, 1242, 1254, 1265, 1275, 1284, 1292, 1299, 1305, 1311, 1312, 1313, 1314, 1315],
       47:[46, 96, 145, 193, 240, 286, 331, 375, 418, 460, 501, 541, 580, 618, 655, 691, 726, 760, 793, 825, 856, 886, 915, 943, 970, 996, 1021, 1045, 1068, 1090, 1111, 1131, 1150, 1168, 1185, 1201, 1216, 1230, 1243, 1255, 1266, 1276, 1285, 1293, 1300, 1306, 1311, 1316, 1317, 1318, 1319],
       48:[47, 97, 146, 194, 241, 287, 332, 376, 419, 461, 502, 542, 581, 619, 656, 692, 727, 761, 794, 826, 857, 887, 916, 944, 971, 997, 1022, 1046, 1069, 1091, 1112, 1132, 1151, 1169, 1186, 1202, 1217, 1231, 1244, 1256, 1267, 1277, 1286, 1294, 1301, 1307, 1312, 1316, 1320, 1321, 1322],
       49:[48, 98, 147, 195, 242, 288, 333, 377, 420, 462, 503, 543, 582, 620, 657, 693, 728, 762, 795, 827, 858, 888, 917, 945, 972, 998, 1023, 1047, 1070, 1092, 1113, 1133, 1152, 1170, 1187, 1203, 1218, 1232, 1245, 1257, 1268, 1278, 1287, 1295, 1302, 1308, 1313, 1317, 1320, 1323, 1324],
       50:[49, 99, 148, 196, 243, 289, 334, 378, 421, 463, 504, 544, 583, 621, 658, 694, 729, 763, 796, 828, 859, 889, 918, 946, 973, 999, 1024, 1048, 1071, 1093, 1114, 1134, 1153, 1171, 1188, 1204, 1219, 1233, 1246, 1258, 1269, 1279, 1288, 1296, 1303, 1309, 1314, 1318, 1321, 1323, 1325],
       51:[50, 100, 149, 197, 244, 290, 335, 379, 422, 464, 505, 545, 584, 622, 659, 695, 730, 764, 797, 829, 860, 890, 919, 947, 974, 1000, 1025, 1049, 1072, 1094, 1115, 1135, 1154, 1172, 1189, 1205, 1220, 1234, 1247, 1259, 1270, 1280, 1289, 1297, 1304, 1310, 1315, 1319, 1322, 1324, 1325],
       255:[]}


### following function only called from within cython
cdef float getNumHandsWithoutConflictshelpccc(np.ndarray[FTYPE_t, ndim=1] r,np.ndarray[ITYPE_t, ndim=1] cardslist):
    # Input:
    #   r - updated RANGE object (essentially r.r is given)
    #   cardlists - list of numbers representing cards
    # Output:
    #   the number of hand combos in the range which do not conflict with
    #   any of the cards in cardslists 
    # Side-effects:
    #   none

    cdef np.ndarray[FTYPE_t, ndim=1] temp
    cdef int c
    cdef int i
    temp = np.copy(r)
    for c in cardslist:
        for i in r1con[c]:
            temp[i]=0.0
    return np.sum(temp)

### following function only called from within python
def getNumHandsWithoutConflictshelp(np.ndarray[FTYPE_t, ndim=1] r,np.ndarray[ITYPE_t, ndim=1] cardslist):
    # Input:
    #   r - updated RANGE object (essentially r.r is given)
    #   cardlists - list of numbers representing cards
    # Output:
    #   the number of hand combos in the range which do not conflict with
    #   any of the cards in cardslists 
    # Side-effects:
    #   none
    cdef np.ndarray[FTYPE_t, ndim=1] temp 
    temp = np.copy(r)
    for c in cardslist:
        for i in r1con[c]:
            temp[i]=0.0
    return np.sum(temp)
My above function was the fastest I could create.

I tried before this the following 2 options (before I introduced data types in the code) in cython but it was way slower:
Code:
def getNumHandsWithoutConflictshelp (r,cardslist):
    result = np.sum(r.r)

    aid=[]
    for c in cardslist:
        aid+=r1con[c]

    aid=list(set(aid))

    for a in aid:
        result-=r.r[a]

    return result
Code:
def getNumHandsWithoutConflictshelp(r,cardslist):

    result = np.sum(r.r)

    for c in cardslist:
        for i in r1con[c]:
            result-=r.r[i]

    aid=list(set(cardslist)-set([255]))
    if len(aid) >1:
        aid.sort(reverse = 1)
        for a in xrange(len(aid)):
            for b in xrange(a+1,len(aid)):
                result+=r.r[r1con[aid[b]]]

    return result
Can you give some hint what the obvious thing is I am missing/doing wrong?
Will Tipton Video Pack 2 - Solving Poker Quote
10-06-2014 , 06:43 PM
Quote:
Originally Posted by WiltOnTilt
Thanks for letting me know, Paul. Based on some googling I wonder if I have some conflict with homebrew, macports, anaconda, and mavericks all having some versions of python installed on my machine. Quite odd that developing on windows has been more straight forward :-)
I set it up on mavericks with macports, and it works. The main issue for me was getting pypoker-eval to compile and install against the correct python interpreter. As I recall, I needed to set PYTHON_LIBS to point to the right place. Once that's resolved, everything else is fairly straightforward.
Will Tipton Video Pack 2 - Solving Poker Quote
10-07-2014 , 10:44 AM
Quote:
Originally Posted by yaqh
Yes, I believe you are correct. Thanks.

Btw, I mention in the video that that function's an approximation already. Anybody done any work on the full version?
For the general version:
I think that what you want to do is to project the probability on each hand of villain's range: (of course villain range is adjusted so to avoid conflicts with hero's hand [i,j] and nature's cards that can be dealt as well)

proba(nature deals card c) = sum on all h(proba(nature deals card c knowing that villain plays hand h) * proba(villain plays hand h))
Villain's range is the one before nature's move so those events are independent.
In case every card can be dealt with equal frequency:
proba(nature deals card c knowing that villain plays hand h) = 1/numCards if no conflicts and h not in nature's possible cards, 1/(numCards-1) if no conflicts and one card of h in nature's possible cards, 1/(numCards-2) if both cards of h in nature's children and no conflicts, 0 if hand h conflicts with card c.
proba(villain plays hand h) = villainRange.r[h]/villainRange.getNumHands

In the 7d,8d,9d,Td,Jd,Qd example:
hero's range is 7d8d, villains range is Td9d,Jd9d
4 possible dealt cards, 9d,Td,Jd,Qd
proba(9d) = 0 obv (both hands conflict)
proba(Td) = 0*.5 + (1/(4-2))*.5 = .25
proba(Jd) = (1/(4-2))*.5 + 0*.5 = .25
proba(Qd) = (1/(4-2))*.5 + 1/((4-2))*.5 = .5

This way of thinking can easily be extended to more general cases with different frequencies.

I rarely post on 2+2 so I would like to use the space for a little announcement...
I am doing lots and lots of stuff starting from Will's videos (thanks again for the material!) but could definitely use some help. It would probably be more fun too
It would be either collaborative with a mid high stakes poker player like myself, who obv would have already worked a bit on will's vids, or it would be a remunerated job with a highly technical person. (I have been in many tehnical directions and lost a lot of time on some subjects, like parallel computing for instance). Please pm me, thanks! (and no scammer, oh well poker these days )
Will Tipton Video Pack 2 - Solving Poker Quote
10-09-2014 , 12:39 PM
Quote:
Originally Posted by yaqh
Sorry for the long delay here. So... I've gone with method 1.

So, IIRC, the reason we used set_hands_with_conflicts() was, in the end, to find out the number of hands in Villain's range for all of our possible holdings. There are a lot of ways to do that, many of which are slow. Here's one idea for doing it fast:

- For each of the 52 cards, have a list of all the hands that conflict with that card. (You only have to make these lists once.) (Notice that there are 51 such hands for each card.) (When I say a list of hands, I mean a list of indexes into your array of length NUM_HANDS.)

Then, when we want to know how big a particular villain range is for each of our holdings (e.g. if we put that answer in an array of length 1326 named result):
- Initialize all entries of result to be the number of hands in Villain' range without card removal effects considered (i.e. just summing up all the fractions).
- For each of the 52 cards
- Count the number of hands in Villain's range it conflicts with using your pre-computed lists of conflicting hands.
- Then subtract off that count from each entry in answer that conflicts with that hand, again using your precomputed list.
- Finally, add back to each entry of answer the fraction of hand in villain's range (that is, in vector notation answer = answer + villainRange), since we subtracted that fraction off twice.

Previously, I think we called something like getNumHandsWithoutConflicts() for each hero hand, and that function added up all the entries in Villain's range, checking each time for a conflict. So, those operations in total took time proportional to NUM_HANDS squared. This method takes time proportional to just NUM_HANDS. Much faster.
Thanks Will.

I've made the following changes to the original code:
1) I'm now using 2D equity arrays and 1D range data
2) I'm using the conflicts dictionary from Emus (thanks!) above in set_hands_with_conflicts()
3) I've replaced get_num_hands_no_conflicts() with get_range_size_no_conflicts() which performs the calculation you suggest
4) I've replaced the relevant code in set_max_evs_at_villain_dp() and set_max_evs_at_nature_dp() so that one call is made to get_range_size_no_conflicts() to create the range size data before the loop over all hands, rather than within that loop. Within the loop I just look up the relevant range size.

I used the original turn spot from the videos to test the speed change. I performed 300 iterations. Please see the %prun data below. The original non-optimised code is first.





So the time taken is down from roughly 1100 seconds to 700 seconds. Is that the size gain you would expect?

I'm now calling set_hands_with_conflicts() 6,000,000 times rather than 18,000,000 times. It is called by get_equity_vs_range() so I guess that's why it remains a large part of the runtime.

But it still takes almost the same amount of time as before! I don't understand that. Any ideas?

FWIW here's my set_hands_with_conflicts() function:
Code:
# conflicts_dict is a dictionary as provided by Emus earlier in the thread
def set_hands_with_conflicts(hand_array, cards_list, num):
    for c in cards_list:
        for i in conflicts_dict[c]:
            hand_array[i] = num
Will Tipton Video Pack 2 - Solving Poker Quote
10-10-2014 , 04:29 AM
Quote:
Originally Posted by Paul Hindemith
Thanks Will.

I've made the following changes to the original code:
1) I'm now using 2D equity arrays and 1D range data
2) I'm using the conflicts dictionary from Emus (thanks!) above in set_hands_with_conflicts()
3) I've replaced get_num_hands_no_conflicts() with get_range_size_no_conflicts() which performs the calculation you suggest
4) I've replaced the relevant code in set_max_evs_at_villain_dp() and set_max_evs_at_nature_dp() so that one call is made to get_range_size_no_conflicts() to create the range size data before the loop over all hands, rather than within that loop. Within the loop I just look up the relevant range size.

I used the original turn spot from the videos to test the speed change. I performed 300 iterations. Please see the %prun data below. The original non-optimised code is first.





So the time taken is down from roughly 1100 seconds to 700 seconds. Is that the size gain you would expect?

I'm now calling set_hands_with_conflicts() 6,000,000 times rather than 18,000,000 times. It is called by get_equity_vs_range() so I guess that's why it remains a large part of the runtime.

But it still takes almost the same amount of time as before! I don't understand that. Any ideas?

FWIW here's my set_hands_with_conflicts() function:
Code:
# conflicts_dict is a dictionary as provided by Emus earlier in the thread
def set_hands_with_conflicts(hand_array, cards_list, num):
    for c in cards_list:
        for i in conflicts_dict[c]:
            hand_array[i] = num
Got the same problem. I guess we have no other choice then to study deeply those 5 pdf's Will gave us. Essentially, we likely still use in some way partially python code and such we still have to do something so the function runs completely on C code with some C speed optimizations.
Will Tipton Video Pack 2 - Solving Poker Quote
10-24-2014 , 12:11 AM
So, finally after reinstalling my mac back to factory setting and starting from scratch and following Will's instructions that he laid out It seems I have everything working properly so thanks for that Will.
Will Tipton Video Pack 2 - Solving Poker Quote
11-02-2014 , 09:23 PM
Quote:
Originally Posted by yaqh
Ok well, think about this from a poker perspective for a minute. We're comparing the top 80% of hands on some river board to the top 20% of hands on that river board. Some card removal/chopping effects aside, the bottom 3/4 of that 80% range will lose to every hand in the 20% range. So, the bottom 3/4 of your equity distribution should be stuff with 0% equity. And that's what the correct ED shows:



That said, there are lots of things that could lead to an incorrect graph. The ranges could be wrong, the equity calcs could be wrong, the plotting function could be wrong. I wrote up some notes about debugging here:

http://willtipton.com/coding/2014/10/05/debugging.html

(it's an edited version of something I wrote earlier in this thread). Please give that stuff a shot, and if it doesn't fix the problem, it'll lead you to gather some information that will help us figure out what's going on.
I had the exact same graph generated as klond.


Also my 1st graph didn't come out quite right :-/

Idk if it's relevant but the only other bit of code that didn't quite work out right occurred when trying to generate a file name for the pf board 255,255,255,255,255

Any idea on how to fix this? My only thought on it is it's something to do with the preflop.ea.npy file, that you included for us to save time, and the above code. As I 1st started the pack a while ago and have recently come back to it (working again from beginning in a new note book) and had already imported that file. I note that klondi had also retaken up the video pack.

Anyway I'll press on with the rest of the videos as I'm really enjoying the pack. It's not too hard to understand whats going on even for a complete n00b like myself!

Thanks in advance for any help
Will Tipton Video Pack 2 - Solving Poker Quote
11-03-2014 , 05:20 PM
@Unicron

I found my error a while ago,. I cant remember it now, but it was one of the functions in the Range class that is used to plot the graph that had a typo.

Maybe you can start looking in the range class functions and see if you can solve it.
Will Tipton Video Pack 2 - Solving Poker Quote
11-04-2014 , 08:26 AM
Can anyone say if the video series improved their game,will your game improve by studying the books alone?
I don't think I'd have the time or patience to start learning Python.
Will Tipton Video Pack 2 - Solving Poker Quote
11-13-2014 , 07:24 AM
Hi, great series, thanks!
I've got a problem tho, when i try to solve the 2 streets example in my result BB checks near 0% on the turn (300 iterations, same board, same ect). On the other hand the preflop minraise sollution is completly fine. Went over the code several times, but couldn't spot the problem yet. Got any ideas?
Will Tipton Video Pack 2 - Solving Poker Quote
11-21-2014 , 07:25 AM
How can we print the EV of a particular hand at the solution?

And what would be the best way to print out the EV of all hands at the solution?

Thanks
Will Tipton Video Pack 2 - Solving Poker Quote
11-24-2014 , 12:34 PM
Quote:
Originally Posted by Emus
my mind blows; I tried that approach and I don't even come close to the speed you mentioned.
I'll share my cython code:

<snip>

Can you give some hint what the obvious thing is I am missing/doing wrong?
So, I didn't go through your code, but what are you saying is slow, exactly? If you've improved one function, but the overall program is slow, then perhaps another function is the problem (or even was in the first place). Have you profiled to check how much time is being spent in each function. If not, please do so and share the results. Many profilers can tell you how much time is being spent on any individual line of code, and that can be really helpful in figuring out what's slow.

If I had to try to optimize python code without that info, it'd be a matter of making sure I know what's going on under the covers when my code runs. E.g., we're using a lot of lists or arrays here. Sometimes when we insert into an array, it has to move all the other numbers over to make space. Or it makes a copy of the array before sticking the new value on the end. Definitely want to make sure nothing like that is going on.

I don't know what support there is for profiling/debugging cython code, but I imagine there is some since performance is pretty much the whole reason for its existence.

edit: yea, so I didn't read all that code, but if it's still a problem for you, and you can provide some profiling info, then lmk and I'll try harder .

Last edited by yaqh; 11-24-2014 at 12:44 PM.
Will Tipton Video Pack 2 - Solving Poker Quote
11-24-2014 , 12:35 PM
Quote:
Originally Posted by jonna102
I set it up on mavericks with macports, and it works. The main issue for me was getting pypoker-eval to compile and install against the correct python interpreter. As I recall, I needed to set PYTHON_LIBS to point to the right place. Once that's resolved, everything else is fairly straightforward.
Thanks for the info!
Will Tipton Video Pack 2 - Solving Poker Quote
11-24-2014 , 12:43 PM
Quote:
Originally Posted by Renaud Desferet
For the general version:
I think that what you want to do is to project the probability on each hand of villain's range: (of course villain range is adjusted so to avoid conflicts with hero's hand [i,j] and nature's cards that can be dealt as well)

proba(nature deals card c) = sum on all h(proba(nature deals card c knowing that villain plays hand h) * proba(villain plays hand h))
Villain's range is the one before nature's move so those events are independent.
In case every card can be dealt with equal frequency:
proba(nature deals card c knowing that villain plays hand h) = 1/numCards if no conflicts and h not in nature's possible cards, 1/(numCards-1) if no conflicts and one card of h in nature's possible cards, 1/(numCards-2) if both cards of h in nature's children and no conflicts, 0 if hand h conflicts with card c.
proba(villain plays hand h) = villainRange.r[h]/villainRange.getNumHands

In the 7d,8d,9d,Td,Jd,Qd example:
hero's range is 7d8d, villains range is Td9d,Jd9d
4 possible dealt cards, 9d,Td,Jd,Qd
proba(9d) = 0 obv (both hands conflict)
proba(Td) = 0*.5 + (1/(4-2))*.5 = .25
proba(Jd) = (1/(4-2))*.5 + 0*.5 = .25
proba(Qd) = (1/(4-2))*.5 + 1/((4-2))*.5 = .5

This way of thinking can easily be extended to more general cases with different frequencies.
Thanks for sharing this. Out of curiosity, did you implement it, and have you any other observations since then? Speed?

The main reason I made it possible to give an arbitrary a priori probability of a card being dealt (other than just 1/num-cards-left-in-the-deck) is to help set up model games. E.g. if we're on the turn, and there's a flushdraw out, and we want a cheap model that includes play on flushing and non-flushing rivers, then maybe we just make a decision tree with two rivers (one flush and one not), but give the two cards different probabilities of being dealt...

Quote:
I rarely post on 2+2 so I would like to use the space for a little announcement...
I am doing lots and lots of stuff starting from Will's videos (thanks again for the material!) but could definitely use some help. It would probably be more fun too
It would be either collaborative with a mid high stakes poker player like myself, who obv would have already worked a bit on will's vids, or it would be a remunerated job with a highly technical person. (I have been in many tehnical directions and lost a lot of time on some subjects, like parallel computing for instance). Please pm me, thanks! (and no scammer, oh well poker these days )
Will Tipton Video Pack 2 - Solving Poker Quote

      
m