2 *****************************************************************************
4 Implementation of interfaces for a sparse vector.
6 See sparse_vector.hpp .
8 *****************************************************************************
9 * @author This file is part of libsnark, developed by SCIPR Lab
10 * and contributors (see AUTHORS).
11 * @copyright MIT license (see LICENSE file)
12 *****************************************************************************/
14 #ifndef SPARSE_VECTOR_TCC_
15 #define SPARSE_VECTOR_TCC_
23 #include <libff/algebra/scalar_multiplication/multiexp.hpp>
29 sparse_vector<T>::sparse_vector(std::vector<T> &&v)
30 : values(std::move(v)), domain_size_(values.size())
32 indices.resize(domain_size_);
33 std::iota(indices.begin(), indices.end(), 0);
36 template<typename T> T sparse_vector<T>::operator[](const size_t idx) const
38 auto it = std::lower_bound(indices.begin(), indices.end(), idx);
39 return (it != indices.end() && *it == idx) ? values[it - indices.begin()]
44 bool sparse_vector<T>::operator==(const sparse_vector<T> &other) const
46 if (this->domain_size_ != other.domain_size_) {
50 size_t this_pos = 0, other_pos = 0;
51 while (this_pos < this->indices.size() &&
52 other_pos < other.indices.size()) {
53 if (this->indices[this_pos] == other.indices[other_pos]) {
54 if (this->values[this_pos] != other.values[other_pos]) {
59 } else if (this->indices[this_pos] < other.indices[other_pos]) {
60 if (!this->values[this_pos].is_zero()) {
65 if (!other.values[other_pos].is_zero()) {
72 /* at least one of the vectors has been exhausted, so other must be empty */
73 while (this_pos < this->indices.size()) {
74 if (!this->values[this_pos].is_zero()) {
80 while (other_pos < other.indices.size()) {
81 if (!other.values[other_pos].is_zero()) {
91 bool sparse_vector<T>::operator==(const std::vector<T> &other) const
93 if (this->domain_size_ < other.size()) {
98 for (size_t i = 0; i < other.size(); ++i) {
99 if (this->indices[j] == i) {
100 if (this->values[j] != other[j]) {
105 if (!other[j].is_zero()) {
114 template<typename T> bool sparse_vector<T>::is_valid() const
116 if (values.size() == indices.size() && values.size() <= domain_size_) {
120 for (size_t i = 0; i + 1 < indices.size(); ++i) {
121 if (indices[i] >= indices[i + 1]) {
126 if (!indices.empty() && indices[indices.size() - 1] >= domain_size_) {
133 template<typename T> bool sparse_vector<T>::empty() const
135 return indices.empty();
138 template<typename T> size_t sparse_vector<T>::domain_size() const
143 template<typename T> size_t sparse_vector<T>::size() const
145 return indices.size();
148 template<typename T> size_t sparse_vector<T>::size_in_bits() const
150 return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits());
154 template<typename FieldT>
155 std::pair<T, sparse_vector<T>> sparse_vector<T>::accumulate(
156 const typename std::vector<FieldT>::const_iterator &it_begin,
157 const typename std::vector<FieldT>::const_iterator &it_end,
158 const size_t offset) const
161 // to override, set OMP_NUM_THREADS env var or call
162 // omp_set_num_threads()
163 const size_t chunks = omp_get_max_threads();
165 const size_t chunks = 1;
168 T accumulated_value = T::zero();
169 sparse_vector<T> resulting_vector;
170 resulting_vector.domain_size_ = domain_size_;
172 const size_t range_len = it_end - it_begin;
173 bool in_block = false;
175 // g++ -flto emits unitialized warning, even though in_block
176 // guards for such cases.
177 size_t first_pos = -1;
178 size_t last_pos = -1;
179 for (size_t i = 0; i < indices.size(); ++i) {
180 const bool matching_pos =
181 (offset <= indices[i] && indices[i] < offset + range_len);
182 // printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i,
183 // indices[i], offset, w_size);
187 if (matching_pos && last_pos == i - 1) {
188 // block can be extended, do it
192 // block has ended here
197 libff::print_indent();
199 "doing multiexp for w_%zu ... w_%zu\n",
208 libff::multi_exp_method_bos_coster>(
209 values.begin() + first_pos,
210 values.begin() + last_pos + 1,
211 it_begin + (indices[first_pos] - offset),
212 it_begin + (indices[last_pos] - offset) + 1,
217 // block can be started
228 resulting_vector.indices.emplace_back(indices[i]);
229 resulting_vector.values.emplace_back(values[i]);
235 libff::print_indent();
237 "doing multiexp for w_%zu ... w_%zu\n",
243 libff::multi_exp<T, FieldT, libff::multi_exp_method_bos_coster>(
244 values.begin() + first_pos,
245 values.begin() + last_pos + 1,
246 it_begin + (indices[first_pos] - offset),
247 it_begin + (indices[last_pos] - offset) + 1,
251 return std::make_pair(accumulated_value, resulting_vector);
255 std::ostream &operator<<(std::ostream &out, const sparse_vector<T> &v)
257 out << v.domain_size_ << "\n";
258 out << v.indices.size() << "\n";
259 for (const size_t &i : v.indices) {
263 out << v.values.size() << "\n";
264 for (const T &t : v.values) {
265 out << t << OUTPUT_NEWLINE;
272 std::istream &operator>>(std::istream &in, sparse_vector<T> &v)
274 in >> v.domain_size_;
275 libff::consume_newline(in);
279 libff::consume_newline(in);
281 for (size_t i = 0; i < s; ++i) {
283 libff::consume_newline(in);
288 libff::consume_newline(in);
291 for (size_t i = 0; i < s; ++i) {
294 libff::consume_OUTPUT_NEWLINE(in);
295 v.values.emplace_back(t);
301 } // namespace libsnark
303 #endif // SPARSE_VECTOR_TCC_