update boost on linux
This commit is contained in:
@@ -15,14 +15,16 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/suffix.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#endif
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/tools/real_cast.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/binomial.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/math/tools/detail/is_const_iterable.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
@@ -197,7 +199,7 @@ division(polynomial<T> u, const polynomial<T>& v)
|
||||
BOOST_ASSERT(u);
|
||||
|
||||
typedef typename polynomial<T>::size_type N;
|
||||
|
||||
|
||||
N const m = u.size() - 1, n = v.size() - 1;
|
||||
N k = m - n;
|
||||
polynomial<T> q;
|
||||
@@ -213,13 +215,35 @@ division(polynomial<T> u, const polynomial<T>& v)
|
||||
return std::make_pair(q, u);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct identity
|
||||
//
|
||||
// These structures are the same as the void specializations of the functors of the same name
|
||||
// in the std lib from C++14 onwards:
|
||||
//
|
||||
struct negate
|
||||
{
|
||||
T operator()(T const &x) const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
template <class T>
|
||||
T operator()(T const &x) const
|
||||
{
|
||||
return -x;
|
||||
}
|
||||
};
|
||||
|
||||
struct plus
|
||||
{
|
||||
template <class T, class U>
|
||||
T operator()(T const &x, U const& y) const
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
};
|
||||
|
||||
struct minus
|
||||
{
|
||||
template <class T, class U>
|
||||
T operator()(T const &x, U const& y) const
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -255,12 +279,7 @@ quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
|
||||
|
||||
|
||||
template <class T>
|
||||
class polynomial :
|
||||
equality_comparable< polynomial<T>,
|
||||
dividable< polynomial<T>,
|
||||
dividable2< polynomial<T>, T,
|
||||
modable< polynomial<T>,
|
||||
modable2< polynomial<T>, T > > > > >
|
||||
class polynomial
|
||||
{
|
||||
public:
|
||||
// typedefs:
|
||||
@@ -284,13 +303,26 @@ public:
|
||||
normalize();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
polynomial(std::vector<T>&& p) : m_data(std::move(p))
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class U>
|
||||
explicit polynomial(const U& point)
|
||||
explicit polynomial(const U& point, typename boost::enable_if<boost::is_convertible<U, T> >::type* = 0)
|
||||
{
|
||||
if (point != U(0))
|
||||
m_data.push_back(point);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
// move:
|
||||
polynomial(polynomial&& p) BOOST_NOEXCEPT
|
||||
: m_data(std::move(p.m_data)) { }
|
||||
#endif
|
||||
|
||||
// copy:
|
||||
polynomial(const polynomial& p)
|
||||
: m_data(p.m_data) { }
|
||||
@@ -298,17 +330,24 @@ public:
|
||||
template <class U>
|
||||
polynomial(const polynomial<U>& p)
|
||||
{
|
||||
m_data.resize(p.size());
|
||||
for(unsigned i = 0; i < p.size(); ++i)
|
||||
{
|
||||
m_data.push_back(boost::math::tools::real_cast<T>(p[i]));
|
||||
m_data[i] = boost::math::tools::real_cast<T>(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_MATH_HAS_IS_CONST_ITERABLE
|
||||
template <class Range>
|
||||
explicit polynomial(const Range& r, typename boost::enable_if<boost::math::tools::detail::is_const_iterable<Range> >::type* = 0)
|
||||
: polynomial(r.begin(), r.end())
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500)
|
||||
polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
polynomial&
|
||||
operator=(std::initializer_list<T> l)
|
||||
{
|
||||
@@ -320,26 +359,32 @@ public:
|
||||
|
||||
|
||||
// access:
|
||||
size_type size()const { return m_data.size(); }
|
||||
size_type degree()const
|
||||
size_type size() const { return m_data.size(); }
|
||||
size_type degree() const
|
||||
{
|
||||
if (size() == 0)
|
||||
throw std::logic_error("degree() is undefined for the zero polynomial.");
|
||||
return m_data.size() - 1;
|
||||
}
|
||||
}
|
||||
value_type& operator[](size_type i)
|
||||
{
|
||||
return m_data[i];
|
||||
}
|
||||
const value_type& operator[](size_type i)const
|
||||
const value_type& operator[](size_type i) const
|
||||
{
|
||||
return m_data[i];
|
||||
}
|
||||
T evaluate(T z)const
|
||||
|
||||
T evaluate(T z) const
|
||||
{
|
||||
return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size()) : 0;
|
||||
return this->operator()(z);
|
||||
}
|
||||
std::vector<T> chebyshev()const
|
||||
|
||||
T operator()(T z) const
|
||||
{
|
||||
return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size()) : T(0);
|
||||
}
|
||||
std::vector<T> chebyshev() const
|
||||
{
|
||||
return polynomial_to_chebyshev(m_data);
|
||||
}
|
||||
@@ -354,9 +399,48 @@ public:
|
||||
return m_data;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
polynomial<T> prime() const
|
||||
{
|
||||
if (m_data.size() == 0)
|
||||
{
|
||||
return polynomial<T>({});
|
||||
}
|
||||
|
||||
std::vector<T> p_data(m_data.size() - 1);
|
||||
for (size_t i = 0; i < p_data.size(); ++i) {
|
||||
p_data[i] = m_data[i+1]*static_cast<T>(i+1);
|
||||
}
|
||||
return polynomial<T>(std::move(p_data));
|
||||
}
|
||||
|
||||
polynomial<T> integrate() const
|
||||
{
|
||||
std::vector<T> i_data(m_data.size() + 1);
|
||||
// Choose integration constant such that P(0) = 0.
|
||||
i_data[0] = T(0);
|
||||
for (size_t i = 1; i < i_data.size(); ++i)
|
||||
{
|
||||
i_data[i] = m_data[i-1]/static_cast<T>(i);
|
||||
}
|
||||
return polynomial<T>(std::move(i_data));
|
||||
}
|
||||
|
||||
// operators:
|
||||
polynomial& operator =(polynomial&& p) BOOST_NOEXCEPT
|
||||
{
|
||||
m_data = std::move(p.m_data);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
polynomial& operator =(const polynomial& p)
|
||||
{
|
||||
m_data = p.m_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator +=(const U& value)
|
||||
typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
|
||||
{
|
||||
addition(value);
|
||||
normalize();
|
||||
@@ -364,7 +448,7 @@ public:
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator -=(const U& value)
|
||||
typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
|
||||
{
|
||||
subtraction(value);
|
||||
normalize();
|
||||
@@ -372,7 +456,7 @@ public:
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator *=(const U& value)
|
||||
typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
|
||||
{
|
||||
multiplication(value);
|
||||
normalize();
|
||||
@@ -380,7 +464,7 @@ public:
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator /=(const U& value)
|
||||
typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
|
||||
{
|
||||
division(value);
|
||||
normalize();
|
||||
@@ -388,7 +472,7 @@ public:
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator %=(const U& /*value*/)
|
||||
typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& /*value*/)
|
||||
{
|
||||
// We can always divide by a scalar, so there is no remainder:
|
||||
this->set_zero();
|
||||
@@ -410,20 +494,25 @@ public:
|
||||
normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename V>
|
||||
void multiply(const polynomial<U>& a, const polynomial<V>& b) {
|
||||
if (!a || !b)
|
||||
{
|
||||
this->set_zero();
|
||||
return;
|
||||
}
|
||||
std::vector<T> prod(a.size() + b.size() - 1, T(0));
|
||||
for (unsigned i = 0; i < a.size(); ++i)
|
||||
for (unsigned j = 0; j < b.size(); ++j)
|
||||
prod[i+j] += a.m_data[i] * b.m_data[j];
|
||||
m_data.swap(prod);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& operator *=(const polynomial<U>& value)
|
||||
{
|
||||
// TODO: FIXME: use O(N log(N)) algorithm!!!
|
||||
if (!value)
|
||||
{
|
||||
this->set_zero();
|
||||
return *this;
|
||||
}
|
||||
std::vector<T> prod(size() + value.size() - 1, T(0));
|
||||
for (size_type i = 0; i < value.size(); ++i)
|
||||
for (size_type j = 0; j < size(); ++j)
|
||||
prod[i+j] += m_data[j] * value[i];
|
||||
m_data.swap(prod);
|
||||
this->multiply(*this, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -456,13 +545,13 @@ public:
|
||||
normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Convenient and efficient query for zero.
|
||||
bool is_zero() const
|
||||
{
|
||||
return m_data.empty();
|
||||
}
|
||||
|
||||
|
||||
// Conversion to bool.
|
||||
#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
|
||||
typedef bool (polynomial::*unmentionable_type)() const;
|
||||
@@ -483,74 +572,84 @@ public:
|
||||
{
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
|
||||
/** Remove zero coefficients 'from the top', that is for which there are no
|
||||
* non-zero coefficients of higher degree. */
|
||||
void normalize()
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_LAMBDAS
|
||||
m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != T(0); }).base(), m_data.end());
|
||||
#else
|
||||
using namespace boost::lambda;
|
||||
m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), _1 != T(0)).base(), m_data.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
template <class U, class R1, class R2>
|
||||
polynomial& addition(const U& value, R1 sign, R2 op)
|
||||
template <class U, class R>
|
||||
polynomial& addition(const U& value, R op)
|
||||
{
|
||||
if(m_data.size() == 0)
|
||||
m_data.push_back(sign(value));
|
||||
else
|
||||
m_data[0] = op(m_data[0], value);
|
||||
m_data.resize(1, 0);
|
||||
m_data[0] = op(m_data[0], value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& addition(const U& value)
|
||||
{
|
||||
return addition(value, detail::identity<U>(), std::plus<U>());
|
||||
return addition(value, detail::plus());
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& subtraction(const U& value)
|
||||
{
|
||||
return addition(value, std::negate<U>(), std::minus<U>());
|
||||
return addition(value, detail::minus());
|
||||
}
|
||||
|
||||
template <class U, class R1, class R2>
|
||||
polynomial& addition(const polynomial<U>& value, R1 sign, R2 op)
|
||||
template <class U, class R>
|
||||
polynomial& addition(const polynomial<U>& value, R op)
|
||||
{
|
||||
size_type s1 = (std::min)(m_data.size(), value.size());
|
||||
for(size_type i = 0; i < s1; ++i)
|
||||
if (m_data.size() < value.size())
|
||||
m_data.resize(value.size(), 0);
|
||||
for(size_type i = 0; i < value.size(); ++i)
|
||||
m_data[i] = op(m_data[i], value[i]);
|
||||
for(size_type i = s1; i < value.size(); ++i)
|
||||
m_data.push_back(sign(value[i]));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& addition(const polynomial<U>& value)
|
||||
{
|
||||
return addition(value, detail::identity<U>(), std::plus<U>());
|
||||
return addition(value, detail::plus());
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& subtraction(const polynomial<U>& value)
|
||||
{
|
||||
return addition(value, std::negate<U>(), std::minus<U>());
|
||||
return addition(value, detail::minus());
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& multiplication(const U& value)
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_LAMBDAS
|
||||
std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
|
||||
#else
|
||||
using namespace boost::lambda;
|
||||
std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 * value));
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
polynomial& division(const U& value)
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_LAMBDAS
|
||||
std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
|
||||
#else
|
||||
using namespace boost::lambda;
|
||||
std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 / value));
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -565,6 +664,26 @@ inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
|
||||
{
|
||||
a += b;
|
||||
return a;
|
||||
}
|
||||
template <class T>
|
||||
inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
|
||||
{
|
||||
b += a;
|
||||
return b;
|
||||
}
|
||||
template <class T>
|
||||
inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
|
||||
{
|
||||
a += b;
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
|
||||
@@ -573,61 +692,101 @@ inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
|
||||
result -= b;
|
||||
return result;
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
|
||||
{
|
||||
a -= b;
|
||||
return a;
|
||||
}
|
||||
template <class T>
|
||||
inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
|
||||
{
|
||||
b -= a;
|
||||
return -b;
|
||||
}
|
||||
template <class T>
|
||||
inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
|
||||
{
|
||||
a -= b;
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result *= b;
|
||||
polynomial<T> result;
|
||||
result.multiply(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
|
||||
{
|
||||
return quotient_remainder(a, b).first;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
|
||||
{
|
||||
return quotient_remainder(a, b).second;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline polynomial<T> operator + (const polynomial<T>& a, const U& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result += b;
|
||||
return result;
|
||||
a += b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline polynomial<T> operator - (const polynomial<T>& a, const U& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result -= b;
|
||||
return result;
|
||||
a -= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline polynomial<T> operator * (const polynomial<T>& a, const U& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result *= b;
|
||||
return result;
|
||||
a *= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
|
||||
{
|
||||
a /= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
|
||||
{
|
||||
// Since we can always divide by a scalar, result is always an empty polynomial:
|
||||
return polynomial<T>();
|
||||
}
|
||||
|
||||
template <class U, class T>
|
||||
inline polynomial<T> operator + (const U& a, const polynomial<T>& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
|
||||
{
|
||||
polynomial<T> result(b);
|
||||
result += a;
|
||||
return result;
|
||||
b += a;
|
||||
return b;
|
||||
}
|
||||
|
||||
template <class U, class T>
|
||||
inline polynomial<T> operator - (const U& a, const polynomial<T>& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result -= b;
|
||||
return result;
|
||||
b -= a;
|
||||
return -b;
|
||||
}
|
||||
|
||||
template <class U, class T>
|
||||
inline polynomial<T> operator * (const U& a, const polynomial<T>& b)
|
||||
inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
|
||||
{
|
||||
polynomial<T> result(b);
|
||||
result *= a;
|
||||
return result;
|
||||
b *= a;
|
||||
return b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -636,27 +795,31 @@ bool operator == (const polynomial<T> &a, const polynomial<T> &b)
|
||||
return a.data() == b.data();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
polynomial<T> operator >> (const polynomial<T>& a, const U& b)
|
||||
template <class T>
|
||||
bool operator != (const polynomial<T> &a, const polynomial<T> &b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result >>= b;
|
||||
return result;
|
||||
return a.data() != b.data();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
polynomial<T> operator << (const polynomial<T>& a, const U& b)
|
||||
polynomial<T> operator >> (polynomial<T> a, const U& b)
|
||||
{
|
||||
polynomial<T> result(a);
|
||||
result <<= b;
|
||||
return result;
|
||||
a >>= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
polynomial<T> operator << (polynomial<T> a, const U& b)
|
||||
{
|
||||
a <<= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
// Unary minus (negate).
|
||||
template <class T>
|
||||
polynomial<T> operator - (polynomial<T> a)
|
||||
{
|
||||
std::transform(a.data().begin(), a.data().end(), a.data().begin(), std::negate<T>());
|
||||
std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -713,7 +876,9 @@ inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT,
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
//
|
||||
// Polynomial specific overload of gcd algorithm:
|
||||
//
|
||||
#include <boost/math/tools/polynomial_gcd.hpp>
|
||||
|
||||
#endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user