fts_solver/types/demand/
point.rs

1use std::cmp::Ordering;
2
3/// A demand curve is defined by its points, which in turn have an associated `quantity` and `price`
4#[derive(Clone, Debug, PartialEq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Point {
7    /// The quantity associated to the point (typically the dependent variable)
8    pub quantity: f64,
9    /// The price associated to the point (typically the independent variable)
10    pub price: f64,
11}
12
13impl Point {
14    /// Is this point collinear with the other two?
15    pub fn is_collinear(&self, lhs: &Self, rhs: &Self) -> bool {
16        let &Point {
17            quantity: x0,
18            price: y0,
19        } = lhs;
20        let &Point {
21            quantity: x1,
22            price: y1,
23        } = self;
24        let &Point {
25            quantity: x2,
26            price: y2,
27        } = rhs;
28
29        (x2 - x0) * (y1 - y0) == (x1 - x0) * (y2 - y0)
30    }
31}
32
33// We define a partial ordering for point so that demand curve validation is:
34// All consecutive pairs of points satisfy pt0.partial_cmp(&pt1).is_le()
35impl PartialOrd for Point {
36    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
37        match (
38            self.quantity.partial_cmp(&other.quantity),
39            self.price.partial_cmp(&other.price),
40        ) {
41            (Some(Ordering::Less), Some(price)) => {
42                if price.is_ge() {
43                    Some(Ordering::Less)
44                } else {
45                    None
46                }
47            }
48            (Some(Ordering::Greater), Some(price)) => {
49                if price.is_le() {
50                    Some(Ordering::Greater)
51                } else {
52                    None
53                }
54            }
55            (Some(Ordering::Equal), Some(price)) => Some(price.reverse()),
56            (None, _) | (_, None) => None,
57        }
58    }
59}