flag_algebra/
algebra.rs

1//! Manipulation of vectors and inequalities in a flag algebra.
2
3use crate::expr::{Expr, Names, VarRange};
4use crate::flag::Flag;
5use crate::operator::*;
6use ndarray::{Array1, ScalarOperand};
7use num::{pow::Pow, FromPrimitive, Integer, Num};
8use sprs::{CsMat, CsMatView, CsVec, MulAcc, TriMat};
9use std::fmt::*;
10use std::ops::*;
11
12/// An element of a flag algebra.
13#[derive(Clone, Debug)]
14pub struct QFlag<N, F: Flag> {
15    /// Basis of the space where the element lives. This corresponds to the size and type of the flags.
16    pub basis: Basis<F>,
17    /// The vector of the element in the corresponding basis is `(1/self.scale).self.data`.
18    pub data: Array1<N>,
19    /// Scaling factor of the vector.
20    pub scale: u64,
21    /// Expression recording how the vector was computed.
22    pub expr: Expr<N, F>,
23}
24
25// equality for QFlags
26impl<N, F> PartialEq for QFlag<N, F>
27where
28    N: Num + FromPrimitive + Clone,
29    F: Flag,
30{
31    fn eq(&self, other: &Self) -> bool {
32        assert_eq!(self.basis, other.basis);
33        assert_eq!(self.data.len(), other.data.len());
34        //
35        let s1 = N::from_u64(self.scale).unwrap();
36        let s2 = N::from_u64(other.scale).unwrap();
37        self.data
38            .iter()
39            .zip(other.data.iter())
40            .all(|(x, y)| x.clone() * s2.clone() == y.clone() * s1.clone())
41    }
42}
43
44// ==================== operarions on Qflags ===========
45
46/// Arithmetic to to put two scaled vectors on same denominator
47///
48/// If `f1 = v1 / scale1` and `f2 = v2 / scale2`, then
49/// `matching_scales(scale1, scale2)` returns `(c1, c2, scale)`
50/// such that  `f1 = v1 * c1 / scale` and `f2 = v2 * c2 / scale`.
51fn matching_scales<N>(scale1: u64, scale2: u64) -> (N, N, u64)
52where
53    N: FromPrimitive,
54{
55    let gcd = scale1.gcd(&scale2);
56    let c1 = N::from_u64(scale2 / gcd).unwrap();
57    let c2 = N::from_u64(scale1 / gcd).unwrap();
58    let scale = (scale1 / gcd) * scale2;
59    (c1, c2, scale)
60}
61
62impl<N, F> Add<&Self> for QFlag<N, F>
63where
64    N: Clone + FromPrimitive + Num + ScalarOperand,
65    F: Flag,
66{
67    type Output = Self;
68
69    fn add(self, other: &Self) -> Self::Output {
70        assert_eq!(self.basis, other.basis);
71        assert_eq!(self.data.len(), other.data.len());
72        let (a1, a2, scale) = matching_scales::<N>(self.scale, other.scale);
73        QFlag {
74            basis: self.basis,
75            data: self.data * a1 + &other.data * a2,
76            scale,
77            expr: self.expr + other.expr.clone(),
78        }
79    }
80}
81
82impl<N, F> Add for QFlag<N, F>
83where
84    N: Clone + Num + FromPrimitive + ScalarOperand,
85    F: Flag,
86{
87    type Output = Self;
88
89    fn add(self, other: Self) -> Self::Output {
90        self + &other
91    }
92}
93
94impl<'a, N, F> Sub for &'a QFlag<N, F>
95where
96    N: Clone + Num + FromPrimitive + ScalarOperand,
97    F: Flag,
98{
99    type Output = QFlag<N, F>;
100
101    fn sub(self, other: Self) -> Self::Output {
102        assert_eq!(self.basis, other.basis);
103        assert_eq!(self.data.len(), other.data.len());
104        let (a1, a2, scale) = matching_scales::<N>(self.scale, other.scale);
105        QFlag {
106            basis: self.basis,
107            data: &self.data * a1 - &other.data * a2,
108            scale,
109            expr: self.expr.clone() - other.expr.clone(),
110        }
111    }
112}
113
114impl<N, F> Sub for QFlag<N, F>
115where
116    N: Clone + Num + FromPrimitive + ScalarOperand,
117    F: Flag,
118{
119    type Output = Self;
120
121    fn sub(self, other: Self) -> Self::Output {
122        &self - &other
123    }
124}
125
126impl<N, F: Flag> Neg for QFlag<N, F>
127where
128    N: Clone + Neg<Output = N>,
129{
130    type Output = Self;
131
132    fn neg(self) -> Self::Output {
133        Self {
134            basis: self.basis,
135            data: -self.data,
136            scale: self.scale,
137            expr: -self.expr,
138        }
139    }
140}
141
142impl<'a, N, F> Neg for &'a QFlag<N, F>
143where
144    N: Clone + Neg<Output = N>,
145    F: Flag,
146{
147    type Output = QFlag<N, F>;
148
149    fn neg(self) -> Self::Output {
150        QFlag {
151            basis: self.basis,
152            data: -self.data.clone(),
153            scale: self.scale,
154            expr: -self.expr.clone(),
155        }
156    }
157}
158
159// Right scalar multiplication (it is not possible to implement it on left)
160impl<N, F> Mul<N> for QFlag<N, F>
161where
162    N: Num + ScalarOperand + Display,
163    F: Flag,
164{
165    type Output = Self;
166
167    fn mul(self, rhs: N) -> Self::Output {
168        Self {
169            expr: Expr::num(&rhs) * self.expr.clone(),
170            basis: self.basis,
171            data: self.data * rhs,
172            scale: self.scale,
173        }
174    }
175}
176
177impl<N, F> Pow<usize> for &QFlag<N, F>
178where
179    N: Num + Clone + FromPrimitive + Display,
180    F: Flag,
181{
182    type Output = QFlag<N, F>;
183
184    fn pow(self, n: usize) -> QFlag<N, F> {
185        match n {
186            0 => self.basis.with_size(self.basis.t.size).one(),
187            1 => self.clone(),
188            n => {
189                let mut res = self * self;
190                for _ in 2..n {
191                    res = &res * self
192                }
193                res
194            }
195        }
196    }
197}
198
199impl<N, F: Flag> Display for IneqMeta<N, F>
200where
201    N: Display,
202{
203    fn fmt(&self, f: &mut Formatter) -> Result {
204        write!(
205            f,
206            "{}\t{} {}",
207            self.flag_expr,
208            if self.equality { '=' } else { '≥' },
209            self.bound_expr
210        )
211    }
212}
213
214impl<N, F: Flag> Display for Ineq<N, F>
215where
216    N: Display,
217{
218    fn fmt(&self, f: &mut Formatter) -> Result {
219        self.meta.fmt(f)
220    }
221}
222
223// =================
224fn quadratic_form<N>(lhs: &Array1<N>, matrix: &CsMat<u32>, rhs: &Array1<N>) -> N
225where
226    N: Num + Clone + FromPrimitive,
227{
228    assert_eq!(lhs.len(), matrix.rows());
229    assert_eq!(rhs.len(), matrix.cols());
230    let mut res = N::zero();
231    for (v, (i, j)) in matrix {
232        res = res + (N::from_u32(*v).unwrap() * lhs[i].clone() * rhs[j].clone());
233    }
234    res
235}
236
237fn vector_matrix_mul<N>(matrix: &CsMatView<u32>, vec: &Array1<N>) -> Array1<N>
238where
239    N: Num + Clone + FromPrimitive,
240{
241    assert_eq!(vec.len(), matrix.cols());
242    let mut res: Array1<N> = Array1::zeros(matrix.rows());
243    for (&v, (i, j)) in matrix {
244        res[i] = res[i].clone() + N::from_u32(v).unwrap() * vec[j].clone();
245    }
246    res
247}
248
249fn multiply<N>(lhs: &Array1<N>, table: &[CsMat<u32>], rhs: &Array1<N>) -> Array1<N>
250where
251    N: Num + Clone + FromPrimitive,
252{
253    let mut res = Array1::<N>::zeros(table.len());
254    for (i, matrix) in table.iter().enumerate() {
255        res[i] = quadratic_form(lhs, matrix, rhs);
256    }
257    res
258}
259
260// Conversions between dense and sparse arrays
261// Dense to sparse
262fn csvec_from_array<N>(array: &Array1<N>) -> CsVec<N>
263where
264    N: Num + Clone,
265{
266    let mut res = CsVec::empty(array.len());
267    for (i, val) in array.iter().enumerate() {
268        if val != &N::zero() {
269            res.append(i, val.clone())
270        }
271    }
272    res
273}
274
275// Sparse to dense
276fn array_from_csvec<N>(csvec: &CsVec<N>) -> Array1<N>
277where
278    N: Num + Clone,
279{
280    let mut res = vec![N::zero(); csvec.dim()];
281    csvec.scatter(&mut res);
282    Array1::from(res)
283}
284
285/// Flag operator function where the data from the flag algebra is given in input
286impl<N, F> QFlag<N, F>
287where
288    N: Num + Clone + FromPrimitive,
289    F: Flag,
290{
291    fn raw_expand(&self, operator: &CsMat<u32>, outbasis: Basis<F>, denom: u32) -> Self {
292        Self {
293            basis: outbasis,
294            data: vector_matrix_mul(&operator.view(), &self.data),
295            scale: self.scale * denom as u64,
296            expr: self.expr.clone(),
297        }
298    }
299    fn raw_multiply(&self, table: &[CsMat<u32>], other: &Self, denom: u32) -> Self {
300        assert_eq!(self.basis.t, other.basis.t);
301        Self {
302            basis: self.basis * other.basis,
303            data: multiply(&self.data, table, &other.data),
304            scale: self.scale * denom as u64 * other.scale,
305            expr: Expr::mul(self.expr.clone(), other.expr.clone()),
306        }
307    }
308    fn raw_untype(
309        &self,
310        untype_flag: &[usize],
311        untype_count: &[u32],
312        outbasis: Basis<F>,
313        outbasis_size: usize,
314        denom: u32,
315    ) -> Self {
316        assert_eq!(untype_flag.len(), untype_count.len());
317        let mut data = Array1::<N>::zeros(outbasis_size);
318        for (i, v) in self.data.iter().enumerate() {
319            data[untype_flag[i]] =
320                data[untype_flag[i]].clone() + v.clone() * N::from_u32(untype_count[i]).unwrap()
321        }
322        Self {
323            basis: outbasis,
324            data,
325            scale: self.scale * denom as u64,
326            expr: self.expr.clone().unlab(),
327        }
328    }
329}
330
331fn untype_matrix<N>(untype_flag: &[usize], untype_count: &[u32], outbasis_size: usize) -> CsMat<N>
332where
333    N: Num + FromPrimitive + Clone,
334{
335    let inbasis_size = untype_flag.len();
336    let shape = (outbasis_size, inbasis_size);
337    let mut trimat = TriMat::with_capacity(shape, inbasis_size);
338    for i in 0..untype_flag.len() {
339        trimat.add_triplet(untype_flag[i], i, N::from_u32(untype_count[i]).unwrap())
340    }
341    trimat.to_csr()
342}
343
344/// # Flag algebra operations
345
346impl<'a, N, F> Mul for &'a QFlag<N, F>
347where
348    N: Num + Clone + FromPrimitive,
349    F: Flag,
350{
351    type Output = QFlag<N, F>;
352
353    fn mul(self, other: Self) -> QFlag<N, F> {
354        let split = SplitCount::from_input(&self.basis, &other.basis);
355        self.raw_multiply(&split.get(), other, split.denom())
356    }
357}
358
359impl<N, F> Mul for QFlag<N, F>
360where
361    N: Num + Clone + FromPrimitive,
362    F: Flag,
363{
364    type Output = Self;
365
366    fn mul(self, other: Self) -> Self {
367        &self * &other
368    }
369}
370
371impl<N, F: Flag> QFlag<N, F> {
372    /// Projection to a basis of larger flag.
373    pub fn expand(&self, outbasis: Basis<F>) -> Self
374    where
375        N: Num + Clone + FromPrimitive,
376    {
377        let subflag = SubflagCount::from_to(self.basis, outbasis);
378        self.raw_expand(&subflag.get(), outbasis, subflag.denom())
379    }
380    /// Unlabeling operator 〚.〛 to the flag algebra of completly unlabeled flags.
381    pub fn untype(&self) -> Self
382    where
383        N: Num + Clone + FromPrimitive,
384    {
385        let unlabeling = Unlabeling::<F>::total(self.basis.t);
386        let size = self.basis.size;
387        let outbasis = self.basis.with_type(Type::empty());
388        let unlabel = Unlabel { unlabeling, size };
389        let (unlab_flag, unlab_count) = unlabel.get();
390        self.raw_untype(
391            &unlab_flag,
392            &unlab_count,
393            outbasis,
394            outbasis.get().len(),
395            unlabel.denom(),
396        )
397    }
398    /// Return the same element with modified pretty-print expression
399    pub fn with_expr(mut self, expr: Expr<N, F>) -> Self {
400        self.expr = expr;
401        self
402    }
403    /// Name the vector for the purpose of pretty-printing
404    pub fn named(mut self, name: String) -> Self {
405        self.expr = self.expr.named(name);
406        self
407    }
408    /// Divide the elements of the vector by the scale and set the scale to 1
409    pub fn no_scale(mut self) -> Self
410    where
411        N: FromPrimitive + DivAssign<N> + ScalarOperand,
412    {
413        self.data /= N::from_u64(self.scale).unwrap();
414        self.scale = 1;
415        self
416    }
417    pub fn map<G, M>(&self, g: G) -> QFlag<M, F>
418    where
419        G: Fn(&N) -> M,
420    {
421        QFlag {
422            basis: self.basis,
423            data: self.data.map(&g),
424            scale: self.scale,
425            expr: self.expr.map(&g),
426        }
427    }
428}
429
430/// # Creating inequalies from `QFlag`
431impl<N, F> QFlag<N, F>
432where
433    N: Num + FromPrimitive + Clone + Display,
434    F: Flag,
435{
436    /// Return the inequality "`self` ≥ `x`".
437    pub fn at_least(&self, x: N) -> Ineq<N, F> {
438        Ineq {
439            meta: IneqMeta {
440                basis: self.basis,
441                flag_expr: self.expr.clone(),
442                bound_expr: Expr::num(&x),
443                equality: false,
444                forall: None,
445                scale: self.scale,
446            },
447            data: vec![IneqData {
448                flag: csvec_from_array(&self.data),
449                bound: x * N::from_u64(self.scale).unwrap(),
450            }],
451        }
452    }
453    /// Return the inequality "`self` ≤ `x`".
454    pub fn at_most(&self, x: N) -> Ineq<N, F>
455    where
456        N: Clone + Neg<Output = N>,
457    {
458        (-self.clone()).at_least(-x)
459    }
460    /// Return the inequality "`self` ≥ `0`".
461    pub fn non_negative(&self) -> Ineq<N, F>
462    where
463        N: Num,
464    {
465        self.at_least(N::zero())
466    }
467    /// Return the equality "`self` = `n`".
468    pub fn equal(self, n: N) -> Ineq<N, F>
469    where
470        N: Clone + Neg<Output = N>,
471    {
472        self.at_least(n).equality()
473    }
474}
475
476/// Return the inequalities expressing that the sum of the flags of `basis`
477/// is equal to one.
478pub fn total_sum_is_one<N, F>(basis: Basis<F>) -> Ineq<N, F>
479where
480    F: Flag,
481    N: Num + Clone + Neg<Output = N> + FromPrimitive + Display,
482{
483    basis.one().equal(N::one())
484}
485
486/// Return the inequalities expressing that the flags of `basis`
487/// are larger than zero.
488pub fn flags_are_nonnegative<N, F>(basis: Basis<F>) -> Ineq<N, F>
489where
490    F: Flag,
491    N: Num + Clone + Neg<Output = N>,
492{
493    let n = basis.get().len();
494    let mut data = Vec::with_capacity(n);
495    for i in 0..n {
496        let mut flag = CsVec::empty(n);
497        flag.append(i, N::one());
498        data.push(IneqData {
499            flag,
500            bound: N::zero(),
501        })
502    }
503    let meta = IneqMeta {
504        basis,
505        flag_expr: Expr::Var(0).named(format!("flag(:{})", basis.print_concise())),
506        bound_expr: Expr::Zero,
507        equality: false,
508        forall: Some(VarRange::InBasis(basis)),
509        scale: 1,
510    };
511    Ineq { meta, data }
512}
513
514//============
515#[derive(Clone, Debug)]
516/// Contains informations about a set of inequalities of a flag algebra.
517pub(crate) struct IneqMeta<N, F: Flag> {
518    /// Basis in which the inequality is expressed.
519    /// This correspond to the type and size of the flags.
520    pub basis: Basis<F>,
521    /// Expression recording how the left sides of the inequalities where constructed.
522    pub flag_expr: Expr<N, F>,
523    forall: Option<VarRange<F>>,
524    /// Expression recording how the right sides where constructed.
525    pub bound_expr: Expr<N, F>,
526    /// True if the inequality is an equality
527    pub equality: bool,
528    scale: u64,
529}
530
531impl<N: Clone, F: Flag> IneqMeta<N, F> {
532    fn opposite(self) -> Self {
533        Self {
534            basis: self.basis,
535            flag_expr: self.flag_expr.neg(),
536            bound_expr: self.bound_expr.neg(),
537            equality: self.equality,
538            forall: self.forall,
539            scale: self.scale,
540        }
541    }
542    fn one_sided_expr(&self) -> Expr<N, F> {
543        Expr::sub(self.flag_expr.clone(), self.bound_expr.clone())
544    }
545
546    fn multiply(&self, rhs_basis: Basis<F>, rhs_expr: Expr<N, F>) -> Self {
547        let forall = if let Expr::Var(_) = rhs_expr {
548            match self.forall {
549                None => Some(VarRange::InBasis(rhs_basis)),
550                Some(_) => unimplemented!(),
551            }
552        } else {
553            self.forall.clone()
554        };
555        Self {
556            basis: self.basis * rhs_basis,
557            flag_expr: Expr::mul(self.one_sided_expr(), rhs_expr),
558            bound_expr: Expr::Zero,
559            equality: self.equality,
560            forall,
561            scale: self.scale * SplitCount::from_input(&self.basis, &rhs_basis).denom() as u64,
562        }
563    }
564
565    fn untype(&self) -> Self {
566        Self {
567            basis: self.basis.with_type(Type::empty()),
568            flag_expr: Expr::unlab(self.flag_expr.clone()),
569            bound_expr: self.bound_expr.clone(),
570            equality: self.equality,
571            forall: self.forall.clone(),
572            scale: self.scale * Unlabel::total(self.basis).denom() as u64,
573        }
574    }
575
576    pub(crate) fn latex(&self, names: &mut Names<N, F>) -> String
577    where
578        N: Display,
579    {
580        format!(
581            "{}{} {} {}",
582            if let Some(ref range) = self.forall {
583                range.latex(names)
584            } else {
585                String::new()
586            },
587            self.flag_expr.latex(names),
588            if self.equality { "=" } else { "\\geq" },
589            self.bound_expr.latex(names),
590        )
591    }
592}
593
594#[derive(Clone, Debug)]
595/// Contains the vector and the bound of one inequality in a flag algebra.
596/// This inequality has the form `self.flag  ≥ self.bound`.
597/// Expression recording how the left sides where constructed.
598pub(crate) struct IneqData<N> {
599    /// Vector of the left side in the corresponding flag basis.
600    pub flag: CsVec<N>,
601    /// Number on the right side of the inequality.
602    pub bound: N,
603}
604
605impl<N> IneqData<N>
606where
607    N: Num + Clone,
608{
609    fn opposite(self) -> Self
610    where
611        N: Neg<Output = N>,
612    {
613        let mut flag = self.flag;
614        flag.map_inplace(|x| -x.clone());
615        Self {
616            flag,
617            bound: -self.bound,
618        }
619    }
620    fn one_sided(self) -> Self
621    where
622        N: Neg<Output = N>,
623    {
624        if self.bound == N::zero() {
625            self
626        } else {
627            // Can be slow
628            // compute self.flag - self.bound
629            let n = self.flag.dim();
630            let mut flag = CsVec::empty(n);
631            flag.reserve(n);
632            let mut next_j = 0;
633            for (i, val) in self.flag.iter() {
634                for j in next_j..i {
635                    flag.append(j, -self.bound.clone())
636                }
637                flag.append(i, val.clone() - self.bound.clone());
638                next_j = i + 1;
639            }
640            for j in next_j..n {
641                flag.append(j, -self.bound.clone())
642            }
643            Self {
644                flag,
645                bound: N::zero(),
646            }
647        }
648    }
649    fn untype(&self, untype_matrix: &CsMat<N>, denom: u32) -> Self
650    where
651        N: Clone + Num + Default + MulAcc + Send + Sync + FromPrimitive,
652    {
653        Self {
654            flag: untype_matrix * &self.flag,
655            bound: self.bound.clone() * N::from_u32(denom).unwrap(),
656        }
657    }
658    // From profiling: Memory allocation here could be optimized
659    fn multiply_by_all(self, table: &[CsMat<N>], acc: &mut Vec<Self>)
660    where
661        N: Num + Clone + Send + Sync + MulAcc + Default + Neg<Output = N>,
662    {
663        if let Some(other_size) = table.first().map(|mat| mat.cols()) {
664            let one_sided = self.one_sided();
665            let mut flags: Vec<CsVec<N>> = vec![CsVec::empty(table.len()); other_size];
666            for (i, mat) in table.iter().enumerate() {
667                let vec: CsVec<N> = &mat.transpose_view() * &one_sided.flag.view();
668                for (j, val) in vec.iter() {
669                    flags[j].append(i, val.clone())
670                }
671            }
672            for flag in flags {
673                let ineq_data = Self {
674                    flag,
675                    bound: N::zero(),
676                };
677                acc.push(ineq_data)
678            }
679        }
680    }
681}
682
683#[derive(Clone, Debug)]
684/// A set of bounds on elements of a flag algebra.
685///
686/// This correpond to a set of inequalities constructed in a similar way.
687pub struct Ineq<N, F: Flag> {
688    /// Common information about the set of inequalities.
689    pub(crate) meta: IneqMeta<N, F>,
690    /// List of data of the inequalities in the set.
691    pub(crate) data: Vec<IneqData<N>>,
692}
693
694impl<N, F> Ineq<N, F>
695where
696    N: Clone + Num,
697    F: Flag,
698{
699    /// If self is "`f ≥ x`", returns "`f ≤ x`".
700    pub fn opposite(self) -> Self
701    where
702        N: Neg<Output = N>,
703    {
704        Self {
705            meta: self.meta.opposite(),
706            data: self.data.into_iter().map(|x| x.opposite()).collect(),
707        }
708    }
709    /// If self is "`f ≥ x`", returns "`f = x`".
710    pub fn equality(mut self) -> Self {
711        self.meta.equality = true;
712        self
713    }
714
715    /// If self is "`f ≥ x`", returns "`f ≥ x - eps`".
716    pub fn relaxed(mut self, eps: N) -> Self
717    where
718        N: SubAssign,
719    {
720        for ineq in &mut self.data {
721            ineq.bound -= eps.clone()
722        }
723        self
724    }
725    /// Return the flag member of the ith inequality
726    pub fn lhs(&self, i: usize) -> QFlag<N, F> {
727        assert!(i < self.data.len());
728        QFlag {
729            basis: self.meta.basis,
730            data: array_from_csvec(&self.data[i].flag),
731            scale: self.meta.scale,
732            expr: self.meta.flag_expr.substitute_option(&self.meta.forall, i),
733        }
734    }
735    pub fn check(&self)
736    where
737        N: Debug + Neg<Output = N> + Clone + FromPrimitive + ScalarOperand + Display,
738    {
739        for i in 0..self.data.len() {
740            let x = self.lhs(i);
741            assert_eq!(x, x.expr.eval());
742        }
743    }
744}
745
746impl<N, F> Ineq<N, F>
747where
748    N: Num + Clone + Send + Sync + Default + FromPrimitive + AddAssign + std::iter::Sum + MulAcc,
749    F: Flag,
750{
751    /// If self is "`f` ≥ `x`", return the projection "`〚f〛 ≥ x`".
752    pub fn untype(&self) -> Self {
753        let unlabeling = Unlabeling::<F>::total(self.meta.basis.t);
754        let size = self.meta.basis.size;
755        let unlabel = Unlabel { unlabeling, size };
756        let (unlab_f, unlab_c) = unlabel.get();
757        let outbasis_size = unlabel.output_basis().get().len();
758        let unlab_matrix = untype_matrix(&unlab_f, &unlab_c, outbasis_size);
759        let denom = unlabel.denom();
760        //
761        let mut data = Vec::new();
762        for i in &self.data {
763            let f = i.untype(&unlab_matrix, denom);
764            data.push(f)
765        }
766        Self {
767            meta: self.meta.untype(),
768            data,
769        }
770    }
771    /// If self is "`f` ≥ `x`", return the set of inequalities "`f*g ≥ x.g`",
772    /// where `g` is chosen such that `f*g` is a vector of `outbasis`.
773    pub fn multiply_by_all(self, outbasis: Basis<F>) -> Self
774    where
775        N: Neg<Output = N>,
776    {
777        let b = outbasis / self.meta.basis;
778        let splitcount = SplitCount::from_input(&self.meta.basis, &b);
779        let table: Vec<CsMat<N>> = splitcount
780            .get()
781            .iter()
782            .map(|m| m.map(|&x| N::from_u32(x).unwrap()))
783            .collect();
784        //
785        let mut data = Vec::new();
786        for ineq in self.data {
787            ineq.multiply_by_all(&table, &mut data)
788        }
789        //
790        Self {
791            data,
792            meta: self.meta.multiply(b, Expr::Var(0)),
793        }
794    }
795    /// If self is "`f` ≥ `x`", return the set of inequalities "`〚f*g〛 ≥ x.〚g〛`",
796    /// where `g` is chosen such that `〚f*g〛` is a vector of `outbasis`.
797    pub fn multiply_and_unlabel(self, outbasis: Basis<F>) -> Self
798    where
799        N: Neg<Output = N>,
800    {
801        assert_eq!(outbasis.t, Type::empty());
802        let unlabeling = Unlabeling::total(self.meta.basis.t);
803        let other = outbasis.with_type(self.meta.basis.t) / self.meta.basis;
804        let splitcount = SplitCount::from_input(&self.meta.basis, &other);
805        let operator = MulAndUnlabel {
806            split: splitcount,
807            unlabeling,
808        };
809        //
810        let table: Vec<CsMat<N>> = operator
811            .get()
812            .iter()
813            .map(|m| m.map(|&x| N::from_i64(x).unwrap()))
814            .collect();
815        //
816        let mut data = Vec::new();
817        //
818        for ineq in self.data {
819            ineq.multiply_by_all(&table, &mut data)
820        }
821        Self {
822            data,
823            meta: self.meta.multiply(other, Expr::Var(0)).untype(),
824        }
825    }
826}
827
828/// Return the vector corresponding to the unlabeled flag `f`.
829pub fn flag<N, F>(f: &F) -> QFlag<N, F>
830where
831    N: Num + Clone,
832    F: Flag,
833{
834    Basis::new(f.size()).flag(f)
835}
836
837/// Return the vector corresponding to the flag `f` with `type_size` labeled
838/// vertices.
839pub fn flag_typed<N, F>(f: &F, type_size: usize) -> QFlag<N, F>
840where
841    N: Num + Clone,
842    F: Flag,
843{
844    let flag = f.canonical_typed(type_size);
845    let type_flag = flag.induce(&(0..type_size).collect::<Vec<_>>()); // type
846    let t = Type::from_flag(&type_flag);
847    let basis = Basis::new(f.size()).with_type(t);
848    basis.flag(&flag)
849}
850
851#[cfg(test)]
852mod tests {
853    use super::*;
854    use crate::flags::Graph;
855    use ndarray::array;
856    #[test]
857    fn test_internals() {
858        // matching_scales
859        assert_eq!(matching_scales(15, 12), (4, 5, 60));
860        assert_eq!(matching_scales(2, 24), (12, 1, 24));
861        let (c1, c2, scale): (u64, u64, _) = matching_scales(1788, 2444);
862        let big = 1788 * 2444 * 1048;
863        assert_eq!((big * c1) / scale, big / 1788);
864        assert_eq!((big * c2) / scale, big / 2444);
865    }
866    #[test]
867    fn test_qflags() {
868        let qflag = QFlag {
869            basis: Basis::<Graph>::new(1),
870            data: array![3., 2., -5., 45.14],
871            scale: 42,
872            expr: Expr::Zero,
873        };
874        assert_eq!(qflag.clone().no_scale(), qflag)
875    }
876    #[test]
877    fn test_qflag_pows() {
878        let b = Basis::new(2).with_type(Type::new(1, 0));
879        let v: QFlag<i128, Graph> = b.random();
880        assert_eq!(v.pow(0), b.with_size(1).one());
881        assert_eq!(v.pow(1), v);
882        assert_eq!(v.pow(2), &v * &v);
883        assert_eq!(v.pow(3), &v * &(&v * &v));
884    }
885}