/** * A bunch of cases in which a geo expression is equivalent() to both itself or to another * expression. */ TEST(ExpressionGeoTest, GeoEquivalent) { { BSONObj query = fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}"); std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query)); ASSERT(ge->equivalent(ge.get())); } { BSONObj query = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"); std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query)); ASSERT(ge->equivalent(ge.get())); } { BSONObj query1 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"), query2 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"); std::unique_ptr<GeoMatchExpression> ge1(makeGeoMatchExpression(query1)), ge2(makeGeoMatchExpression(query2)); ASSERT(ge1->equivalent(ge2.get())); } }
template<typename Scalar> void trmm(int size,int /*othersize*/) { typedef typename NumTraits<Scalar>::Real RealScalar; typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> MatrixColMaj; typedef Matrix<Scalar,Dynamic,Dynamic,RowMajor> MatrixRowMaj; DenseIndex rows = size; DenseIndex cols = ei_random<DenseIndex>(1,size); MatrixColMaj triV(rows,cols), triH(cols,rows), upTri(cols,rows), loTri(rows,cols), unitUpTri(cols,rows), unitLoTri(rows,cols), strictlyUpTri(cols,rows), strictlyLoTri(rows,cols); MatrixColMaj ge1(rows,cols), ge2(cols,rows), ge3; MatrixRowMaj rge3; Scalar s1 = ei_random<Scalar>(), s2 = ei_random<Scalar>(); triV.setRandom(); triH.setRandom(); loTri = triV.template triangularView<Lower>(); upTri = triH.template triangularView<Upper>(); unitLoTri = triV.template triangularView<UnitLower>(); unitUpTri = triH.template triangularView<UnitUpper>(); strictlyLoTri = triV.template triangularView<StrictlyLower>(); strictlyUpTri = triH.template triangularView<StrictlyUpper>(); ge1.setRandom(); ge2.setRandom(); VERIFY_IS_APPROX( ge3 = triV.template triangularView<Lower>() * ge2, loTri * ge2); VERIFY_IS_APPROX( ge3 = ge2 * triV.template triangularView<Lower>(), ge2 * loTri); VERIFY_IS_APPROX( ge3 = triH.template triangularView<Upper>() * ge1, upTri * ge1); VERIFY_IS_APPROX( ge3 = ge1 * triH.template triangularView<Upper>(), ge1 * upTri); VERIFY_IS_APPROX( ge3 = (s1*triV.adjoint()).template triangularView<Upper>() * (s2*ge1), s1*loTri.adjoint() * (s2*ge1)); VERIFY_IS_APPROX( ge3 = ge1 * triV.adjoint().template triangularView<Upper>(), ge1 * loTri.adjoint()); VERIFY_IS_APPROX( ge3 = triH.adjoint().template triangularView<Lower>() * ge2, upTri.adjoint() * ge2); VERIFY_IS_APPROX( ge3 = ge2 * triH.adjoint().template triangularView<Lower>(), ge2 * upTri.adjoint()); VERIFY_IS_APPROX( ge3 = triV.template triangularView<Lower>() * ge1.adjoint(), loTri * ge1.adjoint()); VERIFY_IS_APPROX( ge3 = ge1.adjoint() * triV.template triangularView<Lower>(), ge1.adjoint() * loTri); VERIFY_IS_APPROX( ge3 = triH.template triangularView<Upper>() * ge2.adjoint(), upTri * ge2.adjoint()); VERIFY_IS_APPROX(rge3.noalias() = triH.template triangularView<Upper>() * ge2.adjoint(), upTri * ge2.adjoint()); VERIFY_IS_APPROX( ge3 = (s1*triV).adjoint().template triangularView<Upper>() * ge2.adjoint(), ei_conj(s1) * loTri.adjoint() * ge2.adjoint()); VERIFY_IS_APPROX(rge3.noalias() = triV.adjoint().template triangularView<Upper>() * ge2.adjoint(), loTri.adjoint() * ge2.adjoint()); VERIFY_IS_APPROX( ge3 = triH.adjoint().template triangularView<Lower>() * ge1.adjoint(), upTri.adjoint() * ge1.adjoint()); VERIFY_IS_APPROX(rge3.noalias() = triH.adjoint().template triangularView<Lower>() * ge1.adjoint(), upTri.adjoint() * ge1.adjoint()); VERIFY_IS_APPROX( ge3 = triV.template triangularView<UnitLower>() * ge2, unitLoTri * ge2); VERIFY_IS_APPROX( rge3.noalias() = ge2 * triV.template triangularView<UnitLower>(), ge2 * unitLoTri); VERIFY_IS_APPROX( ge3 = ge2 * triV.template triangularView<UnitLower>(), ge2 * unitLoTri); VERIFY_IS_APPROX( ge3 = (s1*triV).adjoint().template triangularView<UnitUpper>() * ge2.adjoint(), ei_conj(s1) * unitLoTri.adjoint() * ge2.adjoint()); VERIFY_IS_APPROX( ge3 = triV.template triangularView<StrictlyLower>() * ge2, strictlyLoTri * ge2); VERIFY_IS_APPROX( rge3.noalias() = ge2 * triV.template triangularView<StrictlyLower>(), ge2 * strictlyLoTri); VERIFY_IS_APPROX( ge3 = ge2 * triV.template triangularView<StrictlyLower>(), ge2 * strictlyLoTri); VERIFY_IS_APPROX( ge3 = (s1*triV).adjoint().template triangularView<StrictlyUpper>() * ge2.adjoint(), ei_conj(s1) * strictlyLoTri.adjoint() * ge2.adjoint()); }
smt_astt smt_convt::overflow_arith(const expr2tc &expr) { // If in integer mode, this is completely pointless. Return false. if (int_encoding) return mk_smt_bool(false); const overflow2t &overflow = to_overflow2t(expr); const arith_2ops &opers = static_cast<const arith_2ops &>(*overflow.operand); assert(opers.side_1->type == opers.side_2->type); constant_int2tc zero(opers.side_1->type, BigInt(0)); lessthan2tc op1neg(opers.side_1, zero); lessthan2tc op2neg(opers.side_2, zero); equality2tc op1iszero(opers.side_1, zero); equality2tc op2iszero(opers.side_2, zero); or2tc containszero(op1iszero, op2iszero); // Guess whether we're performing a signed or unsigned comparison. bool is_signed = (is_signedbv_type(opers.side_1) || is_signedbv_type(opers.side_2)); if (is_add2t(overflow.operand)) { if (is_signed) { // Two cases: pos/pos, and neg/neg, which can over and underflow resp. // In pos/neg cases, no overflow or underflow is possible, for any value. constant_int2tc zero(opers.side_1->type, BigInt(0)); lessthan2tc op1pos(zero, opers.side_1); lessthan2tc op2pos(zero, opers.side_2); and2tc both_pos(op1pos, op2pos); not2tc negop1(op1pos); not2tc negop2(op2pos); and2tc both_neg(negop1, negop2); implies2tc nooverflow(both_pos, greaterthanequal2tc(overflow.operand, zero)); implies2tc nounderflow(both_neg, lessthanequal2tc(overflow.operand, zero)); return convert_ast(not2tc(and2tc(nooverflow, nounderflow))); } else { // Just ensure the result is >= both operands. greaterthanequal2tc ge1(overflow.operand, opers.side_1); greaterthanequal2tc ge2(overflow.operand, opers.side_2); and2tc res(ge1, ge2); not2tc inv(res); return convert_ast(inv); } } else if (is_sub2t(overflow.operand)) { if (is_signed) { // Convert to be an addition neg2tc negop2(opers.side_2->type, opers.side_2); add2tc anadd(opers.side_1->type, opers.side_1, negop2); expr2tc add_overflows(new overflow2t(anadd)); // Corner case: subtracting MIN_INT from many things overflows. The result // should always be positive. constant_int2tc zero(opers.side_1->type, BigInt(0)); uint64_t topbit = 1ULL << (opers.side_1->type->get_width() - 1); constant_int2tc min_int(opers.side_1->type, BigInt(topbit)); equality2tc is_min_int(min_int, opers.side_2); implies2tc imp(is_min_int, greaterthan2tc(overflow.operand, zero)); return convert_ast(or2tc(add_overflows, is_min_int)); } else { // Just ensure the result is >= the operands. lessthanequal2tc le1(overflow.operand, opers.side_1); lessthanequal2tc le2(overflow.operand, opers.side_2); and2tc res(le1, le2); not2tc inv(res); return convert_ast(inv); } } else { assert(is_mul2t(overflow.operand) && "unexpected overflow_arith operand"); // Zero extend; multiply; Make a decision based on the top half. unsigned int sz = zero->type->get_width(); smt_sortt boolsort = boolean_sort; smt_sortt normalsort = mk_sort(SMT_SORT_BV, sz, false); smt_sortt bigsort = mk_sort(SMT_SORT_BV, sz * 2, false); // All one bit vector is tricky, might be 64 bits wide for all we know. constant_int2tc allonesexpr(zero->type, BigInt((sz == 64) ? 0xFFFFFFFFFFFFFFFFULL : ((1ULL << sz) - 1))); smt_astt allonesvector = convert_ast(allonesexpr); smt_astt arg1_ext, arg2_ext; if (is_signed) { // sign extend top bits. arg1_ext = convert_ast(opers.side_1); arg1_ext = convert_sign_ext(arg1_ext, bigsort, sz - 1, sz); arg2_ext = convert_ast(opers.side_2); arg2_ext = convert_sign_ext(arg2_ext, bigsort, sz - 1, sz); } else { // Zero extend the top parts arg1_ext = convert_ast(opers.side_1); arg1_ext = convert_zero_ext(arg1_ext, bigsort, sz); arg2_ext = convert_ast(opers.side_2); arg2_ext = convert_zero_ext(arg2_ext, bigsort, sz); } smt_astt result = mk_func_app(bigsort, SMT_FUNC_BVMUL, arg1_ext, arg2_ext); // Extract top half. smt_astt toppart = mk_extract(result, (sz * 2) - 1, sz, normalsort); if (is_signed) { // It should either be zero or all one's; which depends on what // configuration of signs it had. If both pos / both neg, then the top // should all be zeros, otherwise all ones. Implement with xor. smt_astt op1neg_ast = convert_ast(op1neg); smt_astt op2neg_ast = convert_ast(op2neg); smt_astt allonescond = mk_func_app(boolsort, SMT_FUNC_XOR, op1neg_ast, op2neg_ast); smt_astt zerovector = convert_ast(zero); smt_astt initial_switch = mk_func_app(normalsort, SMT_FUNC_ITE, allonescond, allonesvector, zerovector); // either value being zero means the top must be zero. smt_astt contains_zero_ast = convert_ast(containszero); smt_astt second_switch = mk_func_app(normalsort, SMT_FUNC_ITE, contains_zero_ast, zerovector, initial_switch); smt_astt is_eq = mk_func_app(boolsort, SMT_FUNC_EQ, second_switch, toppart); return mk_func_app(boolsort, SMT_FUNC_NOT, &is_eq, 1); } else { // It should be zero; if not, overflow smt_astt iseq = mk_func_app(boolsort, SMT_FUNC_EQ, toppart, convert_ast(zero)); return mk_func_app(boolsort, SMT_FUNC_NOT, &iseq, 1); } } return NULL; }