Skip to content

Commit 62cd093

Browse files
committed
Added a foreign exchange market example to showcase graph::hasNegativeCycle().
1 parent c4eff08 commit 62cd093

File tree

2 files changed

+128
-73
lines changed

2 files changed

+128
-73
lines changed

README.md

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,95 @@
11
# Compile Time Graph Library ![Travis Status](https://travis-ci.org/Mandrenkov/Compile-Time-Graph-Library.svg?branch=master)
2-
The Compile Time Graph Library (CTGL) is a C++ header-only library that implements `constexpr` graph algorithms and data structures. Simply include `ctgl.h` and you're set!
2+
The *Compile Time Graph Library* (CTGL) is a C++ header-only library that implements `constexpr` graph algorithms.
3+
4+
## Setup
5+
To integrate CTGL with your project, add the files in the [header](src/h) directory to your include path. Then, include [`ctgl.h`](src/h/ctgl.h) in the source files of your choice!
6+
7+
**Note:** This library uses C++17 features.
38

49
## Examples
510
The first example finds the shortest distance between two nodes in a graph.
611
```C++
7-
// Create Nodes with IDs 1, 2, and 3.
12+
// The nodes of a CTGL graph are ctgl::Node<> types with unique ID parameters.
813
using n1 = ctgl::Node<1>;
914
using n2 = ctgl::Node<2>;
1015
using n3 = ctgl::Node<3>;
1116
using nodes = ctgl::List<n1, n2, n3>;
1217

13-
// Create Edges that connect some of the Nodes.
14-
// (1) --4--> (2) --4--> (3)
15-
// `----------9----------^
18+
// The directed, weighted edges of a CTGL graph are ctgl::Edge<> types.
19+
// 1 --(4)--> 2 --(4)--> 3
20+
// '---------(9)---------^
1621
using e12 = ctgl::Edge<n1, n2, 4>;
1722
using e13 = ctgl::Edge<n1, n3, 9>;
1823
using e23 = ctgl::Edge<n2, n3, 4>;
1924
using edges = ctgl::List<e12, e13, e23>;
2025

21-
// Compose the Nodes and Edges to form a Graph.
26+
// By definition, a Graph is a composition of Nodes and Edges.
2227
using graph = ctgl::Graph<nodes, edges>;
2328

24-
// Find the distance between Node 1 and Node 3 (i.e., 8).
25-
constexpr int dist = ctgl::algorithm::findDistance(graph{}, n1{}, n3{});
29+
// |distance| represents the (shortest) distance between Node 1 and Node 3.
30+
// In this case, the value of |distance| will be 8.
31+
constexpr int distance = ctgl::algorithm::findDistance(graph{}, n1{}, n3{});
2632
```
2733

28-
The second example solves the [TSP](https://en.wikipedia.org/wiki/Travelling_salesman_problem) in O(1) running time.
34+
The second example solves the [Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) in O(1) running time.
2935
```C++
30-
// Create Nodes with IDs 1, 2, 3, and 4.
31-
using n1 = ctgl::Node<1>;
32-
using n2 = ctgl::Node<2>;
33-
using n3 = ctgl::Node<3>;
34-
using n4 = ctgl::Node<4>;
35-
using nodes = ctgl::List<n1, n2, n3, n4>;
36+
// Nodes represent cities in the TSP instance.
37+
using dubai = ctgl::Node<1>;
38+
using miami = ctgl::Node<2>;
39+
using paris = ctgl::Node<3>;
40+
using tokyo = ctgl::Node<4>;
41+
using cities = ctgl::List<dubai, miami, paris, tokyo>;
3642

37-
// Create Edges that form multiple circuits across the Nodes.
38-
// .----------1----------v
39-
// (1) --1--> (2) --2--> (3) --1--> (4) --.
40-
// ^ ^---------3---------' ^---4-----' |
41-
// '----------------3---------------------'
42-
using e12 = ctgl::Edge<n1, n2, 1>;
43-
using e23 = ctgl::Edge<n2, n3, 2>;
44-
using e24 = ctgl::Edge<n2, n4, 1>;
45-
using e31 = ctgl::Edge<n3, n1, 3>;
46-
using e34 = ctgl::Edge<n3, n4, 1>;
47-
using e41 = ctgl::Edge<n4, n1, 3>;
48-
using e43 = ctgl::Edge<n4, n3, 4>;
49-
using edges = ctgl::List<e12, e23, e24, e31, e34, e41, e43>;
43+
// Edges represent unidirectional routes between cities.
44+
// .-------------(1)-------------v
45+
// Dubai --(1)--> Miami --(2)--> Paris --(1)--> Tokyo
46+
// ^ ^-----------(3)-----------' ^---(4)----' |
47+
// '----------------------(3)-----------------------'
48+
using routes = ctgl::List<ctgl::Edge<dubai, miami, 1>,
49+
ctgl::Edge<miami, paris, 2>,
50+
ctgl::Edge<miami, tokyo, 1>,
51+
ctgl::Edge<paris, dubai, 3>,
52+
ctgl::Edge<paris, tokyo, 1>,
53+
ctgl::Edge<tokyo, dubai, 3>,
54+
ctgl::Edge<tokyo, paris, 4>>;
5055

51-
// Compose the Nodes and Edges to form a Graph.
52-
using graph = ctgl::Graph<nodes, edges>;
56+
// |circuit| represents an optimal solution to the TSP instance from Dubai.
57+
// The type of |circuit| will express Dubai --> Miami --> Paris --> Tokyo --> Dubai.
58+
using world = ctgl::Graph<cities, routes>;
59+
constexpr auto circuit = ctgl::algorithm::findShortestRoute(world{}, dubai{}, cities{});
60+
```
61+
62+
The third example detects opportunities for arbitrage in a foreign exchange market.
63+
```C++
64+
// Nodes represent currencies in the foreign exchange market.
65+
using aud = ctgl::Node<1>;
66+
using cad = ctgl::Node<2>;
67+
using nzd = ctgl::Node<3>;
68+
using usd = ctgl::Node<4>;
69+
using currencies = ctgl::List<aud, cad, nzd, usd>;
70+
71+
// Edges represent logarithmic exchange rates between currencies. Why? If the
72+
// product of the exchange rates along a cycle is less than one, then the sum
73+
// of the logarithmic exchanges rates along that cycle must be less than zero.
74+
// v----------(-2)----------.
75+
// NZD --(1)--> AUD --(-3)--> CAD --(3)--> USD
76+
using log_rates = ctgl::List<ctgl::Edge<nzd, aud, 1>,
77+
ctgl::Edge<aud, cad, -3>,
78+
ctgl::Edge<cad, usd, 3>,
79+
ctgl::Edge<usd, aud, -2>>;
5380

54-
// Find an optimal solution to the TSP.
55-
constexpr auto tsp = ctgl::algorithm::findShortestRoute(graph{}, n1{}, nodes{});
81+
// |arbitrage| represents the possibility of arbitrage in the currency market.
82+
// Here, |arbitrage| will be set to true because AUD --> CAD --> USD --> AUD
83+
// forms a negative cycle.
84+
using market = ctgl::Graph<currencies, log_rates>;
85+
constexpr bool arbitrage = ctgl::graph::hasNegativeCycle(market{});
5686
```
5787

58-
## Build Instructions
59-
| Command | Objective |
60-
|--- |--- |
61-
| `make all` | Build the CTGL and run the examples. |
62-
| `make test` | Build the CTGL and run the test suite. |
63-
| `make clean` | Clean the current directory. |
88+
## Development
89+
| Command | Description |
90+
|--- |--- |
91+
| `make all` | Build and run the CTGL examples. |
92+
| `make test` | Build and run the CTGL test suite. |
93+
| `make clean` | Clean the current directory. |
6494

65-
**Note:** You can specify a compiler flag to any of the build commands to select a different compiler target. For example, to build the test suite using Clang, run `make test COMPILER=clang++`.
95+
You can provide a `COMPILER` or `FLAGS` argument to any of the build commands to select a different compiler or add custom flags to a compiler invocation. For example, to build the test suite using Clang, use `make test COMPILER=clang++`.

src/cpp/ctgl.cpp

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,82 @@ int main() {
88
{
99
// Example 1
1010
// -------------------------------------------------------------------------
11-
// Create Nodes with IDs 1, 2, and 3.
11+
// The nodes of a CTGL graph are ctgl::Node<> types with unique ID parameters.
1212
using n1 = ctgl::Node<1>;
1313
using n2 = ctgl::Node<2>;
1414
using n3 = ctgl::Node<3>;
1515
using nodes = ctgl::List<n1, n2, n3>;
1616

17-
// Create Edges that connect some of the Nodes.
18-
// (1) --4--> (2) --4--> (3)
19-
// `----------9----------^
17+
// The directed, weighted edges of a CTGL graph are ctgl::Edge<> types.
18+
// 1 --(4)--> 2 --(4)--> 3
19+
// '---------(9)---------^
2020
using e12 = ctgl::Edge<n1, n2, 4>;
2121
using e13 = ctgl::Edge<n1, n3, 9>;
2222
using e23 = ctgl::Edge<n2, n3, 4>;
2323
using edges = ctgl::List<e12, e13, e23>;
2424

25-
// Compose the Nodes and Edges to form a Graph.
25+
// By definition, a Graph is a composition of Nodes and Edges.
2626
using graph = ctgl::Graph<nodes, edges>;
2727

28-
// Find the distance between Node 1 and Node 3 (i.e., 8).
29-
constexpr int dist = ctgl::algorithm::findDistance(graph{}, n1{}, n3{});
30-
std::cout << "The distance between Node 1 and Node 3 is " << dist << ".\n";
31-
} {
28+
// |distance| represents the (shortest) distance between Node 1 and Node 3.
29+
// In this case, the value of |distance| will be 8.
30+
constexpr int distance = ctgl::algorithm::findDistance(graph{}, n1{}, n3{});
31+
std::cout << "The distance between Node 1 and Node 3 is " << distance << ".\n";
32+
}{
3233
// Example 2
3334
// -------------------------------------------------------------------------
34-
// Create Nodes with IDs 1, 2, 3, and 4.
35-
using n1 = ctgl::Node<1>;
36-
using n2 = ctgl::Node<2>;
37-
using n3 = ctgl::Node<3>;
38-
using n4 = ctgl::Node<4>;
39-
using nodes = ctgl::List<n1, n2, n3, n4>;
40-
41-
// Create Edges that form multiple circuits across the Nodes.
42-
// .----------1----------v
43-
// (1) --1--> (2) --2--> (3) --1--> (4) --.
44-
// ^ ^---------3---------' ^---4-----' |
45-
// '----------------3---------------------'
46-
using e12 = ctgl::Edge<n1, n2, 1>;
47-
using e23 = ctgl::Edge<n2, n3, 2>;
48-
using e24 = ctgl::Edge<n2, n4, 1>;
49-
using e31 = ctgl::Edge<n3, n1, 3>;
50-
using e34 = ctgl::Edge<n3, n4, 1>;
51-
using e41 = ctgl::Edge<n4, n1, 3>;
52-
using e43 = ctgl::Edge<n4, n3, 4>;
53-
using edges = ctgl::List<e12, e23, e24, e31, e34, e41, e43>;
35+
// Nodes represent cities in the TSP instance.
36+
using dubai = ctgl::Node<1>;
37+
using miami = ctgl::Node<2>;
38+
using paris = ctgl::Node<3>;
39+
using tokyo = ctgl::Node<4>;
40+
using cities = ctgl::List<dubai, miami, paris, tokyo>;
5441

55-
// Compose the Nodes and Edges to form a Graph.
56-
using graph = ctgl::Graph<nodes, edges>;
42+
// Edges represent unidirectional routes between cities.
43+
// .-------------(1)-------------v
44+
// Dubai --(1)--> Miami --(2)--> Paris --(1)--> Tokyo
45+
// ^ ^-----------(3)-----------' ^---(4)----' |
46+
// '----------------------(3)-----------------------'
47+
using routes = ctgl::List<ctgl::Edge<dubai, miami, 1>,
48+
ctgl::Edge<miami, paris, 2>,
49+
ctgl::Edge<miami, tokyo, 1>,
50+
ctgl::Edge<paris, dubai, 3>,
51+
ctgl::Edge<paris, tokyo, 1>,
52+
ctgl::Edge<tokyo, dubai, 3>,
53+
ctgl::Edge<tokyo, paris, 4>>;
5754

58-
// Find the length of the solution to the TSP (i.e., 1 + 2 + 1 + 3 = 7).
59-
constexpr auto route = ctgl::algorithm::findShortestRoute(graph{}, n1{}, nodes{});
60-
constexpr int length = ctgl::path::length(route);
55+
// |circuit| represents an optimal solution to the TSP instance from Dubai.
56+
// The type of |circuit| will express Dubai --> Miami --> Paris --> Tokyo --> Dubai.
57+
using world = ctgl::Graph<cities, routes>;
58+
constexpr auto circuit = ctgl::algorithm::findShortestRoute(world{}, dubai{}, cities{});
59+
constexpr int length = ctgl::path::length(circuit);
6160
std::cout << "The solution to the TSP has length " << length << ".\n";
61+
}{
62+
// Example 3
63+
// -------------------------------------------------------------------------
64+
// Nodes represent currencies in the foreign exchange market.
65+
using aud = ctgl::Node<1>;
66+
using cad = ctgl::Node<2>;
67+
using nzd = ctgl::Node<3>;
68+
using usd = ctgl::Node<4>;
69+
using currencies = ctgl::List<aud, cad, nzd, usd>;
70+
71+
// Edges represent logarithmic exchange rates between currencies. Why? If the
72+
// product of the exchange rates along a cycle is less than one, then the sum
73+
// of the logarithmic exchanges rates along that cycle must be less than zero.
74+
// v----------(-2)----------.
75+
// NZD --(1)--> AUD --(-3)--> CAD --(3)--> USD
76+
using log_rates = ctgl::List<ctgl::Edge<nzd, aud, 1>,
77+
ctgl::Edge<aud, cad, -3>,
78+
ctgl::Edge<cad, usd, 3>,
79+
ctgl::Edge<usd, aud, -2>>;
80+
81+
// |arbitrage| represents the possibility of arbitrage in the currency market.
82+
// Here, |arbitrage| will be set to true because AUD --> CAD --> USD --> AUD
83+
// forms a negative cycle.
84+
using market = ctgl::Graph<currencies, log_rates>;
85+
constexpr bool arbitrage = ctgl::graph::hasNegativeCycle(market{});
86+
std::cout << "The foreign exchange market " << (arbitrage ? "is" : "is not") << " susceptible to arbitrage.\n";
6287
}
6388

6489
std::cout << "\nDone.\n";

0 commit comments

Comments
 (0)