vcg_auction/
lib.rs

1//! A [Vickrey-Clarke-Groves
2//! auction](https://en.wikipedia.org/wiki/Vickrey%E2%80%93Clarke%E2%80%93Groves_auction)
3//! library.
4//!
5//! Given a set of items and bids, the highest value combination of bids is
6//! calculated, along with the payments each winner must make. Payments are the
7//! harm each winner causes to other bidders.
8//!
9//! Compatible bid types implement the [`Bid`] trait.
10//!
11//! The default feature `rand` can be disabled if only the non-tiebreaking
12//! implementation is desired.
13//!
14//! # Bid Combinations
15//!
16//! Bids associate a bidder name, a bid value, and a collection of items and
17//! quantities being bid on. Bids are supplied as a collection of "bid sets",
18//! where the bids inside a bid set are mutually-exclusive. Bids that are in
19//! separate bid sets are not mutually-exclusive.
20//!
21//! ```no_test
22//! [
23//!     [
24//!         (Alice, 5, [(chair, 1)]),
25//!         (Alice, 7, [(chair, 2)])
26//!     ],
27//!     [
28//!         (Bob, 4, [(chair, 1)])
29//!     ]
30//! ]
31//! ```
32//!
33//! Here Alice either wants one chair for 5, or two chairs for 7. Her bids are
34//! mutually-exclusive, and no outcome is considered where both bids win. Even
35//! if three chairs were available, Alice couldn't win all three.
36//!
37//! Bob's bid is in another bid set, so any combination of Bob's bid with one of
38//! Alice's bids is valid.
39//!
40//! Mutually-exclusive bids let bidders express their demand curves when
41//! their valuations are different for different combinations of items.
42//!
43//! If bidders want to bid for multiple items with unrelated valuations, those
44//! bids can be placed in separate bid sets instead of enumerating all
45//! combinations.
46//!
47//! ```no_test
48//! [
49//!     [
50//!         (Alice, 5, [(chair, 1)])
51//!     ],
52//!     [
53//!         (Alice, 10, [(table, 1)])
54//!     ],
55//!     [
56//!         (Bob, 20, [(chair, 1), (table, 1)])
57//!     ]
58//! ]
59//! ```
60//!
61//! Here Alice wants a chair for 5, a table for 10, or a table and a chair for
62//! 15. Bob only wants the chair and table together for 20.
63//!
64//! Similarly, if bidders are mutually-exclusive they can be put into the same
65//! bid set. If Bob and Carol wouldn't want to win a chair if the other person
66//! was also going to win a chair, their bids could be expressed like this:
67//!
68//! ```no_test
69//! [
70//!     [
71//!         (Bob, 4, [(chair, 1)]),
72//!         (Carol, 3, [(chair, 1)])
73//!     ]
74//! ]
75//! ```
76//!
77//! No outcome is considered where both win, even if two chairs are available.
78//! Since these bidders are different people, Bob's payment for winning a chair
79//! accounts for Carol's exclusion.
80//!
81//! # Example
82//!
83//! ```
84//! use vcg_auction::{vcg_auction, types::SimpleBid};
85//!
86//! # // Function wrapper lets us avoid unwrap() in the doc example.
87//! #
88//! # use std::error::Error;
89//! #
90//! # fn run_example() -> Option<()> {
91//!
92//! // Two chairs up for auction.
93//! let items = vec![("chair".to_string(), 2)];
94//! let bids = [
95//!     vec![
96//!         SimpleBid::new("Alice", 5, [("chair", 1)]),
97//!         SimpleBid::new("Alice", 7, [("chair", 2)]),
98//!     ],
99//!     vec![SimpleBid::new("Bob", 4, [("chair", 1)])],
100//! ];
101//! let result = vcg_auction(&items, &bids)?;
102//!
103//! // Alice and Bob each win a chair.
104//! assert_eq!(result.winning_bids, [&bids[0][0], &bids[1][0]]);
105//! // Bob's participation in the auction prevented Alice from getting a second
106//! // chair for an additional value of 2, so Bob only pays 2. Alice pays
107//! // nothing since her participation didn't prevent any other valuable
108//! // outcomes.
109//! assert_eq!(
110//!     result.payments,
111//!     [(&"Alice".to_string(), 0), (&"Bob".to_string(), 2)]
112//! );
113//!
114//! // Example from the VCG auction Wikipedia page.
115//! let items = vec![("apple".to_string(), 2)];
116//! let bids = vec![
117//!     vec![SimpleBid::new("Alice", 5, [("apple", 1)])],
118//!     vec![SimpleBid::new("Bob", 2, [("apple", 1)])],
119//!     vec![SimpleBid::new("Carol", 6, [("apple", 2)])],
120//! ];
121//! let result = vcg_auction(&items, &bids)?;
122//!
123//! assert_eq!(result.winning_bids, [&bids[0][0], &bids[1][0]]);
124//! assert_eq!(
125//!     result.payments,
126//!     [(&"Alice".to_string(), 4), (&"Bob".to_string(), 1)]
127//! );
128//!
129//! #     Some(())
130//! # }
131//! # assert!(run_example().is_some()) // still check for example success
132//! ```
133//!
134//! See the tests directory for examples using floating point numbers for bid
135//! values and item quantities, and the
136//! [`secrecy`](https://crates.io/crates/secrecy) crate to help keep bid values
137//! confidential. For floating point bid values, which must implement [`Ord`],
138//! you may want to use
139//! [`ordered-float`](https://crates.io/crates/ordered-float) or a similar
140//! crate.
141
142#![cfg_attr(docsrs, feature(doc_cfg))]
143
144mod traits;
145pub mod types;
146mod vcg;
147
148pub use traits::*;
149pub use vcg::*;