uatlib
Loading...
Searching...
No Matches
simulation.hpp
Go to the documentation of this file.
1
3
4#ifndef UAT_SIMULATION_HPP
5#define UAT_SIMULATION_HPP
6
7#include <uat/agent.hpp>
8
9#include <deque>
10#include <optional>
11#include <random>
12#include <vector>
13
14#include <cool/compose.hpp>
15
16namespace uat
17{
18
20using factory_t = std::function<std::vector<any_agent>(uint_t, int)>;
21
23template <region_compatible R> struct trade_info_t
24{
25 uint_t transaction_time;
26 uint_t from;
27 uint_t to;
28 R location;
29 uint_t time;
30 value_t value;
31};
32
34constexpr auto no_owner = std::numeric_limits<uint_t>::max();
35
36namespace permit_private_status
37{
38
47
49struct in_use
50{
51 uint_t owner;
52};
53
56{};
57
58} // namespace permit_private_status
59
62{
64 std::variant<permit_private_status::on_sale, permit_private_status::in_use, permit_private_status::out_of_limits> current;
65
67 std::vector<trade_value_t> history;
68};
69
70namespace agent_private_status
71{
72
75{
76 id_t id;
77};
78
80struct active
81{
82 id_t id;
83 any_agent data;
84};
85
86} // namespace agent_private_status
87
89using agent_private_status_t = std::variant<agent_private_status::inactive, agent_private_status::active>;
90
93{
94public:
98
99 void insert(any_agent);
100 void update_active(std::vector<id_t>);
101 auto at(id_t) -> any_agent&;
102
103private:
104 uint_t first_id_ = 0u;
105 std::deque<any_agent> agents_;
106 std::vector<id_t> active_;
107};
108
111
114
117
118namespace stop_criterion
119{
120
122struct no_agents_t
123{};
124
126struct time_threshold_t
127{
128 uint_t t;
129};
130} // namespace stop_criterion
131
133using stop_criterion_t = std::variant<stop_criterion::no_agents_t, stop_criterion::time_threshold_t>;
134
145
151template <region_compatible R> auto simulate(const simulation_opts_t<R>& opts = {}) -> void
152{
153 std::mt19937 rnd(opts.seed ? *opts.seed : std::random_device{}());
154
155 agents_private_status_t agents;
156 std::vector<id_t> keep_active;
157
158 uint_t t0 = 0;
159
160 std::deque<std::unordered_map<permit<R>, permit_private_status_t>> data;
161
162 permit_private_status_t ool = {permit_private_status::out_of_limits{}, {}};
163 auto book = [&t0, &data, &ool, &opts](region_view loc, uint_t t) mutable -> permit_private_status_t& {
164 if (t < t0) // XXX agents can check the state at t0, however they should be prohibited to bid for.
165 return ool;
166 if (opts.time_window && t > t0 + 1 + *opts.time_window)
167 return ool;
168 while (t - t0 >= data.size())
169 data.emplace_back();
170 return data[t - t0][{loc.downcast<R>(), t}];
171 };
172
173 auto safe_book = [&book](region_view loc, uint_t t) -> permit_private_status_t { return book(loc, t); };
174
175 auto public_access = [&book](auto id) {
176 return [id = id, &book](region_view s, uint_t t) -> permit_public_status_t {
177 using namespace permit_private_status;
178 using namespace permit_public_status;
179 const auto& pstatus = book(s, t);
180 return std::visit(
181 cool::compose{
182 [](out_of_limits) -> permit_public_status_t { return unavailable{}; },
183 [&](in_use status) -> permit_public_status_t {
184 return status.owner == id ? permit_public_status_t{owned{}} : unavailable{};
185 },
186 [&](on_sale status) -> permit_public_status_t {
187 return status.owner == id ? permit_public_status_t{unavailable{}} : available{status.min_value, pstatus.history};
188 }},
189 pstatus.current);
190 };
191 };
192
193 const auto stop = [&] {
194 using namespace stop_criterion;
195 return std::visit(cool::compose{
196 [&](no_agents_t) { return agents.active_count() == 0; },
197 [&](time_threshold_t th) { return t0 > th.t; },
198 },
199 opts.stop_criterion);
200 };
201
202 do {
203 if (opts.simulation_callback)
204 opts.simulation_callback(t0, std::as_const(agents), permit_private_status_fn(safe_book));
205
206 // Generate new agents
207 if (opts.factory) {
208 auto new_agents = opts.factory(t0, rnd());
209 for (auto& agent : new_agents)
210 agents.insert(std::move(agent));
211 }
212
213 {
214 // Bid phase
215 std::vector<permit<R>> bids;
216 for (const auto id : agents.active()) {
217 auto bid = [&](region_view s, uint_t t, value_t v) -> bool {
218 if (t < t0)
219 return false;
220 using namespace permit_private_status;
221 const auto visitor = cool::compose{[](out_of_limits) { return false; }, [](in_use) { return false; },
222 [&](on_sale& status) {
223 if (v > status.min_value && v > status.highest_bid) {
224 if (status.highest_bidder == no_owner)
225 bids.emplace_back(s.downcast<R>(), t);
226 status.highest_bidder = id;
227 status.highest_bid = v;
228 }
229 return true;
230 }};
231 return std::visit(visitor, book(s, t).current);
232 };
233
234 auto access = public_access(id);
235 agents.at(id).bid_phase(t0, bid_fn(bid), permit_public_status_fn(access), rnd());
236 }
237
238 // Trading
239 if (bids.size() > 0) {
240 const auto first_active = agents.active().front();
241 for (const auto& [s, t] : bids) {
242 const auto status = std::get<permit_private_status::on_sale>(book(s, t).current);
243 if (opts.trade_callback)
244 opts.trade_callback({t0, status.owner, status.highest_bidder, s, t, status.highest_bid});
245
246 agents.at(status.highest_bidder).on_bought(s, t, status.highest_bid);
247 if (status.owner != no_owner && status.owner >= first_active)
248 agents.at(status.owner).on_sold(s, t, status.highest_bid);
249
250 auto& pstatus = book(s, t);
251 pstatus.current = permit_private_status::in_use{status.highest_bidder};
252 pstatus.history.push_back({status.min_value, status.highest_bid});
253 }
254 }
255 }
256
257 // Ask phase
258 {
259 std::vector<std::tuple<R, uint_t, uint_t, value_t>> asks;
260 for (const auto id : agents.active()) {
261 auto ask = [&](region_view s, uint_t t, value_t v) -> bool {
262 if (t < t0)
263 return false;
264 using namespace permit_private_status;
265 const auto visitor = cool::compose{[](out_of_limits) { return false; },
266 [&](on_sale status) {
267 if (status.owner != id)
268 return false;
269 asks.emplace_back(s.downcast<R>(), t, id, v);
270 return true;
271 },
272 [&](in_use& status) {
273 if (status.owner != id)
274 return false;
275 asks.emplace_back(s.downcast<R>(), t, id, v);
276 return true;
277 }};
278 return std::visit(visitor, book(s, t).current);
279 };
280
281 auto access = public_access(id);
282 agents.at(id).ask_phase(t0, ask_fn(ask), permit_public_status_fn(access), rnd());
283 }
284
285 for (const auto& [s, t, id, v] : asks)
286 book(s, t).current = permit_private_status::on_sale{.owner = id, .min_value = v};
287 }
288
289 // Stop condition
290 keep_active.clear();
291 keep_active.reserve(agents.active_count());
292 for (const auto id : agents.active())
293 if (!agents.at(id).stop(t0, rnd()))
294 keep_active.push_back(id);
295 agents.update_active(std::move(keep_active));
296
297 if (data.size() > 0)
298 data.pop_front();
299 ++t0;
300 } while (!stop());
301}
302
303} // namespace uat
304
305#endif // UAT_SIMULATION_HPP
Defines the agent class and related types.
type_safe::function_ref< bool(region_view, uint_t, value_t)> bid_fn
Function reference that allows the agent to bid for a permit.
Definition agent.hpp:52
type_safe::function_ref< bool(region_view, uint_t, value_t)> ask_fn
Function reference that allows the agent to ask for a permit.
Definition agent.hpp:55
type_safe::function_ref< permit_public_status_t(region_view, uint_t)> permit_public_status_fn
Function reference that returns the public status of a permit.
Definition agent.hpp:58
std::variant< permit_public_status::unavailable, permit_public_status::available, permit_public_status::owned > permit_public_status_t
Variant that represents the possible public status of a permit.
Definition agent.hpp:49
Private status of the collection of agents in the simulation.
Definition simulation.hpp:93
auto status(id_t) const -> agent_private_status_t
Get the private status of an agent with the given id.
auto active_count() const -> uint_t
Get the number of active agents.
auto active() const -> std::span< const id_t >
Get the ids of the active agents.
A type-erased class that represents an agent in the simulation.
Definition agent.hpp:149
A non-owning wrapper to an atomic region in the airspace.
Definition permit.hpp:21
Concept for types that are compatible as regions.
Definition type.hpp:26
std::variant< stop_criterion::no_agents_t, stop_criterion::time_threshold_t > stop_criterion_t
Variant that represents the possible stop criteria for the simulation.
Definition simulation.hpp:133
auto simulate(const simulation_opts_t< R > &opts={}) -> void
Definition simulation.hpp:151
std::function< void(trade_info_t< R >)> trade_callback_t
Callback type that receives information about a trade transaction.
Definition simulation.hpp:113
constexpr auto no_owner
Unique value to represent the absence of an owner.
Definition simulation.hpp:34
std::function< std::vector< any_agent >(uint_t, int)> factory_t
A function type that generates agents for each iteration.
Definition simulation.hpp:20
std::function< void(uint_t, const agents_private_status_t &, permit_private_status_fn)> simulation_callback_t
Callback type that receives information about the status of the simulation.
Definition simulation.hpp:116
type_safe::function_ref< permit_private_status_t(region_view, uint_t)> permit_private_status_fn
Function reference that allows the simulation to access the private status of an agent.
Definition simulation.hpp:110
std::variant< agent_private_status::inactive, agent_private_status::active > agent_private_status_t
Variant that represents the private status of an agent.
Definition simulation.hpp:89
Represents the private status of an agent that is active in the simulation.
Definition simulation.hpp:81
Represents the private status of an agent that is inactive in the simulation.
Definition simulation.hpp:75
Represents the private status of a permit that is not available for trading.
Definition simulation.hpp:50
Represents the private status of a permit that is available for trading.
Definition simulation.hpp:41
uint_t highest_bidder
The current highest bidder.
Definition simulation.hpp:44
value_t min_value
The minimum value (exclusive) that the owner is willing to sell the permit.
Definition simulation.hpp:43
uint_t owner
The owner of the permit.
Definition simulation.hpp:42
value_t highest_bid
The current highest bid.
Definition simulation.hpp:45
Represents the private status of a permit that is out of limits (past and future).
Definition simulation.hpp:56
Represents the private status of a permit.
Definition simulation.hpp:62
std::variant< permit_private_status::on_sale, permit_private_status::in_use, permit_private_status::out_of_limits > current
The current status of the permit.
Definition simulation.hpp:64
std::vector< trade_value_t > history
The history of trades involving the permit.
Definition simulation.hpp:67
A tuple containing a region and a time step.
Definition permit.hpp:50
Options to configure the simulation.
Definition simulation.hpp:137
simulation_callback_t simulation_callback
Callback to receive information about the status of the simulation.
Definition simulation.hpp:142
stop_criterion_t stop_criterion
The criterion to stop the simulation.
Definition simulation.hpp:140
std::optional< uint_t > time_window
Maximum time ahead a permit can be traded.
Definition simulation.hpp:139
std::optional< uint_t > seed
Random seed.
Definition simulation.hpp:143
trade_callback_t< R > trade_callback
Callback to receive information about a trade transaction.
Definition simulation.hpp:141
factory_t factory
Generator of agents for each iteration.
Definition simulation.hpp:138
Type to represent the information in a trade transaction.
Definition simulation.hpp:24
std::size_t uint_t
Default unsigned integer type.
Definition type.hpp:29
std::size_t id_t
Default type for identifier.
Definition type.hpp:32
double value_t
Default type for price.
Definition type.hpp:35