problemreductions/models/algebraic/
minimum_matrix_cover.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::traits::Problem;
8use crate::types::Min;
9use serde::{Deserialize, Serialize};
10
11inventory::submit! {
12 ProblemSchemaEntry {
13 name: "MinimumMatrixCover",
14 display_name: "Minimum Matrix Cover",
15 aliases: &[],
16 dimensions: &[],
17 module_path: module_path!(),
18 description: "Find sign assignment minimizing quadratic form over nonnegative integer matrix",
19 fields: &[
20 FieldInfo { name: "matrix", type_name: "Vec<Vec<i64>>", description: "n×n nonnegative integer matrix" },
21 ],
22 }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct MinimumMatrixCover {
54 matrix: Vec<Vec<i64>>,
56}
57
58impl MinimumMatrixCover {
59 pub fn new(matrix: Vec<Vec<i64>>) -> Self {
65 let n = matrix.len();
66 for (i, row) in matrix.iter().enumerate() {
67 assert_eq!(
68 row.len(),
69 n,
70 "Matrix must be square: row {i} has {} columns, expected {n}",
71 row.len()
72 );
73 }
74 Self { matrix }
75 }
76
77 pub fn num_rows(&self) -> usize {
79 self.matrix.len()
80 }
81
82 pub fn matrix(&self) -> &[Vec<i64>] {
84 &self.matrix
85 }
86}
87
88impl Problem for MinimumMatrixCover {
89 const NAME: &'static str = "MinimumMatrixCover";
90 type Value = Min<i64>;
91
92 fn variant() -> Vec<(&'static str, &'static str)> {
93 crate::variant_params![]
94 }
95
96 fn dims(&self) -> Vec<usize> {
97 vec![2; self.num_rows()]
98 }
99
100 fn evaluate(&self, config: &[usize]) -> Min<i64> {
101 let n = self.num_rows();
102 if config.len() != n {
103 return Min(None);
104 }
105 if config.iter().any(|&v| v >= 2) {
106 return Min(None);
107 }
108
109 let signs: Vec<i64> = config.iter().map(|&x| 2 * x as i64 - 1).collect();
111
112 let mut value: i64 = 0;
114 for i in 0..n {
115 for j in 0..n {
116 value += self.matrix[i][j] * signs[i] * signs[j];
117 }
118 }
119
120 Min(Some(value))
121 }
122}
123
124crate::declare_variants! {
125 default MinimumMatrixCover => "2^num_rows",
126}
127
128#[cfg(feature = "example-db")]
129pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
130 vec![crate::example_db::specs::ModelExampleSpec {
133 id: "minimum_matrix_cover",
134 instance: Box::new(MinimumMatrixCover::new(vec![
135 vec![0, 3, 1, 0],
136 vec![3, 0, 0, 2],
137 vec![1, 0, 0, 4],
138 vec![0, 2, 4, 0],
139 ])),
140 optimal_config: vec![0, 1, 1, 0],
141 optimal_value: serde_json::json!(-20),
142 }]
143}
144
145#[cfg(test)]
146#[path = "../../unit_tests/models/algebraic/minimum_matrix_cover.rs"]
147mod tests;