operation DatabaseOracleFromInts(
    markedElement : Int,
    markedQubit: Qubit,
    databaseRegister: Qubit[]
) : Unit {

    body (...) {
        (ControlledOnInt(markedElement, X))(databaseRegister, markedQubit);
    }

    adjoint auto;
    controlled auto;
    adjoint controlled auto;

}

ControlledOnInt?

operation PrepareDatabaseRegister(
    markedElement : Int,
    idxMarkedQubit: Int,
    startQubits: Qubit[]
) : Unit {

    body (...) {
        let flagQubit = startQubits[idxMarkedQubit];
        let databaseRegister = Exclude([idxMarkedQubit], startQubits);

        // Apply 𝑈.
        ApplyToEachCA(H, databaseRegister);

        // Apply 𝐷.
        DatabaseOracleFromInts(markedElement, flagQubit, databaseRegister);

    }

    adjoint auto;
    controlled auto;
    adjoint controlled auto;
}


function GroverStatePrepOracle(markedElement : Int) : StateOracle {
    return StateOracle(PrepareDatabaseRegister(markedElement, _, _));
}

function GroverSearch(
    markedElement: Int,
    nIterations: Int,
    idxMarkedQubit: Int
) : (Qubit[] => Unit : Adjoint, Controlled) {

    return AmpAmpByOracle(nIterations, GroverStatePrepOracle(markedElement), idxMarkedQubit);

}

operation ApplyQuantumSearch() : (Result, Int) {

    let nIterations = 6;
    let nDatabaseQubits = 6;
    let markedElement = 3;
    
    // Allocate variables to store measurement results.
    mutable resultSuccess = Zero;
    mutable numberElement = 0;

    using ((markedQubit, databaseRegister) = (Qubit(), Qubit[nDatabaseQubits])) {

        // Implement the quantum search algorithm.
        (GroverSearch(markedElement, nIterations, 0))([markedQubit] + databaseRegister);

        // Measure the marked qubit. On success, this should be One.
        set resultSuccess = MResetZ(markedQubit);

        // Measure the state of the database register post-selected on
        // the state of the marked qubit.
        let resultElement = MultiM(databaseRegister);
        set numberElement = PositiveIntFromResultArr(resultElement);

        // These reset all qubits to the |0〉 state, which is required 
        // before deallocation.
        ResetAll(databaseRegister);

    }

    // Returns the measurement results of the algorithm.
    return (resultSuccess, numberElement);
    
}

%simulate ApplyQuantumSearch

%version

