bridge2vec

Bridge2Vec logo: the four card suits on a dark tile

Embeddings for contract bridge hands. Two hands land close together when they take tricks alike. Part of Weird2Vec, embedding models for data nobody embeds.

What is double dummy? A bridge deal is 52 cards dealt into four hands of 13: North, East, South and West. Double-dummy analysis assumes every player sees all four hands and plays perfectly. For each trump suit, or notrump, and each declarer, it gives the number of tricks declarer takes: a table of 5 × 4 numbers. Players at the table can't see the other hands, but double-dummy tricks are the usual yardstick for judging hands and contracts.

The model embeds one hand, the 13 cards a player sees when bidding. It reads each hand on its own and then has to predict the deal's double-dummy table from the four hand embeddings alone, so each embedding must carry what matters for taking tricks: lengths, honours, intermediates. Hands that could swap seats without changing the table end up close.

A random bridge deal: 13 cards for each of North, East, South and West around a dashed table

One deal, four hands. The model sees each hand alone.

🚀 Usage

The repo holds the script that trained the model, so one command embeds a hand (spades, hearts, diamonds, clubs):

uv run https://huggingface.co/jgalego/bridge2vec/resolve/main/bridge2vec.py embed --hand AKQ32.KJ4.T9.A87

It prints HCP and suit lengths, the expected tricks when this hand or its partner declares, the five most similar test hands, and the 128-dimensional embedding. With --deal it predicts a whole deal's table and prints the exact one next to it:

uv run https://huggingface.co/jgalego/bridge2vec/resolve/main/bridge2vec.py embed --deal "N:AKQ32.KJ4.T9.A87 JT98.AQ2.KQ8.K92 765.T98.AJ65.QJ3 4.7653.7432.T654"

🃏 Data

jgalego/bridge2vec-deals: random deals, each solved double dummy with DDS through endplay. The test split holds 1,000 random North hands, each dealt 32 times with random East, South and West hands. Averaging a test hand's 32 tables gives its expected table.

🏋️ Training

A transformer reads a hand's 13 cards, each a suit plus a rank, and pools them into a unit vector. For each declarer, an MLP reads the four hand embeddings in the order declarer, left-hand opponent, partner, right-hand opponent, and predicts declarer's tricks in each strain, so rotating the seats rotates the table. Each step relabels the suits at random and moves the table rows to match, since double-dummy results don't depend on suit names. Two small heads read a single embedding: one predicts the hand's expected table, the other its HCP and suit lengths.

Parameters 4,912,479 (4 layers, width 256, embedding 128)
Data 200,000 deals
Steps 50000, 1024 deals per step
Learning rate 0.0003, cosine
Final loss 2.7616 (table 0.8088), 0.648 of cells exact
Hardware NVIDIA A10G, 118 min

📊 Results

Tables. Predicted against exact tables for all 32,000 test deals, per cell.

MAE (tricks) Exact Within one Whole table exact
0.398 0.628 0.98 0.012

Hands. From one hand alone, the expected-table head is off by 0.346 tricks per cell on the 1000 test hands; guessing the average hand is off by 1.251.

Hard pairs. Hands with the same suit-length pattern and similar HCP look alike to a counting rule. Among them, for an anchor and two mates whose expected tables differ from the anchor's by more than half a trick, the embedding must rank the closer table first. Out of 98,216 triplets it gets 0.901 right; chance, and any rule that only counts points and cards per suit, gets 0.5.

Retrieval. Each test hand is matched to its nearest other test hand; the score is the mean difference between their expected tables, in tricks, so lower is better. Deals are matched the same way on their exact tables, excluding deals that share the test hand; a deal's embedding is its four hand embeddings in seat order.

Nearest by Hands Deals
Embedding 0.55 1.277
HCP and suit lengths 0.616 1.412
Random 1.781 3.135

The test hands' embeddings flattened with UMAP, coloured by expected notrump tricks

The test hands' embeddings, flattened with UMAP and coloured by expected notrump tricks with the hand declaring.

Training variants

The same model trained five ways, each on its own branch. main is metric0.3. The metric loss makes the embedding's similarity follow the distance between hands' expected tables (--metric-weight); the auxiliary weight scales the shape head (--aux-weight). Retrieval is the mean table distance to the nearest neighbour, so lower is better.

Branch Aux Metric Table MAE Exact Hard pairs Hand retrieval Deal retrieval
aux0 0 0 0.365 0.655 0.775 0.826 1.775
aux0.1 0.1 0 0.366 0.654 0.769 0.836 1.788
aux1 1 0 0.380 0.642 0.776 0.845 1.793
metric0.3 0.1 0.3 0.398 0.628 0.901 0.550 1.277
metric1 0.1 1 0.409 0.620 0.907 0.543 1.279

The auxiliary weight barely matters. The metric loss costs about 0.03 tricks of table accuracy and improves hard pairs from 0.77 to 0.90. Without it, retrieval by embedding is worse than by HCP and suit lengths; with it, it is better on hands (0.55 against 0.62) and on deals (1.28 against 1.41).

⚠️ Limitations

  • Double dummy is perfect play with all cards visible. Real play and bidding involve hidden cards, so the embedding knows nothing about conventions or what an auction reveals.
  • Deals are random, not from real games, where bidding selects which deals get played.
  • Expected tables average 32 deals per test hand, so they carry sampling noise.

📚 Data and software

  • DDS: B. Haglund and S. Hein's double-dummy solver.
  • endplay: D. Price's Python bridge library, which wraps DDS.
Downloads last month
-
Safetensors
Model size
4.91M params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train jgalego/bridge2vec

Space using jgalego/bridge2vec 1