@@ -3,7 +3,7 @@ use chrono::{Duration, NaiveDate};
3
3
use num:: rational:: BigRational ;
4
4
use num:: BigInt ;
5
5
use std:: cmp:: Ordering ;
6
- use std:: collections:: HashMap ;
6
+ use std:: collections:: { HashMap , HashSet } ;
7
7
use std:: fmt;
8
8
use std:: fmt:: { Display , Formatter } ;
9
9
use std:: rc:: Rc ;
@@ -62,26 +62,38 @@ pub fn conversion(
62
62
63
63
// Initialize distances
64
64
for node in graph. nodes . iter ( ) {
65
+ // println!("{} {} ", node.currency.get_name(), node.date);
65
66
if node. currency == currency {
66
67
distances. insert ( node. clone ( ) , Some ( date - node. date ) ) ;
68
+ // distances.insert(node.clone(), Some(date - date));
69
+ // println!("{}", date - node.date);
67
70
} else {
68
71
distances. insert ( node. clone ( ) , None ) ;
72
+ // println!("None");
69
73
}
70
74
queue. push ( node. clone ( ) ) ;
71
75
}
72
76
while !queue. is_empty ( ) {
77
+ // Sort largest to smallest
73
78
queue. sort_by ( |a, b| cmp ( distances. get ( b) . unwrap ( ) , distances. get ( a) . unwrap ( ) ) ) ;
74
- let v = queue. pop ( ) . unwrap ( ) ;
75
79
80
+ // Take the closest node
81
+ let v = queue. pop ( ) . unwrap ( ) ;
82
+ // This means there is no path to the node
76
83
if distances. get ( v. as_ref ( ) ) . unwrap ( ) . is_none ( ) {
77
84
break ;
78
85
}
86
+
87
+ // The path from the starting currency to the node
79
88
let current_path = if let Some ( path) = paths. get ( v. as_ref ( ) ) {
80
89
path. clone ( )
81
90
} else {
82
91
Vec :: new ( )
83
92
} ;
93
+
94
+ // Update the distances
84
95
for ( u, e) in graph. get_neighbours ( v. as_ref ( ) ) . iter ( ) {
96
+ // println!("Neighbour: {} {}", u.currency.get_name(), u.date);
85
97
let alt = distances. get ( v. as_ref ( ) ) . unwrap ( ) . unwrap ( ) + e. length ( ) ;
86
98
let distance = distances. get ( u. as_ref ( ) ) . unwrap ( ) ;
87
99
let mut update = distance. is_none ( ) ;
@@ -97,18 +109,36 @@ pub fn conversion(
97
109
paths. insert ( u. clone ( ) , u_path) ;
98
110
}
99
111
}
112
+
100
113
// Return not the paths but the multipliers
101
114
let mut multipliers = HashMap :: new ( ) ;
115
+ let mut inserted = HashMap :: new ( ) ;
102
116
for ( k, v) in paths. iter ( ) {
117
+ // println!("{} {} ~{:?}", k.currency.get_name(), k.date, v.len());
103
118
let mut mult = BigRational :: new ( BigInt :: from ( 1 ) , BigInt :: from ( 1 ) ) ;
104
119
let mut currency = k. currency . clone ( ) ;
120
+ match inserted. get ( & k. currency ) {
121
+ Some ( x) => {
122
+ if * x > k. date {
123
+ continue ;
124
+ }
125
+ }
126
+ None => {
127
+ inserted. insert ( currency. clone ( ) , k. date ) ;
128
+ }
129
+ }
105
130
for edge in v. iter ( ) . rev ( ) {
106
- if currency == edge. from . currency {
107
- mult *= edge. price . get_price ( ) . get_amount ( ) ;
108
- currency = edge. to . currency . clone ( ) ;
109
- } else {
110
- mult /= edge. price . get_price ( ) . get_amount ( ) ;
111
- currency = edge. from . currency . clone ( ) ;
131
+ match edge. as_ref ( ) . price . as_ref ( ) {
132
+ None => ( ) , // do nothing, multiply by one and keep the same currency
133
+ Some ( price) => {
134
+ if currency == edge. from . currency {
135
+ mult *= price. get_price ( ) . get_amount ( ) ;
136
+ currency = edge. to . currency . clone ( ) ;
137
+ } else {
138
+ mult /= price. get_price ( ) . get_amount ( ) ;
139
+ currency = edge. from . currency . clone ( ) ;
140
+ }
141
+ }
112
142
}
113
143
}
114
144
multipliers. insert ( k. currency . clone ( ) , mult) ;
@@ -124,7 +154,7 @@ pub struct Node {
124
154
125
155
#[ derive( Debug , Clone ) ]
126
156
pub struct Edge {
127
- price : Price ,
157
+ price : Option < Price > ,
128
158
from : Rc < Node > ,
129
159
to : Rc < Node > ,
130
160
}
@@ -150,8 +180,8 @@ impl Graph {
150
180
fn from_prices ( prices : & Vec < Price > , source : Node ) -> Self {
151
181
let mut nodes = HashMap :: new ( ) ;
152
182
let mut edges = Vec :: new ( ) ;
153
- let mut currency_dates = HashMap :: new ( ) ;
154
- currency_dates. insert ( source. currency . clone ( ) , source. date ) ;
183
+ let mut currency_dates = HashSet :: new ( ) ;
184
+ currency_dates. insert ( ( source. currency . clone ( ) , source. date ) ) ;
155
185
// Remove redundant prices and create the nodes
156
186
let mut prices_nodup = HashMap :: new ( ) ;
157
187
for p in prices. iter ( ) {
@@ -174,44 +204,63 @@ impl Graph {
174
204
}
175
205
}
176
206
}
207
+ }
208
+ for ( _, p) in prices_nodup. iter ( ) {
209
+ let commodities =
210
+ if p. price . get_commodity ( ) . unwrap ( ) . get_name ( ) < p. commodity . as_ref ( ) . get_name ( ) {
211
+ ( p. price . get_commodity ( ) . unwrap ( ) , p. commodity . clone ( ) )
212
+ } else {
213
+ ( p. commodity . clone ( ) , p. price . get_commodity ( ) . unwrap ( ) )
214
+ } ;
177
215
let c_vec = vec ! [ commodities. 0 . clone( ) , commodities. 1 . clone( ) ] ;
178
216
for c in c_vec {
179
- match currency_dates. get ( c. as_ref ( ) ) {
180
- Some ( v) => {
181
- if v < & p. date {
182
- currency_dates. insert ( c. clone ( ) , p. date ) ;
183
- }
184
- }
185
- None => {
186
- currency_dates. insert ( c. clone ( ) , p. date ) ;
187
- }
188
- }
217
+ currency_dates. insert ( ( c. clone ( ) , p. date ) ) ;
189
218
}
190
219
}
191
-
192
220
// Create the nodes
193
221
for ( c, d) in currency_dates. iter ( ) {
194
222
nodes. insert (
195
- c. clone ( ) ,
223
+ ( c. clone ( ) , d . clone ( ) ) ,
196
224
Rc :: new ( Node {
197
225
currency : c. clone ( ) ,
198
226
date : d. clone ( ) ,
199
227
} ) ,
200
228
) ;
201
229
}
230
+ // Edges from the prices
202
231
for ( _, p) in prices_nodup. iter ( ) {
203
- let from = nodes. get ( p. commodity . as_ref ( ) ) . unwrap ( ) . clone ( ) ;
232
+ let from = nodes
233
+ . get ( & ( p. commodity . clone ( ) , p. date . clone ( ) ) )
234
+ . unwrap ( )
235
+ . clone ( ) ;
204
236
let to = nodes
205
- . get ( p. price . get_commodity ( ) . unwrap ( ) . as_ref ( ) )
237
+ . get ( & ( p. price . get_commodity ( ) . unwrap ( ) , p . date . clone ( ) ) )
206
238
. unwrap ( )
207
239
. clone ( ) ;
208
240
edges. push ( Rc :: new ( Edge {
209
- price : p. clone ( ) ,
241
+ price : Some ( p. clone ( ) ) ,
210
242
from : from. clone ( ) ,
211
243
to : to. clone ( ) ,
212
244
} ) ) ;
213
245
}
214
246
247
+ // println!("Nodes: {}", nodes.len());
248
+ // println!("Edges: {}", edges.len());
249
+ let vec_node: Vec < Rc < Node > > = nodes. iter ( ) . map ( |x| x. 1 . clone ( ) ) . collect ( ) ;
250
+ let n = vec_node. len ( ) ;
251
+ for i in 0 ..n {
252
+ for j in i..n {
253
+ if vec_node[ i] . currency == vec_node[ j] . currency {
254
+ edges. push ( Rc :: new ( Edge {
255
+ price : None ,
256
+ from : vec_node[ i] . clone ( ) ,
257
+ to : vec_node[ j] . clone ( ) ,
258
+ } ) )
259
+ }
260
+ }
261
+ }
262
+ // println!("Edges: {}", edges.len());
263
+
215
264
Graph {
216
265
nodes : nodes. iter ( ) . map ( |x| x. 1 . clone ( ) ) . collect ( ) ,
217
266
edges,
@@ -263,7 +312,7 @@ mod tests {
263
312
#[ test]
264
313
fn test_graph ( ) {
265
314
// Copy from balance command
266
- let path = PathBuf :: from ( "examples /demo.ledger" ) ;
315
+ let path = PathBuf :: from ( "tests/example_files /demo.ledger" ) ;
267
316
let mut tokenizer = Tokenizer :: from ( & path) ;
268
317
let items = tokenizer. tokenize ( ) . unwrap ( ) ;
269
318
let ledger = items. to_ledger ( false ) . unwrap ( ) ;
0 commit comments