Problem: bipartite_check

Your task is to implement an algorithm to check if a graph is Bipartite (2-colorable) and verify its functional correctness in Dafny. You need to implement check_bipartite, which attempts to color the graph with two colors (represented as booleans). It should return Some(colors) if successful, and None if the graph is not bipartite. There are several verification challenges: (1) Coloring Validity: If returning Some(colors), you must prove that for every edge $(u, v)$ in the graph, colors[u] != colors[v]. (2) Non-Bipartiteness: If returning None, you must prove that no valid 2-coloring exists. This is the hardest part. It requires proving that the conflict found (e.g., an edge connecting two nodes forced to be the same color) implies a contradiction for any possible valid coloring of the component. (3) Connectivity: Since the graph may be disconnected, you must prove the algorithm correctly handles all connected components, ensuring the property holds globally.

// Following is the block for necessary definitions
// <preamble>
datatype Option<T> = Some(value: T) | None

datatype Graph = Graph(adj: seq<seq<int>>)

// Helper predicates/functions for the Graph datatype
ghost predicate well_formed(g: Graph) {
  forall u: int, i: int :: 
    0 <= u < |g.adj| && 0 <= i < |g.adj[u]| 
    ==> 
    0 <= g.adj[u][i] < |g.adj|
}

ghost function size(g: Graph): int {
  |g.adj|
}

// --- Basic Graph Definitions ---

ghost predicate has_edge(g: Graph, u: int, v: int) {
  exists i: int :: 
    0 <= u < |g.adj| 
    && 0 <= i < |g.adj[u]| 
    && g.adj[u][i] == v
}

// Bipartite (2-Coloring) Definitions
// A coloring is valid if no two connected nodes share the same color.
// We represent colors as booleans (false=ColorA, true=ColorB).
ghost predicate is_valid_coloring(g: Graph, colors: seq<bool>) {
  && |colors| == size(g)
  && (forall u: int, v: int :: 
        has_edge(g, u, v) 
        ==> 
        // In Dafny, we must ensure indices are within bounds for valid access
        0 <= u < |colors| && 0 <= v < |colors| && colors[u] != colors[v])
}

// Helper to state that a graph IS bipartite (exists some valid coloring)
ghost predicate is_bipartite(g: Graph) {
  exists colors: seq<bool> :: is_valid_coloring(g, colors)
}
// </preamble>

// Following is the block for potential helper specifications
// <helpers>

// </helpers>

// Following is the block for proofs of lemmas
// <proofs>

// </proofs>

// Following is the block for the main specification
// <spec>
// Bipartite Check (2-Coloring)
// Functional Correctness:
// - If Bipartite: Returns Some(colors).
// - If Not: Returns None.
method check_bipartite(graph: Graph) returns (res: Option<seq<bool>>)
  requires well_formed(graph)
  ensures match res {
    case Some(colors) => is_valid_coloring(graph, colors)
    case None => !is_bipartite(graph)
  }
// </spec>
// <code>
{
    // Implement and verify the function to check if a graph is bipartite 
}
// </code>