dexterior_core/
cochain.rs

1//! Cochains, i.e. values assigned to elements of a mesh.
2
3use nalgebra as na;
4
5use crate::mesh::SubsetImpl;
6
7/// A vector of values corresponding to
8/// a set of `k`-dimensional cells on a mesh.
9///
10/// Cochains can be constructed using the following methods
11/// on [`SimplicialMesh`][crate::SimplicialMesh]:
12/// - [`new_zero_cochain`][crate::SimplicialMesh::new_zero_cochain]
13pub type Cochain<const DIM: usize, Primality> = CochainImpl<na::Const<DIM>, Primality>;
14
15/// The cochain type used internally by Dexterior.
16///
17/// This type cannot use const generics because they cannot currently
18/// do the compile-time generic arithmetic needed for operators.
19/// Thus, the more convenient alias [`Cochain`][self::Cochain]
20/// is preferred for public APIs.
21#[derive(Clone)]
22pub struct CochainImpl<Dimension, Primality> {
23    /// The underlying vector of real values, exposed for convenience.
24    ///
25    /// Note that changing the dimension of this vector at runtime
26    /// will cause a dimension mismatch with operators,
27    /// leading to a panic when an operator is applied.
28    /// Use with caution.
29    pub values: na::DVector<f64>,
30    _marker: std::marker::PhantomData<(Dimension, Primality)>,
31}
32
33impl<Dimension, Primality> CochainImpl<Dimension, Primality> {
34    // constructors only exposed to crate
35    // because cochains are always based on a mesh
36    // and it doesn't make sense for a user to create them directly;
37    // public constructors are methods on SimplicialMesh
38
39    #[inline]
40    pub(crate) fn from_values(values: na::DVector<f64>) -> Self {
41        Self {
42            values,
43            _marker: std::marker::PhantomData,
44        }
45    }
46
47    #[inline]
48    pub(crate) fn zeros(len: usize) -> Self {
49        Self::from_values(na::DVector::zeros(len))
50    }
51
52    /// Linearly interpolate along the line from `self` to `end`.
53    pub fn lerp(&self, end: &Self, t: f64) -> Self {
54        self + &(t * (end - self))
55    }
56
57    /// Replace a subset of this cochain's values with those of another cochain.
58    pub fn overwrite(&mut self, subset: &SubsetImpl<Dimension, Primality>, other: &Self) {
59        for i in subset.indices.ones() {
60            self.values[i] = other.values[i];
61        }
62    }
63}
64
65impl<Dimension, Primality> crate::operator::Operand for CochainImpl<Dimension, Primality> {
66    type Dimension = Dimension;
67    type Primality = Primality;
68
69    fn values(&self) -> &na::DVector<f64> {
70        &self.values
71    }
72
73    fn from_values(values: na::DVector<f64>) -> Self {
74        Self {
75            values,
76            _marker: std::marker::PhantomData,
77        }
78    }
79}
80
81// std trait impls for math ops and such
82// (several permutations needed to also work with references.
83// maybe this could be shortened with macros,
84// but I can't be bothered)
85
86impl<D, P> std::fmt::Debug for CochainImpl<D, P>
87where
88    D: na::DimName,
89{
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}-cochain, values {:?}", D::USIZE, self.values)
92    }
93}
94
95impl<D, P> PartialEq for CochainImpl<D, P> {
96    fn eq(&self, other: &Self) -> bool {
97        self.values == other.values
98    }
99}
100
101// Index with SimplexViews
102
103impl<'a, D, const MESH_DIM: usize> std::ops::Index<crate::SimplexView<'a, D, MESH_DIM>>
104    for CochainImpl<D, crate::Primal>
105where
106    D: na::DimName,
107    na::Const<MESH_DIM>: na::DimNameSub<D>,
108{
109    type Output = f64;
110
111    fn index(&self, simplex: crate::SimplexView<'a, D, MESH_DIM>) -> &Self::Output {
112        &self.values[simplex.index()]
113    }
114}
115
116impl<'a, D, const MESH_DIM: usize> std::ops::IndexMut<crate::SimplexView<'a, D, MESH_DIM>>
117    for CochainImpl<D, crate::Primal>
118where
119    D: na::DimName,
120    na::Const<MESH_DIM>: na::DimNameSub<D>,
121{
122    fn index_mut(&mut self, simplex: crate::SimplexView<'a, D, MESH_DIM>) -> &mut Self::Output {
123        &mut self.values[simplex.index()]
124    }
125}
126
127impl<'a, D, const MESH_DIM: usize> std::ops::Index<crate::DualCellView<'a, D, MESH_DIM>>
128    for CochainImpl<D, crate::Dual>
129where
130    D: na::DimName,
131    na::Const<MESH_DIM>: na::DimNameSub<D>,
132{
133    type Output = f64;
134
135    fn index(&self, simplex: crate::DualCellView<'a, D, MESH_DIM>) -> &Self::Output {
136        &self.values[simplex.index()]
137    }
138}
139
140impl<'a, D, const MESH_DIM: usize> std::ops::IndexMut<crate::DualCellView<'a, D, MESH_DIM>>
141    for CochainImpl<D, crate::Dual>
142where
143    D: na::DimName,
144    na::Const<MESH_DIM>: na::DimNameSub<D>,
145{
146    fn index_mut(&mut self, simplex: crate::DualCellView<'a, D, MESH_DIM>) -> &mut Self::Output {
147        &mut self.values[simplex.index()]
148    }
149}
150
151// Add
152
153impl<D, P> std::ops::Add for CochainImpl<D, P> {
154    type Output = Self;
155
156    fn add(self, rhs: Self) -> Self::Output {
157        CochainImpl::from_values(self.values + rhs.values)
158    }
159}
160
161impl<D, P> std::ops::Add<&CochainImpl<D, P>> for CochainImpl<D, P> {
162    type Output = Self;
163
164    fn add(self, rhs: &CochainImpl<D, P>) -> Self::Output {
165        CochainImpl::from_values(self.values + &rhs.values)
166    }
167}
168
169impl<D, P> std::ops::Add<CochainImpl<D, P>> for &CochainImpl<D, P> {
170    type Output = CochainImpl<D, P>;
171
172    fn add(self, rhs: CochainImpl<D, P>) -> Self::Output {
173        CochainImpl::from_values(&self.values + rhs.values)
174    }
175}
176
177impl<D, P> std::ops::Add for &CochainImpl<D, P> {
178    type Output = CochainImpl<D, P>;
179
180    fn add(self, rhs: Self) -> Self::Output {
181        CochainImpl::from_values(&self.values + &rhs.values)
182    }
183}
184
185// AddAssign
186
187impl<D, P> std::ops::AddAssign for CochainImpl<D, P> {
188    fn add_assign(&mut self, rhs: Self) {
189        self.values += rhs.values;
190    }
191}
192
193impl<D, P> std::ops::AddAssign<&CochainImpl<D, P>> for CochainImpl<D, P> {
194    fn add_assign(&mut self, rhs: &CochainImpl<D, P>) {
195        self.values += &rhs.values;
196    }
197}
198
199// Neg
200
201impl<D, P> std::ops::Neg for CochainImpl<D, P> {
202    type Output = Self;
203
204    fn neg(self) -> Self::Output {
205        Self::from_values(-self.values)
206    }
207}
208
209impl<D, P> std::ops::Neg for &CochainImpl<D, P> {
210    type Output = CochainImpl<D, P>;
211
212    fn neg(self) -> Self::Output {
213        CochainImpl::from_values(-&self.values)
214    }
215}
216
217// Sub
218
219impl<D, P> std::ops::Sub for CochainImpl<D, P> {
220    type Output = Self;
221
222    fn sub(self, rhs: Self) -> Self::Output {
223        Self::from_values(self.values - rhs.values)
224    }
225}
226
227impl<D, P> std::ops::Sub<&CochainImpl<D, P>> for CochainImpl<D, P> {
228    type Output = Self;
229
230    fn sub(self, rhs: &CochainImpl<D, P>) -> Self::Output {
231        CochainImpl::from_values(&self.values - &rhs.values)
232    }
233}
234
235impl<D, P> std::ops::Sub<CochainImpl<D, P>> for &CochainImpl<D, P> {
236    type Output = CochainImpl<D, P>;
237
238    fn sub(self, rhs: CochainImpl<D, P>) -> Self::Output {
239        CochainImpl::from_values(&self.values - &rhs.values)
240    }
241}
242
243impl<D, P> std::ops::Sub for &CochainImpl<D, P> {
244    type Output = CochainImpl<D, P>;
245
246    fn sub(self, rhs: Self) -> Self::Output {
247        CochainImpl::from_values(&self.values - &rhs.values)
248    }
249}
250
251// SubAssign
252
253impl<D, P> std::ops::SubAssign for CochainImpl<D, P> {
254    fn sub_assign(&mut self, rhs: Self) {
255        self.values -= rhs.values;
256    }
257}
258
259impl<D, P> std::ops::SubAssign<&CochainImpl<D, P>> for CochainImpl<D, P> {
260    fn sub_assign(&mut self, rhs: &CochainImpl<D, P>) {
261        self.values -= &rhs.values;
262    }
263}
264
265// Mul (scalar)
266
267impl<D, P> std::ops::Mul<CochainImpl<D, P>> for f64 {
268    type Output = CochainImpl<D, P>;
269
270    fn mul(self, rhs: CochainImpl<D, P>) -> Self::Output {
271        CochainImpl::from_values(self * rhs.values)
272    }
273}
274
275impl<D, P> std::ops::Mul<&CochainImpl<D, P>> for f64 {
276    type Output = CochainImpl<D, P>;
277
278    fn mul(self, rhs: &CochainImpl<D, P>) -> Self::Output {
279        CochainImpl::from_values(self * &rhs.values)
280    }
281}