Problem: knapsack_01

Your task is to implement the 0/1 Knapsack algorithm and verify its correctness in Dafny. You are given a sequence of weights and a sequence of values for n items, and a maximum weight capacity W. The goal is to determine the maximum total value of items that can be included in the knapsack such that the total weight does not exceed W. Each item can be selected at most once (hence 0/1). In the incomplete code, the specification defines what constitutes a valid selection strategy (a sequence of booleans indicating whether each item is chosen) and how to calculate the total weight and value. Your task is to implement the algorithm (typically DP) and verify that it returns the optimal value. Specifically, you must prove: (1) Upper Bound: Any valid selection yields a total value less than or equal to the returned result. (2) Existence: There exists a valid selection whose total value is exactly equal to the returned result. Note that because Dafny integers are signed, explicit preconditions are added to ensure weights, values, and capacity are non-negative.

// Following is the block for necessary definitions
// <preamble>
// Calculates the total weight of the selected items
function total_weight(selected: seq<bool>, weights: seq<int>): int
    requires |selected| <= |weights|
    decreases |selected|
{
    if |selected| == 0 then
        0
    else
        (if selected[0] then weights[0] else 0) + 
        total_weight(selected[1..], weights[1..])
}

// Calculates the total value of the selected items
function total_value(selected: seq<bool>, values: seq<int>): int
    requires |selected| <= |values|
    decreases |selected|
{
    if |selected| == 0 then
        0
    else
        (if selected[0] then values[0] else 0) + 
        total_value(selected[1..], values[1..])
}

// Definition of a valid strategy: 
// 1. Selection length matches items length
// 2. Total weight does not exceed capacity
predicate is_valid_strategy(selected: seq<bool>, weights: seq<int>, capacity: int)
{
    |selected| == |weights| &&
    total_weight(selected, weights) <= capacity
}
// </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 solve_knapsack_01(weights: seq<int>, values: seq<int>, capacity: int) returns (max_val: int)
    requires |weights| == |values|
    requires |weights| <= 100 // Reasonable bound for recursion/verification time
    requires 0 <= capacity <= 1000 // Explicitly constrain non-negative capacity
    requires forall i :: 0 <= i < |weights| ==> 0 <= weights[i] <= 1000 // Explicitly constrain non-negative weights
    requires forall i :: 0 <= i < |values| ==> 0 <= values[i] <= 1000   // Explicitly constrain non-negative values
    ensures max_val >= 0
    ensures
        // 1. Upper Bound
        forall selected: seq<bool> :: 
            is_valid_strategy(selected, weights, capacity)
            ==> total_value(selected, values) <= max_val
    ensures
        // 2. Existence
        exists selected: seq<bool> :: 
            is_valid_strategy(selected, weights, capacity)
            && total_value(selected, values) == max_val
// </spec>
// <code>
{
    // TODO: Implement the 0/1 Knapsack DP algorithm here.
}
// </code>

method Main() {}