problemreductions/models/misc/
cosine_product_integration.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
13use crate::traits::Problem;
14use serde::{Deserialize, Serialize};
15
16inventory::submit! {
17 ProblemSchemaEntry {
18 name: "CosineProductIntegration",
19 display_name: "Cosine Product Integration",
20 aliases: &[],
21 dimensions: &[],
22 category: crate::registry::ProblemCategory::Misc,
23 module_path: module_path!(),
24 description: "Decide whether a balanced sign assignment exists for a sequence of integer frequencies",
25 fields: &[
26 FieldInfo {
27 name: "coefficients",
28 type_name: "Vec<i64>",
29 description: "Integer cosine frequencies",
30 },
31 ],
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct CosineProductIntegration {
59 coefficients: Vec<i64>,
60}
61
62impl CosineProductIntegration {
63 pub fn new(coefficients: Vec<i64>) -> Self {
69 assert!(
70 !coefficients.is_empty(),
71 "CosineProductIntegration requires at least one coefficient"
72 );
73 Self { coefficients }
74 }
75
76 pub fn coefficients(&self) -> &[i64] {
78 &self.coefficients
79 }
80
81 pub fn num_coefficients(&self) -> usize {
83 self.coefficients.len()
84 }
85}
86
87impl Problem for CosineProductIntegration {
88 const NAME: &'static str = "CosineProductIntegration";
89 type Solution = Vec<bool>;
90 type Value = crate::types::Or;
91
92 crate::problem_parameters![("num_coefficients", num_coefficients),];
93
94 fn variant() -> Vec<(&'static str, &'static str)> {
95 crate::variant_params![]
96 }
97
98 fn evaluate(
99 &self,
100 config: &Self::Solution,
101 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
102 Ok({
103 crate::types::Or({
104 if config.len() != self.num_coefficients() {
105 return Err(crate::traits::EvaluationError::InvalidConfiguration(
106 "sign-selection length does not match the coefficients".into(),
107 ));
108 }
109 let signed_sum = self.coefficients.iter().zip(config.iter()).try_fold(
110 0_i64,
111 |total, (&coefficient, &bit)| {
112 let term = if !bit {
113 coefficient
114 } else {
115 coefficient.checked_neg().ok_or_else(|| {
116 crate::traits::EvaluationError::IntegerOverflow(
117 "negating cosine-product coefficient".into(),
118 )
119 })?
120 };
121 total.checked_add(term).ok_or_else(|| {
122 crate::traits::EvaluationError::IntegerOverflow(
123 "summing signed cosine-product coefficients".into(),
124 )
125 })
126 },
127 )?;
128 signed_sum == 0
129 })
130 })
131 }
132}
133
134impl crate::solvers::BruteForceProblem for CosineProductIntegration {
135 fn dimensions(&self) -> Vec<usize> {
136 vec![2; self.num_coefficients()]
137 }
138}
139
140crate::declare_variants! {
141 default CosineProductIntegration => "2^(num_coefficients / 2)",
142}
143
144crate::register_brute_force! {
145 CosineProductIntegration decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
146}
147
148#[cfg(feature = "example-db")]
149pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
150 vec![crate::example_db::specs::ModelExampleSpec {
151 id: "cosine_product_integration",
152 instance: Box::new(CosineProductIntegration::new(vec![2, 3, 5])),
153 optimal_config: serde_json::json!(vec![false, false, true]),
154 optimal_value: serde_json::json!(true),
155 }]
156}
157
158#[cfg(test)]
159#[path = "../../unit_tests/models/misc/cosine_product_integration.rs"]
160mod tests;