You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

316 lines
8.2 KiB

/** @file
*****************************************************************************
Implementation of interfaces for a sparse vector.
See sparse_vector.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SPARSE_VECTOR_TCC_
#define SPARSE_VECTOR_TCC_
#include "algebra/scalar_multiplication/multiexp.hpp"
#include <numeric>
namespace libsnark {
template<typename T>
sparse_vector<T>::sparse_vector(std::vector<T> &&v) :
values(std::move(v)), domain_size_(values.size())
{
indices.resize(domain_size_);
std::iota(indices.begin(), indices.end(), 0);
}
template<typename T>
T sparse_vector<T>::operator[](const size_t idx) const
{
auto it = std::lower_bound(indices.begin(), indices.end(), idx);
return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T();
}
template<typename T>
bool sparse_vector<T>::operator==(const sparse_vector<T> &other) const
{
if (this->domain_size_ != other.domain_size_)
{
return false;
}
size_t this_pos = 0, other_pos = 0;
while (this_pos < this->indices.size() && other_pos < other.indices.size())
{
if (this->indices[this_pos] == other.indices[other_pos])
{
if (this->values[this_pos] != other.values[other_pos])
{
return false;
}
++this_pos;
++other_pos;
}
else if (this->indices[this_pos] < other.indices[other_pos])
{
if (!this->values[this_pos].is_zero())
{
return false;
}
++this_pos;
}
else
{
if (!other.values[other_pos].is_zero())
{
return false;
}
++other_pos;
}
}
/* at least one of the vectors has been exhausted, so other must be empty */
while (this_pos < this->indices.size())
{
if (!this->values[this_pos].is_zero())
{
return false;
}
++this_pos;
}
while (other_pos < other.indices.size())
{
if (!other.values[other_pos].is_zero())
{
return false;
}
++other_pos;
}
return true;
}
template<typename T>
bool sparse_vector<T>::operator==(const std::vector<T> &other) const
{
if (this->domain_size_ < other.size())
{
return false;
}
size_t j = 0;
for (size_t i = 0; i < other.size(); ++i)
{
if (this->indices[j] == i)
{
if (this->values[j] != other[j])
{
return false;
}
++j;
}
else
{
if (!other[j].is_zero())
{
return false;
}
}
}
return true;
}
template<typename T>
bool sparse_vector<T>::is_valid() const
{
if (values.size() == indices.size() && values.size() <= domain_size_)
{
return false;
}
for (size_t i = 0; i + 1 < indices.size(); ++i)
{
if (indices[i] >= indices[i+1])
{
return false;
}
}
if (!indices.empty() && indices[indices.size()-1] >= domain_size_)
{
return false;
}
return true;
}
template<typename T>
bool sparse_vector<T>::empty() const
{
return indices.empty();
}
template<typename T>
size_t sparse_vector<T>::domain_size() const
{
return domain_size_;
}
template<typename T>
size_t sparse_vector<T>::size() const
{
return indices.size();
}
template<typename T>
size_t sparse_vector<T>::size_in_bits() const
{
return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits());
}
template<typename T>
template<typename FieldT>
std::pair<T, sparse_vector<T> > sparse_vector<T>::accumulate(const typename std::vector<FieldT>::const_iterator &it_begin,
const typename std::vector<FieldT>::const_iterator &it_end,
const size_t offset) const
{
// TODO: does not really belong here.
const size_t chunks = 1;
const bool use_multiexp = true;
T accumulated_value = T::zero();
sparse_vector<T> resulting_vector;
resulting_vector.domain_size_ = domain_size_;
const size_t range_len = it_end - it_begin;
bool in_block = false;
size_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases.
for (size_t i = 0; i < indices.size(); ++i)
{
const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len);
// printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size);
bool copy_over;
if (in_block)
{
if (matching_pos && last_pos == i-1)
{
// block can be extended, do it
last_pos = i;
copy_over = false;
}
else
{
// block has ended here
in_block = false;
copy_over = true;
#ifdef DEBUG
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
#endif
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
values.begin() + last_pos + 1,
it_begin + (indices[first_pos] - offset),
it_begin + (indices[last_pos] - offset) + 1,
chunks, use_multiexp);
}
}
else
{
if (matching_pos)
{
// block can be started
first_pos = i;
last_pos = i;
in_block = true;
copy_over = false;
}
else
{
copy_over = true;
}
}
if (copy_over)
{
resulting_vector.indices.emplace_back(indices[i]);
resulting_vector.values.emplace_back(values[i]);
}
}
if (in_block)
{
#ifdef DEBUG
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
#endif
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
values.begin() + last_pos + 1,
it_begin + (indices[first_pos] - offset),
it_begin + (indices[last_pos] - offset) + 1,
chunks, use_multiexp);
}
return std::make_pair(accumulated_value, resulting_vector);
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const sparse_vector<T> &v)
{
out << v.domain_size_ << "\n";
out << v.indices.size() << "\n";
for (const size_t& i : v.indices)
{
out << i << "\n";
}
out << v.values.size() << "\n";
for (const T& t : v.values)
{
out << t << OUTPUT_NEWLINE;
}
return out;
}
template<typename T>
std::istream& operator>>(std::istream& in, sparse_vector<T> &v)
{
in >> v.domain_size_;
consume_newline(in);
size_t s;
in >> s;
consume_newline(in);
v.indices.resize(s);
for (size_t i = 0; i < s; ++i)
{
in >> v.indices[i];
consume_newline(in);
}
v.values.clear();
in >> s;
consume_newline(in);
v.values.reserve(s);
for (size_t i = 0; i < s; ++i)
{
T t;
in >> t;
consume_OUTPUT_NEWLINE(in);
v.values.emplace_back(t);
}
return in;
}
} // libsnark
#endif // SPARSE_VECTOR_TCC_