Problem: lca

Implement a function lowest_common_ancestor that finds the lowest common ancestor of two nodes in a binary tree. Inputs: 1. root: A Tree representing the root of a binary tree. 2. p: An int value representing the first target node. 3. q: An int value representing the second target node. Assumptions & Constraints: 1. Existence: Both p and q are guaranteed to exist in the tree. 2. Uniqueness: All values in the tree are distinct; this ensures that p and q unambiguously identify specific unique nodes in the tree structure. Functional Specification (What to Return): The function must return a value lca_val such that: 1. Common Ancestor: The node containing lca_val is an ancestor of both p and q (a node is considered an ancestor of itself). 2. Lowest (Deepest): Among all common ancestors of p and q, the returned node is the one with the greatest depth (distance from the root). Verification Requirements: You must prove that the returned node satisfies the "Common Ancestor" property; you must prove that for all other nodes in the tree, if that node is a common ancestor, its depth is less than or equal to the depth of your returned node; and you must utilize the provided helper specifications (spec_get_depth, is_common_ancestor, tree_distinct) to construct your proof.


// Following is the block for necessary definitions
// <preamble>
datatype Tree = Nil | Node(val: int, left: Tree, right: Tree)

datatype Option<T> = None | Some(get: T) {
    predicate is_some() { this.Some? }
}

// Standard view as a Set of values
ghost function view(t: Tree): set<int> 
    decreases t
{
    match t {
        case Nil => {}
        case Node(v, l, r) => view(l) + view(r) + {v}
    }
}

ghost function contains(t: Tree, target: int): bool 
    decreases t
{
    match t {
        case Nil => false
        case Node(v, l, r) => v == target || contains(l, target) || contains(r, target)
    }
}

// We need to define what it means for a tree to have distinct values.
ghost predicate tree_distinct(t: Tree)
    decreases t
{
    match t {
        case Nil => true
        case Node(v, l, r) => 
            // 1. Left subtree is distinct
            tree_distinct(l) &&
            // 2. Right subtree is distinct
            tree_distinct(r) &&
            // 3. Current value is NOT in left or right subtrees
            !contains(l, v) &&
            !contains(r, v) &&
            // 4. Left and Right sets are disjoint (no shared values)
            (view(l) * view(r) == {}) // Set intersection is empty
    }
}

// With tree_distinct guaranteed, spec_get_depth is now unambiguous.
ghost function spec_get_depth(t: Tree, target: int): Option<int>
    decreases t
{
    match t {
        case Nil => None
        case Node(v, l, r) =>
            if v == target then
                Some(0)
            else
                var left_d := spec_get_depth(l, target);
                var right_d := spec_get_depth(r, target);
                if left_d.Some? then
                    Some(left_d.get + 1)
                else if right_d.Some? then
                    Some(right_d.get + 1)
                else
                    None
    }
}

ghost function spec_get_subtree(t: Tree, target: int): Tree
    decreases t
{
    match t {
        case Nil => Nil
        case Node(v, l, r) =>
            if v == target then
                t
            else
                var left_sub := spec_get_subtree(l, target);
                var right_sub := spec_get_subtree(r, target);
                if left_sub.Node? then left_sub else right_sub
    }
}

ghost predicate is_common_ancestor(t: Tree, anc_val: int, p: int, q: int) {
    var subtree := spec_get_subtree(t, anc_val);
    match subtree {
        case Node(_, _, _) => contains(subtree, p) && contains(subtree, q)
        case Nil => false
    }
}
// </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>
method lowest_common_ancestor(root: Tree, p: int, q: int) returns (res: Option<int>)
    requires p >= 0 // u64 constraint
    requires q >= 0 // u64 constraint
    requires contains(root, p)
    requires contains(root, q)
    // The tree must contain unique values.
    requires tree_distinct(root)
    ensures res.Some?
    ensures is_common_ancestor(root, res.get, p, q)
    ensures forall x: int :: is_common_ancestor(root, x, p, q) ==> 
        spec_get_depth(root, x).Some? && 
        spec_get_depth(root, res.get).Some? &&
        spec_get_depth(root, x).get <= spec_get_depth(root, res.get).get
// </spec>
// <code>
{
    // Implement and verify LCA algorithm here.
}
// </code>