Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/models/graph/maximum_clique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
use crate::topology::{Graph, SimpleGraph};
use crate::traits::Problem;
use crate::types::{Max, WeightElement};
use crate::types::{Max, One, WeightElement};
use num_traits::Zero;
use serde::{Deserialize, Serialize};

Expand All @@ -17,7 +17,7 @@ inventory::submit! {
aliases: &[],
dimensions: &[
VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
VariantDimension::new("weight", "i32", &["i32"]),
VariantDimension::new("weight", "One", &["One", "i32"]),
],
module_path: module_path!(),
description: "Find maximum weight clique in a graph",
Expand Down Expand Up @@ -165,7 +165,8 @@ fn is_clique_config<G: Graph>(graph: &G, config: &[usize]) -> bool {
}

crate::declare_variants! {
default MaximumClique<SimpleGraph, i32> => "1.1996^num_vertices",
MaximumClique<SimpleGraph, i32> => "1.1996^num_vertices",
default MaximumClique<SimpleGraph, One> => "1.1996^num_vertices",
}

#[cfg(feature = "example-db")]
Expand Down
16 changes: 15 additions & 1 deletion src/rules/graph_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Shared helpers for graph-based reductions.

use crate::topology::Graph;
use crate::topology::{Graph, SimpleGraph};

/// Extract a Hamiltonian cycle vertex ordering from edge-selection configs on complete graphs.
///
Expand Down Expand Up @@ -57,3 +57,17 @@ pub(crate) fn edges_to_cycle_order<G: Graph>(graph: &G, target_solution: &[usize

order
}

/// Build the complement graph edges: edges between all non-adjacent vertex pairs.
pub(crate) fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
let n = graph.num_vertices();
let mut edges = Vec::new();
for u in 0..n {
for v in (u + 1)..n {
if !graph.has_edge(u, v) {
edges.push((u, v));
}
}
}
edges
}
13 changes: 1 addition & 12 deletions src/rules/kcoloring_partitionintocliques.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,7 @@ impl ReductionResult for ReductionKColoringToPartitionIntoCliques {
}
}

fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
let n = graph.num_vertices();
let mut edges = Vec::new();
for u in 0..n {
for v in (u + 1)..n {
if !graph.has_edge(u, v) {
edges.push((u, v));
}
}
}
edges
}
use super::graph_helpers::complement_edges;

#[reduction(
overhead = {
Expand Down
18 changes: 18 additions & 0 deletions src/rules/maximumclique_casts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! Variant cast reductions for MaximumClique.
//!
//! Weight-hierarchy cast converting MaximumClique between weight subtypes.

use crate::impl_variant_reduction;
use crate::models::graph::MaximumClique;
use crate::topology::SimpleGraph;
use crate::types::One;
use crate::variant::CastToParent;

// Weight-hierarchy cast (One → i32)
impl_variant_reduction!(
MaximumClique,
<SimpleGraph, One> => <SimpleGraph, i32>,
fields: [num_vertices, num_edges],
|src| MaximumClique::new(
src.graph().clone(), src.weights().iter().map(|w| w.cast_to_parent()).collect())
);
44 changes: 25 additions & 19 deletions src/rules/maximumclique_maximumindependentset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::models::graph::{MaximumClique, MaximumIndependentSet};
use crate::reduction;
use crate::rules::traits::{ReduceTo, ReductionResult};
use crate::topology::{Graph, SimpleGraph};
use crate::types::WeightElement;
use crate::types::{One, WeightElement};

/// Result of reducing MaximumClique to MaximumIndependentSet.
#[derive(Debug, Clone)]
Expand All @@ -33,18 +33,15 @@ where
}
}

/// Build the complement graph: edges between all non-adjacent vertex pairs.
fn complement_edges(graph: &SimpleGraph) -> Vec<(usize, usize)> {
let n = graph.num_vertices();
let mut edges = Vec::new();
for u in 0..n {
for v in (u + 1)..n {
if !graph.has_edge(u, v) {
edges.push((u, v));
}
}
}
edges
fn reduce_clique_to_is<W: WeightElement + Clone + Default>(
src: &MaximumClique<SimpleGraph, W>,
) -> ReductionCliqueToIS<W> {
let comp_edges = super::graph_helpers::complement_edges(src.graph());
let target = MaximumIndependentSet::new(
SimpleGraph::new(src.graph().num_vertices(), comp_edges),
src.weights().to_vec(),
);
ReductionCliqueToIS { target }
}

#[reduction(
Expand All @@ -57,12 +54,21 @@ impl ReduceTo<MaximumIndependentSet<SimpleGraph, i32>> for MaximumClique<SimpleG
type Result = ReductionCliqueToIS<i32>;

fn reduce_to(&self) -> Self::Result {
let comp_edges = complement_edges(self.graph());
let target = MaximumIndependentSet::new(
SimpleGraph::new(self.graph().num_vertices(), comp_edges),
self.weights().to_vec(),
);
ReductionCliqueToIS { target }
reduce_clique_to_is(self)
}
}

#[reduction(
overhead = {
num_vertices = "num_vertices",
num_edges = "num_vertices * (num_vertices - 1) / 2 - num_edges",
}
)]
impl ReduceTo<MaximumIndependentSet<SimpleGraph, One>> for MaximumClique<SimpleGraph, One> {
type Result = ReductionCliqueToIS<One>;

fn reduce_to(&self) -> Self::Result {
reduce_clique_to_is(self)
}
}

Expand Down
43 changes: 27 additions & 16 deletions src/rules/maximumindependentset_maximumclique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::models::graph::{MaximumClique, MaximumIndependentSet};
use crate::reduction;
use crate::rules::traits::{ReduceTo, ReductionResult};
use crate::topology::{Graph, SimpleGraph};
use crate::types::WeightElement;
use crate::types::{One, WeightElement};

/// Result of reducing MaximumIndependentSet to MaximumClique.
#[derive(Debug, Clone)]
Expand All @@ -33,6 +33,17 @@ where
}
}

fn reduce_is_to_clique<W: WeightElement + Clone + Default>(
src: &MaximumIndependentSet<SimpleGraph, W>,
) -> ReductionISToClique<W> {
let comp_edges = super::graph_helpers::complement_edges(src.graph());
let target = MaximumClique::new(
SimpleGraph::new(src.graph().num_vertices(), comp_edges),
src.weights().to_vec(),
);
ReductionISToClique { target }
}

#[reduction(
overhead = {
num_vertices = "num_vertices",
Expand All @@ -43,21 +54,21 @@ impl ReduceTo<MaximumClique<SimpleGraph, i32>> for MaximumIndependentSet<SimpleG
type Result = ReductionISToClique<i32>;

fn reduce_to(&self) -> Self::Result {
let n = self.graph().num_vertices();
// Build complement graph edges
let mut complement_edges = Vec::new();
for u in 0..n {
for v in (u + 1)..n {
if !self.graph().has_edge(u, v) {
complement_edges.push((u, v));
}
}
}
let target = MaximumClique::new(
SimpleGraph::new(n, complement_edges),
self.weights().to_vec(),
);
ReductionISToClique { target }
reduce_is_to_clique(self)
}
}

#[reduction(
overhead = {
num_vertices = "num_vertices",
num_edges = "num_vertices * (num_vertices - 1) / 2 - num_edges",
}
)]
impl ReduceTo<MaximumClique<SimpleGraph, One>> for MaximumIndependentSet<SimpleGraph, One> {
type Result = ReductionISToClique<One>;

fn reduce_to(&self) -> Self::Result {
reduce_is_to_clique(self)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub(crate) mod ksatisfiability_timetabledesign;
pub(crate) mod longestcommonsubsequence_maximumindependentset;
pub(crate) mod maxcut_minimumcutintoboundedsets;
pub(crate) mod maximum2satisfiability_maxcut;
mod maximumclique_casts;
pub(crate) mod maximumclique_maximumindependentset;
mod maximumindependentset_casts;
mod maximumindependentset_gridgraph;
Expand Down
Loading