Skip to content

Instantly share code, notes, and snippets.

@maxim-ge
Last active October 21, 2025 06:30
Show Gist options
  • Select an option

  • Save maxim-ge/5ef884464963b88c5cb232b457b774af to your computer and use it in GitHub Desktop.

Select an option

Save maxim-ge/5ef884464963b88c5cb232b457b774af to your computer and use it in GitHub Desktop.
Proof of the CAP Theorem in Coq (Rocq)
(* CAP theorem *)

Require Import Lia.

Inductive Value : Type :=
  | V1   : Value
  | V0   : Value
  | None : Value.

Class NetworkModel := {
  (* Number of network parts *)
  (* All parts are initialized with V0 *)
  n : nat;
  
  (* write to part[i], read from part[j] and reset all parts to V0 *)
  wr : forall (i j : nat), 
              i < n -> 
              j < n -> 
              Value;
              
  is_consistent : Prop :=
    forall (i j : nat) (Hi : i < n) (Hj : j < n),
    wr i j Hi Hj = V1 \/ wr i j Hi Hj = None;
    
  is_available : Prop :=
    forall (i j : nat) (Hi : i < n) (Hj : j < n),
    wr i j Hi Hj = V0 \/ wr i j Hi Hj = V1;

  is_partitioned : Prop :=
    n > 1;

  (* Behavior of two partitions *)
  wr_diff_parts : 
    forall (i j : nat) (Hi : i < n) (Hj : j < n),
    i <> j -> 
    (wr i j Hi Hj <> V1 \/ wr j i Hj Hi <> V1)
}.

(* If the NetworkModel is partitioned and consistent then there is at least one None response from wr *)
Lemma pc_exists_None :
  forall (model : NetworkModel),
  model.(is_partitioned)  /\ model.(is_consistent)  ->
  exists (i j : nat) (Hi : i < model.(n)) (Hj : j < model.(n)),
  model.(wr) i j Hi Hj = None.
Proof.
  intros model [H_partitioned H_c01].
  assert (H_c10 := H_c01).

  (* Since the model is partitioned, n > 1 *)
  unfold is_partitioned in H_partitioned.
  assert (Hn : model.(n) >= 2) by lia.

  (* Choose two distinct indices i and j *)
  assert (H0 : 0 < model.(n)) by lia.
  assert (H1 : 1 < model.(n)) by lia.
  assert (H01_neq : 0 <> 1) by lia.
  assert (H10_neq : 1 <> 0) by lia.  

  (* Apply the wr_diff_parts *)
  pose proof (model.(wr_diff_parts)  0 1 H0 H1 H01_neq) as H_p.
  unfold is_consistent in H_c10.
  unfold is_consistent in H_c01.
  specialize (H_c01 0 1 H0 H1).
  specialize (H_c10 1 0 H1 H0).
  
  destruct H_p as [H_p01 | H_p10].
- exists 0, 1, H0, H1.
  
  destruct H_c01 as [H_v1 | H_none].
+ (* Case: wr model 0 1 H0 H1 = V1 *)
  contradiction H_v1. 
+ (* Case: wr model 0 1 H0 H1 = None *)
  exact H_none.
  
- exists 1, 0, H1, H0.
  destruct H_c10 as [H_v1 | H_none].
  + (* Case: wr model 1 0 H1 H0 = V1 *)
  contradiction H_v1. 
  + (* Case: wr model 1 0 H1 H0 = None *)
  exact H_none. 
 
Qed.

Theorem cap :
  forall (model : NetworkModel),
  model.(is_partitioned)  ->
  ~ ( model.(is_consistent)  /\ model.(is_available) ).
Proof.
  intros model Hp Hca.
  
  destruct Hca as [Hc Ha].
  
  (* exists wr = None *)  
  pose proof (pc_exists_None model).
  assert (Hpc: model.(is_partitioned)  /\ model.(is_consistent) ).
  split.
  exact Hp.
  exact Hc.
  apply H in Hpc as HexistsNone.
  
  unfold is_available in Ha.
  destruct HexistsNone as [i [j [Hi [Hj Heq]]]].
  specialize (Ha i j Hi Hj).
  
  (* Ha says wr i j Hi Hj = V0 \/ wr i j Hi Hj = V1 *)
  (* Heq says wr i j Hi Hj = None *)
  (* None is neither V0 nor V1, contradiction *)
  rewrite Heq in Ha.
  destruct Ha as [HV0 | HV1].
  - discriminate HV0.
  - discriminate HV1.
Qed.

You can load it to the Coq scratchpad.

image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment