Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(bb): constexpr simplifications #7906

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 0 additions & 71 deletions barretenberg/cpp/src/barretenberg/common/constexpr_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@
#include <tuple>
#include <utility>

/**
* @brief constexpr_utils defines some helper methods that perform some stl-equivalent operations
* but in a constexpr context over quantities known at compile-time
*
* Current methods are:
*
* constexpr_for : loop over a range , where the size_t iterator `i` is a constexpr variable
* constexpr_find : find if an element is in an array
*/
namespace bb {

/**
Expand Down Expand Up @@ -97,66 +88,4 @@ template <size_t Start, size_t End, size_t Inc, class F> constexpr void constexp
}
}

/**
* @brief returns true/false depending on whether `key` is in `container`
*
* @tparam container i.e. what are we looking in?
* @tparam key i.e. what are we looking for?
* @return true found!
* @return false not found!
*
* @details method is constexpr and can be used in static_asserts
*/
template <const auto& container, auto key> constexpr bool constexpr_find()
{
// using ElementType = typename std::remove_extent<ContainerType>::type;
bool found = false;
constexpr_for<0, container.size(), 1>([&]<size_t k>() {
if constexpr (std::get<k>(container) == key) {
found = true;
}
});
return found;
}

/**
* @brief Create a constexpr array object whose elements contain a default value
*
* @tparam T type contained in the array
* @tparam Is index sequence
* @param value the value each array element is being initialized to
* @return constexpr std::array<T, sizeof...(Is)>
*
* @details This method is used to create constexpr arrays whose encapsulated type:
*
* 1. HAS NO CONSTEXPR DEFAULT CONSTRUCTOR
* 2. HAS A CONSTEXPR COPY CONSTRUCTOR
*
* An example of this is bb::field_t
* (the default constructor does not default assign values to the field_t member variables for efficiency reasons, to
* reduce the time require to construct large arrays of field elements. This means the default constructor for field_t
* cannot be constexpr)
*/
template <typename T, std::size_t... Is>
constexpr std::array<T, sizeof...(Is)> create_array(T value, std::index_sequence<Is...> /*unused*/)
{
// cast Is to void to remove the warning: unused value
std::array<T, sizeof...(Is)> result = { { (static_cast<void>(Is), value)... } };
return result;
}

/**
* @brief Create a constexpr array object whose values all are 0
*
* @tparam T
* @tparam N
* @return constexpr std::array<T, N>
*
* @details Use in the same context as create_array, i.e. when encapsulated type has a default constructor that is not
* constexpr
*/
template <typename T, size_t N> constexpr std::array<T, N> create_empty_array()
{
return create_array(T(0), std::make_index_sequence<N>());
}
}; // namespace bb
156 changes: 52 additions & 104 deletions barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,90 +262,49 @@ auto get_unshifted_then_shifted(const auto& all_entities)
return concatenate(all_entities.get_unshifted(), all_entities.get_shifted());
};

template <typename Tuple, size_t... I>
static constexpr auto _compute_max_partial_relation_length_internal([[maybe_unused]] std::index_sequence<I...>)
{
constexpr std::array<size_t, sizeof...(I)> lengths = { std::tuple_element_t<I, Tuple>::RELATION_LENGTH... };
return *std::max_element(lengths.begin(), lengths.end());
}

/**
* @brief Utility function to find max PARTIAL_RELATION_LENGTH tuples of Relations.
* @details The "partial length" of a relation is 1 + the degree of the relation, where any challenges used in the
* relation are as constants, not as variables..
*/
template <typename Tuple, std::size_t Index = 0> static constexpr size_t compute_max_partial_relation_length()
{
return _compute_max_partial_relation_length_internal<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

template <typename Tuple, size_t... I>
static constexpr auto _compute_max_total_relation_length_internal([[maybe_unused]] std::index_sequence<I...>)
template <typename Tuple, bool ZK = false> constexpr size_t compute_max_partial_relation_length()
{
constexpr std::array<size_t, sizeof...(I)> lengths = { std::tuple_element_t<I, Tuple>::TOTAL_RELATION_LENGTH... };
return *std::max_element(lengths.begin(), lengths.end());
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<std::size_t... Is>(std::index_sequence<Is...>) {
if constexpr (ZK) {
return std::max({ std::tuple_element_t<Is, Tuple>::ZK_RELATION_LENGTH... });
} else {
return std::max({ std::tuple_element_t<Is, Tuple>::RELATION_LENGTH... });
}
}(seq);
}

/**
* @brief Utility function to find max TOTAL_RELATION_LENGTH among tuples of Relations.
* @details The "total length" of a relation is 1 + the degree of the relation, where any challenges used in the
* relation are regarded as variables.
*/
template <typename Tuple> static constexpr size_t compute_max_total_relation_length()
{
return _compute_max_total_relation_length_internal<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

template <typename Tuple, size_t... I>
static constexpr auto _compute_number_of_subrelations_internal([[maybe_unused]] std::index_sequence<I...>)
template <typename Tuple, bool ZK = false> constexpr size_t compute_max_total_relation_length()
{
constexpr std::array<size_t, sizeof...(I)> lengths = {
std::tuple_element_t<I, Tuple>::SUBRELATION_PARTIAL_LENGTHS.size()...
};
return std::accumulate(lengths.begin(), lengths.end(), 0);
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<std::size_t... Is>(std::index_sequence<Is...>) {
if constexpr (ZK) {
return std::max({ std::tuple_element_t<Is, Tuple>::ZK_TOTAL_RELATION_LENGTH... });
} else {
return std::max({ std::tuple_element_t<Is, Tuple>::TOTAL_RELATION_LENGTH... });
}
}(seq);
}

/**
* @brief Utility function to find the number of subrelations.
*/
template <typename Tuple> static constexpr size_t compute_number_of_subrelations()
{
return _compute_number_of_subrelations_internal<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

template <typename Tuple, size_t NUM_INSTANCES, bool optimised = false, size_t... I>
static constexpr auto _create_protogalaxy_tuple_of_tuples_of_univariates_internal(
[[maybe_unused]] std::index_sequence<I...>)
template <typename Tuple> constexpr size_t compute_number_of_subrelations()
{
if constexpr (optimised) {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::template OptimisedProtogalaxyTupleOfUnivariatesOverSubrelations<
NUM_INSTANCES>{}...);
} else {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::template ProtogalaxyTupleOfUnivariatesOverSubrelations<
NUM_INSTANCES>{}...);
}
}

/**
* @brief Takes a Tuple of objects in the Relation class and recursively computes the maximum among partial
* subrelation lengths incremented by corresponding subrelation witness degrees over all
* subrelations of given relations. This method is required to compute the size of
* Round Univariates in ZK Sumcheck.
* @tparam Tuple
* @tparam Index
* @return constexpr size_t
*/
template <typename Tuple, std::size_t Index = 0> static constexpr size_t compute_max_total_zk_relation_length()
{
if constexpr (Index >= std::tuple_size<Tuple>::value) {
return 0; // Return 0 when reach end of the tuple
} else {
constexpr size_t current_zk_length = std::tuple_element<Index, Tuple>::type::ZK_TOTAL_RELATION_LENGTH;
constexpr size_t next_zk_length = compute_max_total_zk_relation_length<Tuple, Index + 1>();
return (current_zk_length > next_zk_length) ? current_zk_length : next_zk_length;
}
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<std::size_t... I>(std::index_sequence<I...>) {
return (0 + ... + std::tuple_element_t<I, Tuple>::SUBRELATION_PARTIAL_LENGTHS.size());
}(seq);
}

/**
Expand All @@ -356,64 +315,53 @@ template <typename Tuple, std::size_t Index = 0> static constexpr size_t compute
* @tparam optimised Enable optimised version with skipping some of the computation
*/
template <typename Tuple, size_t NUM_INSTANCES, bool optimised = false>
static constexpr auto create_protogalaxy_tuple_of_tuples_of_univariates()
{
return _create_protogalaxy_tuple_of_tuples_of_univariates_internal<Tuple, NUM_INSTANCES, optimised>(
std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

template <typename Tuple, size_t... I>
static constexpr auto _create_sumcheck_tuple_of_tuples_of_univariates_internal(
[[maybe_unused]] std::index_sequence<I...>)
constexpr auto create_protogalaxy_tuple_of_tuples_of_univariates()
{
return std::make_tuple(typename std::tuple_element_t<I, Tuple>::SumcheckTupleOfUnivariatesOverSubrelations{}...);
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<size_t... I>(std::index_sequence<I...>) {
if constexpr (optimised) {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::
template OptimisedProtogalaxyTupleOfUnivariatesOverSubrelations<NUM_INSTANCES>{}...);
} else {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::template ProtogalaxyTupleOfUnivariatesOverSubrelations<
NUM_INSTANCES>{}...);
}
}(seq);
}

template <typename Tuple, size_t... I>
static constexpr auto _create_zk_sumcheck_tuple_of_tuples_of_univariates_internal(
[[maybe_unused]] std::index_sequence<I...>)
{
return std::make_tuple(typename std::tuple_element_t<I, Tuple>::ZKSumcheckTupleOfUnivariatesOverSubrelations{}...);
}
/**
* @brief Utility function to construct a container for the subrelation accumulators of sumcheck proving.
* @details The size of the outer tuple is equal to the number of relations. Each relation contributes an inner tuple of
* univariates whose size is equal to the number of subrelations of the relation. The length of a univariate in an inner
* tuple is determined by the corresponding subrelation length.
*/
template <typename Tuple> static constexpr auto create_sumcheck_tuple_of_tuples_of_univariates()
template <typename Tuple, bool ZK = false> constexpr auto create_sumcheck_tuple_of_tuples_of_univariates()
{
return _create_sumcheck_tuple_of_tuples_of_univariates_internal<Tuple>(
std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

/**
* @brief Recursive utility function to construct a container for the subrelation accumulators of ZK Sumcheck prover.
* @details The size of the outer tuple is equal to the number of relations. Each relation contributes an inner tuple of
* univariates whose size is equal to the number of subrelations of the relation. The length of a univariate in an inner
* tuple is determined by the corresponding zk subrelation length, i.e. by the subrelation partial length corrected by
* the corresponding witness degree.
*/
template <typename Tuple> static constexpr auto create_zk_sumcheck_tuple_of_tuples_of_univariates()
{
return _create_zk_sumcheck_tuple_of_tuples_of_univariates_internal<Tuple>(
std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

template <typename Tuple, size_t... I>
static constexpr auto _create_tuple_of_arrays_of_values_internal([[maybe_unused]] std::index_sequence<I...>)
{
return std::make_tuple(typename std::tuple_element_t<I, Tuple>::SumcheckArrayOfValuesOverSubrelations{}...);
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<size_t... I>(std::index_sequence<I...>) {
if constexpr (ZK) {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::ZKSumcheckTupleOfUnivariatesOverSubrelations{}...);
} else {
return std::make_tuple(
typename std::tuple_element_t<I, Tuple>::SumcheckTupleOfUnivariatesOverSubrelations{}...);
}
}(seq);
}

/**
* @brief Construct tuple of arrays
* @details Container for storing value of each identity in each relation. Each Relation contributes an array of
* length num-identities.
*/
template <typename Tuple> static constexpr auto create_tuple_of_arrays_of_values()
template <typename Tuple> constexpr auto create_tuple_of_arrays_of_values()
{
return _create_tuple_of_arrays_of_values_internal<Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>());
constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Tuple>>();
return []<size_t... I>(std::index_sequence<I...>) {
return std::make_tuple(typename std::tuple_element_t<I, Tuple>::SumcheckArrayOfValuesOverSubrelations{}...);
}(seq);
}

} // namespace bb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp"

namespace bb {

/*!
\brief Child class of UltraFlavor that runs with ZK Sumcheck.
\details
Expand All @@ -16,19 +17,20 @@ univariate accumuluator size has to be increased by the subrelation's witness de
\ref docs/src/sumcheck-outline.md "Sumcheck Outline".
*/
class UltraFlavorWithZK : public bb::UltraFlavor {

public:
// This flavor runs with ZK Sumcheck
static constexpr bool HasZK = true;
// Compute the maximum over all partial subrelation lengths incremented by the corresponding subrelation witness
// degrees for the Relations inherited from UltraFlavor
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_total_zk_relation_length<Relations>();
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_total_relation_length<Relations, HasZK>();
// Determine the number of evaluations of Prover and Libra Polynomials that the Prover sends to the Verifier in
// the rounds of ZK Sumcheck.
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1;
// Construct the container for the subrelations' contributions
using SumcheckTupleOfTuplesOfUnivariates = decltype(create_zk_sumcheck_tuple_of_tuples_of_univariates<Relations>());
using SumcheckTupleOfTuplesOfUnivariates =
decltype(create_sumcheck_tuple_of_tuples_of_univariates<Relations, HasZK>());
// Re-define ExtendedEdges to account for the incremented MAX_PARTIAL_RELATION_LENGTH
using ExtendedEdges = ProverUnivariates<MAX_PARTIAL_RELATION_LENGTH>;
};

} // namespace bb
Loading