Skip to content

Commit

Permalink
QUBO and PUBO format output (#186)
Browse files Browse the repository at this point in the history
Revival of #143
  • Loading branch information
termoshtt authored Dec 6, 2024
1 parent 444816b commit 879fb91
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 91 deletions.
1 change: 1 addition & 0 deletions rust/ommx/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ mod parameter;
mod parametric_instance;
mod polynomial;
mod quadratic;
mod sorted_ids;
mod state;

use proptest::prelude::*;
Expand Down
26 changes: 19 additions & 7 deletions rust/ommx/src/convert/decision_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,23 +141,23 @@ impl Arbitrary for Kind {
}

impl Arbitrary for DecisionVariable {
type Parameters = u64;
type Parameters = (u64, Kind);
type Strategy = BoxedStrategy<Self>;

fn arbitrary_with(max_id: Self::Parameters) -> Self::Strategy {
fn arbitrary_with((id, kind): Self::Parameters) -> Self::Strategy {
let subscripts = prop_oneof![
Just(Vec::<i64>::new()),
proptest::collection::vec(-(max_id as i64)..=(max_id as i64), 1..=3),
proptest::collection::vec(-10_i64..=10, 1..=3),
];
let parameters = prop_oneof![
Just(HashMap::<String, String>::new()),
proptest::collection::hash_map(String::arbitrary(), String::arbitrary(), 1..=3),
];
(
0..=max_id,
Just(id),
Option::<Bound>::arbitrary(),
Option::<String>::arbitrary(),
Kind::arbitrary(),
Just(kind),
subscripts,
parameters,
Option::<String>::arbitrary(),
Expand All @@ -176,11 +176,23 @@ impl Arbitrary for DecisionVariable {
)
.boxed()
}

fn arbitrary() -> Self::Strategy {
(Just(0), Kind::arbitrary())
.prop_flat_map(Self::arbitrary_with)
.boxed()
}
}

pub fn arbitrary_decision_variables(ids: BTreeSet<u64>) -> BoxedStrategy<Vec<DecisionVariable>> {
pub(super) fn arbitrary_decision_variables(
ids: BTreeSet<u64>,
kind_strategy: impl Strategy<Value = Kind> + 'static,
) -> BoxedStrategy<Vec<DecisionVariable>> {
(
proptest::collection::vec(DecisionVariable::arbitrary(), ids.len()),
proptest::collection::vec(
(Just(0), kind_strategy).prop_flat_map(DecisionVariable::arbitrary_with),
ids.len(),
),
Just(ids),
)
.prop_map(|(mut dvs, used_ids)| {
Expand Down
36 changes: 22 additions & 14 deletions rust/ommx/src/convert/format.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt;

use super::sorted_ids::SortedIds;

fn write_f64_with_precision(f: &mut fmt::Formatter, coefficient: f64) -> fmt::Result {
if let Some(precision) = f.precision() {
write!(f, "{1:.0$}", precision, coefficient)?;
Expand All @@ -9,7 +11,7 @@ fn write_f64_with_precision(f: &mut fmt::Formatter, coefficient: f64) -> fmt::Re
Ok(())
}

fn write_term(f: &mut fmt::Formatter, mut ids: Vec<u64>, coefficient: f64) -> fmt::Result {
fn write_term(f: &mut fmt::Formatter, ids: SortedIds, coefficient: f64) -> fmt::Result {
if ids.is_empty() {
write_f64_with_precision(f, coefficient)?;
return Ok(());
Expand All @@ -22,7 +24,6 @@ fn write_term(f: &mut fmt::Formatter, mut ids: Vec<u64>, coefficient: f64) -> fm
if coefficient.abs() != 1.0 {
write!(f, "*")?;
}
ids.sort_unstable();
let mut ids = ids.iter().peekable();
if let Some(id) = ids.next() {
write!(f, "x{}", id)?;
Expand All @@ -35,21 +36,28 @@ fn write_term(f: &mut fmt::Formatter, mut ids: Vec<u64>, coefficient: f64) -> fm

pub fn format_polynomial(
f: &mut fmt::Formatter,
iter: impl Iterator<Item = (Vec<u64>, f64)>,
iter: impl Iterator<Item = (SortedIds, f64)>,
) -> fmt::Result {
let mut terms = iter.peekable();
for (ids, coefficient) in terms.by_ref() {
if coefficient == 0.0 {
continue;
}
write_term(f, ids, coefficient)?;
break;
let mut terms: Vec<_> = iter
.filter(|(_, coefficient)| coefficient.abs() > f64::EPSILON)
.collect();
if terms.is_empty() {
write!(f, "0")?;
return Ok(());
}

for (ids, coefficient) in terms {
if coefficient == 0.0 {
continue;
terms.sort_unstable_by(|(a, _), (b, _)| {
if a.len() != b.len() {
b.len().cmp(&a.len())
} else {
a.cmp(b)
}
});

let mut iter = terms.into_iter();
let (ids, coefficient) = iter.next().unwrap();
write_term(f, ids, coefficient)?;

for (ids, coefficient) in iter {
if coefficient < 0.0 {
write!(f, " - ")?;
write_term(f, ids, -coefficient)?;
Expand Down
34 changes: 32 additions & 2 deletions rust/ommx/src/convert/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use num::Zero;
use proptest::prelude::*;
use std::{collections::BTreeSet, fmt, iter::*, ops::*};

use super::sorted_ids::SortedIds;

impl Zero for Function {
fn zero() -> Self {
Self {
Expand Down Expand Up @@ -77,13 +79,30 @@ impl FromIterator<((u64, u64), f64)> for Function {
}
}

impl FromIterator<(Vec<u64>, f64)> for Function {
fn from_iter<I: IntoIterator<Item = (Vec<u64>, f64)>>(iter: I) -> Self {
impl FromIterator<(SortedIds, f64)> for Function {
fn from_iter<I: IntoIterator<Item = (SortedIds, f64)>>(iter: I) -> Self {
let poly: Polynomial = iter.into_iter().collect();
poly.into()
}
}

impl<'a> IntoIterator for &'a Function {
type Item = (SortedIds, f64);
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;

fn into_iter(self) -> Self::IntoIter {
match &self.function {
Some(FunctionEnum::Constant(c)) => Box::new(std::iter::once((SortedIds::empty(), *c))),
Some(FunctionEnum::Linear(linear)) => {
Box::new(linear.into_iter().map(|(id, c)| (id.into(), c)))
}
Some(FunctionEnum::Quadratic(quad)) => Box::new(quad.into_iter()),
Some(FunctionEnum::Polynomial(poly)) => Box::new(poly.into_iter()),
None => Box::new(std::iter::empty()),
}
}
}

impl Function {
pub fn used_decision_variable_ids(&self) -> BTreeSet<u64> {
match &self.function {
Expand Down Expand Up @@ -121,6 +140,17 @@ impl Function {
FunctionEnum::Polynomial(poly) => poly.as_constant(),
}
}

/// Get 0-th order term.
pub fn get_constant(&self) -> f64 {
match &self.function {
Some(FunctionEnum::Constant(c)) => *c,
Some(FunctionEnum::Linear(linear)) => linear.constant,
Some(FunctionEnum::Quadratic(quad)) => quad.get_constant(),
Some(FunctionEnum::Polynomial(poly)) => poly.get_constant(),
None => 0.0,
}
}
}

impl Add for Function {
Expand Down
Loading

0 comments on commit 879fb91

Please sign in to comment.