use super::types::{ArithmeticProgression, Clique, Coloring, IndependentSet, RamseyWitness};
pub fn ramsey_number_known(r: usize, s: usize) -> Option<usize> {
let (r, s) = if r <= s { (r, s) } else { (s, r) };
match (r, s) {
(0, _) => Some(0),
(1, _) => Some(1),
(2, s) => Some(s),
(3, 3) => Some(6),
(3, 4) => Some(9),
(3, 5) => Some(14),
(3, 6) => Some(18),
(3, 7) => Some(23),
(3, 8) => Some(28),
(3, 9) => Some(36),
(4, 4) => Some(18),
(4, 5) => Some(25),
_ => None,
}
}
pub fn ramsey_upper_bound(r: usize, s: usize) -> usize {
if r == 0 || s == 0 {
return 0;
}
binomial(r + s - 2, r.saturating_sub(1))
}
pub fn find_monochromatic_clique(coloring: &Coloring, color: usize, size: usize) -> Option<Clique> {
let n = coloring.num_vertices;
if size == 0 {
return Some(Clique {
vertices: vec![],
size: 0,
});
}
if size > n {
return None;
}
let mut adj = vec![vec![false; n]; n];
for &(u, v, c) in &coloring.edges {
if c == color {
adj[u][v] = true;
adj[v][u] = true;
}
}
let mut combo = Vec::with_capacity(size);
if find_clique_recursive(&adj, n, size, 0, &mut combo) {
let s = combo.len();
Some(Clique {
vertices: combo,
size: s,
})
} else {
None
}
}
pub fn is_valid_ramsey_coloring(coloring: &Coloring, r: usize, s: usize) -> bool {
find_monochromatic_clique(coloring, 0, r).is_none()
&& find_monochromatic_clique(coloring, 1, s).is_none()
}
pub fn greedy_coloring(n: usize, r: usize, s: usize) -> Option<Coloring> {
let mut edges: Vec<(usize, usize, usize)> = Vec::new();
let mut adj0 = vec![vec![false; n]; n];
let mut adj1 = vec![vec![false; n]; n];
for u in 0..n {
for v in (u + 1)..n {
adj0[u][v] = true;
adj0[v][u] = true;
let creates_clique0 = would_create_clique(&adj0, u, v, r);
if creates_clique0 {
adj0[u][v] = false;
adj0[v][u] = false;
adj1[u][v] = true;
adj1[v][u] = true;
let creates_clique1 = would_create_clique(&adj1, u, v, s);
if creates_clique1 {
adj1[u][v] = false;
adj1[v][u] = false;
return None; }
edges.push((u, v, 1));
} else {
edges.push((u, v, 0));
}
}
}
let coloring = Coloring {
num_vertices: n,
num_colors: 2,
edges,
};
if is_valid_ramsey_coloring(&coloring, r, s) {
Some(coloring)
} else {
None
}
}
pub fn van_der_waerden_number_known(k: usize, r: usize) -> Option<usize> {
if r != 2 {
return None;
}
match k {
2 => Some(3),
3 => Some(9),
4 => Some(35),
5 => Some(178),
_ => None,
}
}
pub fn find_arithmetic_progression(
coloring: &[usize],
color: usize,
length: usize,
) -> Option<ArithmeticProgression> {
let n = coloring.len();
if length == 0 || n == 0 {
return None;
}
if length == 1 {
for (i, &c) in coloring.iter().enumerate() {
if c == color {
return Some(ArithmeticProgression {
start: i + 1,
step: 1,
length: 1,
});
}
}
return None;
}
for start in 0..n {
if coloring[start] != color {
continue;
}
let max_step = (n - 1 - start) / (length - 1);
for step in 1..=max_step {
let all_same = (0..length).all(|k| {
let idx = start + k * step;
idx < n && coloring[idx] == color
});
if all_same {
return Some(ArithmeticProgression {
start: start + 1,
step,
length,
});
}
}
}
None
}
pub fn schur_number_known(k: usize) -> Option<usize> {
match k {
1 => Some(1),
2 => Some(4),
3 => Some(13),
4 => Some(44),
5 => Some(160),
_ => None,
}
}
pub fn check_schur_triple_free(assignment: &[usize], color: usize) -> bool {
let n = assignment.len();
let colored: Vec<usize> = (1..=n)
.filter(|&i| i <= assignment.len() && assignment[i - 1] == color)
.collect();
for i in 0..colored.len() {
for j in i..colored.len() {
let z = colored[i] + colored[j];
if z <= n && assignment[z - 1] == color {
return false;
}
}
}
true
}
pub fn happy_ending_convex_position(points: &[(f64, f64)]) -> bool {
let n = points.len();
if n <= 3 {
return true;
}
let hull = convex_hull(points);
hull.len() == n
}
pub fn convex_position_number(n: usize) -> usize {
if n <= 2 {
return n;
}
binomial(2 * n - 4, n - 2) + 1
}
pub fn hales_jewett_bound(t: usize, n: usize) -> usize {
if t == 0 || n == 0 {
return 1;
}
let inner = saturating_pow(t, n);
saturating_pow(t, inner)
}
pub fn turan_number(n: usize, r: usize) -> usize {
if r <= 1 {
return 0;
}
if r == 2 {
return 0;
}
let num = (r - 2) * n * n;
let den = 2 * (r - 1);
num / den
}
pub fn turan_graph_edges(n: usize, r: usize) -> usize {
if r == 0 || n == 0 {
return 0;
}
if r >= n {
return n * (n - 1) / 2;
}
let q = n / r;
let s = n % r;
let sum_sq = (r - s) * q * q + s * (q + 1) * (q + 1);
(n * n - sum_sq) / 2
}
pub fn zarankiewicz_bound(m: usize, n: usize, s: usize, t: usize) -> usize {
if s == 0 || t == 0 || m == 0 || n == 0 {
return 0;
}
let s_f = s as f64;
let t_f = t as f64;
let m_f = m as f64;
let n_f = n as f64;
let term1 = 0.5 * (t_f - 1.0).powf(1.0 / s_f) * (m_f - s_f + 1.0) * n_f.powf(1.0 - 1.0 / s_f);
let term2 = 0.5 * (s_f - 1.0) * n_f;
(term1 + term2).ceil() as usize
}
pub(super) fn binomial(n: usize, k: usize) -> usize {
if k > n {
return 0;
}
let k = k.min(n - k); let mut result: u128 = 1;
for i in 0..k {
result = result * (n - i) as u128 / (i + 1) as u128;
}
result.min(usize::MAX as u128) as usize
}
fn saturating_pow(base: usize, exp: usize) -> usize {
if base == 0 {
return 0;
}
if base == 1 || exp == 0 {
return 1;
}
let mut result: usize = 1;
for _ in 0..exp {
result = result.saturating_mul(base);
if result == usize::MAX {
return usize::MAX;
}
}
result
}
fn find_clique_recursive(
adj: &[Vec<bool>],
n: usize,
target: usize,
start: usize,
combo: &mut Vec<usize>,
) -> bool {
if combo.len() == target {
return true;
}
let remaining = target - combo.len();
for v in start..n {
if n - v < remaining {
break; }
if combo.iter().all(|&u| adj[u][v]) {
combo.push(v);
if find_clique_recursive(adj, n, target, v + 1, combo) {
return true;
}
combo.pop();
}
}
false
}
fn would_create_clique(adj: &[Vec<bool>], u: usize, v: usize, target: usize) -> bool {
if target <= 2 {
return target == 2; }
let n = adj.len();
let common: Vec<usize> = (0..n)
.filter(|&w| w != u && w != v && adj[u][w] && adj[v][w])
.collect();
if common.len() < target - 2 {
return false;
}
let sub_adj: Vec<Vec<bool>> = common
.iter()
.map(|&ci| common.iter().map(|&cj| adj[ci][cj]).collect())
.collect();
let mut combo = Vec::new();
find_clique_recursive(&sub_adj, common.len(), target - 2, 0, &mut combo)
}
pub(super) fn convex_hull(points: &[(f64, f64)]) -> Vec<usize> {
let n = points.len();
if n <= 1 {
return (0..n).collect();
}
let start = (0..n)
.min_by(|&a, &b| {
points[a]
.0
.partial_cmp(&points[b].0)
.unwrap_or(std::cmp::Ordering::Equal)
.then(
points[a]
.1
.partial_cmp(&points[b].1)
.unwrap_or(std::cmp::Ordering::Equal),
)
})
.unwrap_or(0);
let mut hull = Vec::new();
let mut current = start;
loop {
hull.push(current);
let mut next = (current + 1) % n;
for candidate in 0..n {
if candidate == current {
continue;
}
let cross = cross2d(points[current], points[next], points[candidate]);
if cross < 0.0
|| (cross == 0.0
&& dist2(points[current], points[candidate])
> dist2(points[current], points[next]))
{
next = candidate;
}
}
current = next;
if current == start {
break;
}
if hull.len() > n {
break; }
}
hull
}
fn cross2d(a: (f64, f64), b: (f64, f64), c: (f64, f64)) -> f64 {
(b.0 - a.0) * (c.1 - a.1) - (b.1 - a.1) * (c.0 - a.0)
}
fn dist2(a: (f64, f64), b: (f64, f64)) -> f64 {
let dx = a.0 - b.0;
let dy = a.1 - b.1;
dx * dx + dy * dy
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ramsey_r1_s() {
assert_eq!(ramsey_number_known(1, 7), Some(1));
}
#[test]
fn test_ramsey_r2_s() {
assert_eq!(ramsey_number_known(2, 7), Some(7));
}
#[test]
fn test_ramsey_33() {
assert_eq!(ramsey_number_known(3, 3), Some(6));
}
#[test]
fn test_ramsey_44() {
assert_eq!(ramsey_number_known(4, 4), Some(18));
}
#[test]
fn test_ramsey_45_symmetric() {
assert_eq!(ramsey_number_known(4, 5), ramsey_number_known(5, 4));
assert_eq!(ramsey_number_known(4, 5), Some(25));
}
#[test]
fn test_ramsey_unknown() {
assert_eq!(ramsey_number_known(6, 6), None);
}
#[test]
fn test_ramsey_upper_bound_33() {
assert_eq!(ramsey_upper_bound(3, 3), 6);
}
#[test]
fn test_ramsey_upper_bound_34() {
assert_eq!(ramsey_upper_bound(3, 4), 10);
}
#[test]
fn test_find_clique_in_complete_3() {
let edges = vec![(0, 1, 0), (0, 2, 0), (1, 2, 0)];
let coloring = Coloring {
num_vertices: 3,
num_colors: 1,
edges,
};
let clique = find_monochromatic_clique(&coloring, 0, 3);
assert!(clique.is_some());
let c = clique.unwrap();
assert_eq!(c.size, 3);
}
#[test]
fn test_find_clique_none() {
let edges = vec![(0, 1, 0), (1, 2, 0)];
let coloring = Coloring {
num_vertices: 3,
num_colors: 1,
edges,
};
let clique = find_monochromatic_clique(&coloring, 0, 3);
assert!(clique.is_none());
}
#[test]
fn test_valid_ramsey_coloring_5_vertices() {
let n = 5usize;
let mut edges = Vec::new();
for u in 0..n {
for v in (u + 1)..n {
let diff = v - u;
let color = if diff == 1 || diff == n - 1 { 1 } else { 0 };
edges.push((u, v, color));
}
}
let coloring = Coloring {
num_vertices: n,
num_colors: 2,
edges,
};
assert!(is_valid_ramsey_coloring(&coloring, 3, 3));
}
#[test]
fn test_greedy_coloring_small() {
for n in 1usize..=5 {
let result = greedy_coloring(n, 3, 3);
if let Some(col) = result {
assert!(
is_valid_ramsey_coloring(&col, 3, 3),
"Greedy produced invalid coloring for n={}",
n
);
}
}
}
#[test]
fn test_vdw_known_k3() {
assert_eq!(van_der_waerden_number_known(3, 2), Some(9));
}
#[test]
fn test_vdw_unknown_3colors() {
assert_eq!(van_der_waerden_number_known(3, 3), None);
}
#[test]
fn test_find_ap_length_3() {
let c = vec![0usize, 1, 0, 1, 0, 1, 0, 1, 0];
let ap = find_arithmetic_progression(&c, 0, 3);
assert!(ap.is_some());
let p = ap.unwrap();
assert_eq!(p.length, 3);
assert_eq!(p.step, 2);
}
#[test]
fn test_find_ap_none() {
let c = vec![0usize, 1, 1, 0];
let ap = find_arithmetic_progression(&c, 0, 3);
assert!(ap.is_none());
}
#[test]
fn test_schur_known() {
assert_eq!(schur_number_known(3), Some(13));
assert_eq!(schur_number_known(5), Some(160));
}
#[test]
fn test_schur_unknown() {
assert_eq!(schur_number_known(7), None);
}
#[test]
fn test_check_schur_triple_free_ok() {
let assignment = vec![0usize, 1, 1, 0]; assert!(check_schur_triple_free(&assignment, 0));
}
#[test]
fn test_check_schur_triple_not_free() {
let assignment = vec![0usize, 0, 0];
assert!(!check_schur_triple_free(&assignment, 0));
}
#[test]
fn test_convex_position_square() {
let pts = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)];
assert!(happy_ending_convex_position(&pts));
}
#[test]
fn test_convex_position_interior_point() {
let pts = vec![(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (1.0, 1.0)];
assert!(!happy_ending_convex_position(&pts));
}
#[test]
fn test_convex_position_number_4() {
assert_eq!(convex_position_number(4), 7);
}
#[test]
fn test_turan_number_k3_n6() {
assert_eq!(turan_number(6, 3), 9);
}
#[test]
fn test_turan_graph_edges_complete() {
assert_eq!(turan_graph_edges(5, 10), 5 * 4 / 2);
}
#[test]
fn test_turan_graph_edges_t6_3() {
assert_eq!(turan_graph_edges(6, 3), 12);
}
#[test]
fn test_zarankiewicz_bound_basic() {
let z = zarankiewicz_bound(4, 4, 2, 2);
assert!(z > 0);
}
#[test]
fn test_binomial_symmetry() {
assert_eq!(binomial(10, 3), binomial(10, 7));
}
#[test]
fn test_hales_jewett_bound_positive() {
let b = hales_jewett_bound(2, 3);
assert!(b >= 1);
}
}