void ClauseAllocator::updateAllOffsetsAndPointers(
    Solver* solver
    , const vector<ClOffset>& offsets
) {
    //Must be at toplevel, otherwise propBy reset will not work
    //and also, detachReattacher will fail
    assert(solver->decisionLevel() == 0);

    //We are at decision level 0, so we can reset all PropBy-s
    for (auto& vdata: solver->varData) {
        vdata.reason = PropBy();
    }

    //Detach long clauses
    CompleteDetachReatacher detachReattach(solver);
    detachReattach.detach_nonbins_nontris();

    //Make sure all non-freed clauses were accessible from solver
    const size_t origNumClauses =
        solver->longIrredCls.size() + solver->longRedCls.size();
    if (origNumClauses != offsets.size()) {
        std::cerr
        << "ERROR: Not all non-freed clauses are accessible from Solver"
        << endl
        << " This usually means that a clause was not freed, i.e. a mem leak"
        << endl
        << " no. clauses accessible from solver: " << origNumClauses
        << endl
        << " no. clauses non-freed: " << offsets.size()
        << endl;

        assert(origNumClauses == offsets.size());
        std::exit(-1);
    }

    //Clear clauses
    solver->longIrredCls.clear();
    solver->longRedCls.clear();

    //Add back to the solver the correct red & irred clauses
    for(auto offset: offsets) {
        Clause* cl = ptr(offset);
        assert(!cl->freed());

        //Put it in the right bucket
        if (cl->red()) {
            solver->longRedCls.push_back(offset);
        } else {
            solver->longIrredCls.push_back(offset);
        }
    }

    //Finally, reattach long clauses
    detachReattach.reattachLongs();
}
Example #2
0
void CNF::find_all_attach() const
{
#ifdef SLOW_DEBUG
    for (size_t i = 0; i < watches.size(); i++) {
        const Lit lit = Lit::toLit(i);
        for (uint32_t i2 = 0; i2 < watches[lit].size(); i2++) {
            const Watched& w = watches[lit][i2];
            if (!w.isClause())
                continue;

            //Get clause
            Clause* cl = cl_alloc.ptr(w.get_offset());
            assert(!cl->freed());

            //Assert watch correctness
            if ((*cl)[0] != lit
                && (*cl)[1] != lit
            ) {
                std::cerr
                << "ERROR! Clause " << (*cl)
                << " not attached?"
                << endl;

                assert(false);
                std::exit(-1);
            }

            //Clause in one of the lists
            if (!find_clause(w.get_offset())) {
                std::cerr
                << "ERROR! did not find clause " << *cl
                << endl;

                assert(false);
                std::exit(1);
            }
        }
    }

    find_all_attach(longIrredCls);
    find_all_attach(longRedCls);
#endif
}
Example #3
0
Clause* BVA::find_cl_for_bva(
    const vector<Lit>& torem
    , const bool red
) const {
    Clause* cl = NULL;
    for(const Lit lit: torem) {
        seen[lit.toInt()] = 1;
    }
    for(Watched w: solver->watches[torem[0]]) {
        if (!w.isClause())
            continue;

        cl = solver->cl_alloc.ptr(w.get_offset());
        if (cl->red() != red
            || cl->size() != torem.size()
        ) {
            continue;
        }
        #ifdef SLOW_DEBUG
        assert(!cl->freed());
        assert(!cl->getRemoved());
        #endif

        bool OK = true;
        for(const Lit lit: *cl) {
            if (seen[lit.toInt()] == 0) {
                OK = false;
                break;
            }
        }

        if (OK)
            break;
    }

    for(const Lit lit: torem) {
        seen[lit.toInt()] = 0;
    }

    assert(cl != NULL);
    return cl;
}
Example #4
0
void ClauseAllocator::move_one_watchlist(
    watch_subarray& ws, ClOffset* newDataStart, ClOffset*& new_ptr)
{
    for(Watched& w: ws) {
        if (w.isClause()) {
            Clause* old = ptr(w.get_offset());
            assert(!old->freed());
            Lit blocked = w.getBlockedLit();
            if (old->reloced) {
                ClOffset new_offset = (*old)[0].toInt();
                #ifdef LARGE_OFFSETS
                new_offset += ((uint64_t)(*old)[1].toInt())<<32;
                #endif
                w = Watched(new_offset, blocked);
            } else {
                ClOffset new_offset = move_cl(newDataStart, new_ptr, old);
                w = Watched(new_offset, blocked);
            }
        }
    }
}
/**
@brief If needed, compacts stacks, removing unused clauses

Firstly, the algorithm determines if the number of useless slots is large or
small compared to the problem size. If it is small, it does nothing. If it is
large, then it allocates new stacks, copies the non-freed clauses to these new
stacks, updates all pointers and offsets, and frees the original stacks.
*/
void ClauseAllocator::consolidate(
    Solver* solver
    , const bool force
) {
    const double myTime = cpuTime();

    //If re-allocation is not really neccessary, don't do it
    //Neccesities:
    //1) There is too much memory allocated. Re-allocation will save space
    //   Avoiding segfault (max is 16 outerOffsets, more than 10 is near)
    //2) There is too much empty, unused space (>30%)
    if (!force
        && ((double)currentlyUsedSize/(double)size > 0.7)
    ) {
        if (solver->conf.verbosity >= 3) {
            cout << "c Not consolidating memory." << endl;
        }
        return;
    }

    //Data for new struct
    vector<uint32_t> newOrigClauseSizes;
    vector<ClOffset> newOffsets;
    uint64_t newSize = 0;

    //Pointers that will be moved along
    BASE_DATA_TYPE* newDataStart = dataStart;
    BASE_DATA_TYPE* tmpDataStart = dataStart;

    assert(sizeof(Clause) % sizeof(BASE_DATA_TYPE) == 0);
    assert(sizeof(BASE_DATA_TYPE) % sizeof(Lit) == 0);
    for (const size_t sz: origClauseSizes) {
        Clause* clause = (Clause*)tmpDataStart;
        //Already freed, so skip entirely
        if (clause->freed()) {
            #ifdef VALGRIND_MAKE_MEM_DEFINED
            VALGRIND_MAKE_MEM_DEFINED(((char*)clause)+sizeof(Clause), clause->size()*sizeof(Lit));
            #endif
            tmpDataStart += sz;
            continue;
        }

        //Move to new position
        size_t bytesNeeded = sizeof(Clause) + clause->size()*sizeof(Lit);
        size_t sizeNeeded = bytesNeeded/sizeof(BASE_DATA_TYPE) + (bool)(bytesNeeded % sizeof(BASE_DATA_TYPE));
        assert(sizeNeeded <= sz && "New clause size must not be bigger than orig clause size");
        memmove(newDataStart, tmpDataStart, sizeNeeded*sizeof(BASE_DATA_TYPE));

        //Record position
        newOffsets.push_back(newSize);

        //Record sizes
        newOrigClauseSizes.push_back(sizeNeeded);
        newSize += sizeNeeded;

        //Move pointers along
        newDataStart += sizeNeeded;
        tmpDataStart += sz;
    }

    //Update offsets & pointers(?) now, when everything is in memory still
    updateAllOffsetsAndPointers(solver, newOffsets);

    const double time_used = cpuTime() - myTime;
    if (solver->conf.verbosity >= 2) {
        cout << "c [mem] Consolidated memory ";
        cout << " cls"; print_value_kilo_mega(newOrigClauseSizes.size());
        cout << " old size"; print_value_kilo_mega(size);
        cout << " new size"; print_value_kilo_mega(newSize);
        cout << solver->conf.print_times(time_used)
        << endl;
    }
    if (solver->sqlStats) {
        solver->sqlStats->time_passed_min(
            solver
            , "consolidate"
            , time_used
        );
    }

    //Update sizes
    size = newSize;
    currentlyUsedSize = newSize;
    newOrigClauseSizes.swap(origClauseSizes);
}
Example #6
0
void ClauseAllocator::consolidate(Solver* solver)
{
    double myTime = cpuTime();

    //if (dataStarts.size() > 2) {
    uint32_t sum = 0;
    for (uint32_t i = 0; i < sizes.size(); i++) {
        sum += currentlyUsedSize[i];
    }
    uint32_t sumAlloc = 0;
    for (uint32_t i = 0; i < sizes.size(); i++) {
        sumAlloc += sizes[i];
    }

    #ifdef DEBUG_CLAUSEALLOCATOR
    std::cout << "c ratio:" << (double)sum/(double)sumAlloc << std::endl;
    #endif //DEBUG_CLAUSEALLOCATOR

    if ((double)sum/(double)sumAlloc > 0.7 /*&& sum > 10000000*/) {
        if (solver->verbosity >= 2) {
            std::cout << "c Not consolidating memory." << std::endl;
        }
        return;
    }


    uint32_t newMaxSize = std::max(sum*2*sizeof(uint32_t), MIN_LIST_SIZE);
    uint32_t* newDataStarts = (uint32_t*)malloc(newMaxSize);
    newMaxSize /= sizeof(uint32_t);
    uint32_t newSize = 0;
    vec<uint32_t> newOrigClauseSizes;
    //}

    map<Clause*, Clause*> oldToNewPointer;
    map<uint32_t, uint32_t> oldToNewOffset;

    uint32_t* newDataStartsPointer = newDataStarts;
    for (uint32_t i = 0; i < dataStarts.size(); i++) {
        uint32_t currentLoc = 0;
        for (uint32_t i2 = 0; i2 < origClauseSizes[i].size(); i2++) {
            Clause* oldPointer = (Clause*)(dataStarts[i] + currentLoc);
            if (!oldPointer->freed()) {
                uint32_t sizeNeeded = sizeof(Clause) + oldPointer->size()*sizeof(Lit);
                memcpy(newDataStartsPointer, dataStarts[i] + currentLoc, sizeNeeded);

                oldToNewPointer[oldPointer] = (Clause*)newDataStartsPointer;
                oldToNewOffset[combineOuterInterOffsets(i, currentLoc)] = combineOuterInterOffsets(0, newSize);

                newSize += sizeNeeded/sizeof(uint32_t);
                newOrigClauseSizes.push(sizeNeeded/sizeof(uint32_t));
                newDataStartsPointer += sizeNeeded/sizeof(uint32_t);
            }

            currentLoc += origClauseSizes[i][i2];
        }
    }
    assert(newSize < newMaxSize);
    assert(newSize <= newMaxSize/2);

    updateOffsets(solver->watches, oldToNewOffset);
    updateOffsetsXor(solver->xorwatches, oldToNewOffset);

    updatePointers(solver->clauses, oldToNewPointer);
    updatePointers(solver->learnts, oldToNewPointer);
    updatePointers(solver->binaryClauses, oldToNewPointer);
    updatePointers(solver->xorclauses, oldToNewPointer);

    //No need to update varreplacer, since it only stores binary clauses that
    //must have been allocated such as to use the pool
    //updatePointers(solver->varReplacer->clauses, oldToNewPointer);
    updatePointers(solver->partHandler->clausesRemoved, oldToNewPointer);
    updatePointers(solver->partHandler->xorClausesRemoved, oldToNewPointer);
    for(map<Var, vector<Clause*> >::iterator it = solver->subsumer->elimedOutVar.begin(); it != solver->subsumer->elimedOutVar.end(); it++) {
        updatePointers(it->second, oldToNewPointer);
    }
    for(map<Var, vector<XorClause*> >::iterator it = solver->xorSubsumer->elimedOutVar.begin(); it != solver->xorSubsumer->elimedOutVar.end(); it++) {
        updatePointers(it->second, oldToNewPointer);
    }


    vec<PropagatedFrom>& reason = solver->reason;
    for (PropagatedFrom *it = reason.getData(), *end = reason.getDataEnd(); it != end; it++) {
        if (!it->isBinary() && !it->isNULL()) {
            /*if ((it == reason.getData() + (*it->getClause())[0].var())
                && (solver->value((*it->getClause())[0]) == l_True)) {
                assert(oldToNewPointer.find(it->getClause()) != oldToNewPointer.end());
                *it = PropagatedFrom(oldToNewPointer[it->getClause()]);
            } else {
                *it = PropagatedFrom();
            }*/
            if (oldToNewPointer.find(it->getClause()) != oldToNewPointer.end()) {
                *it = PropagatedFrom(oldToNewPointer[it->getClause()]);
            }
        }
    }

    for (uint32_t i = 0; i < dataStarts.size(); i++)
        free(dataStarts[i]);

    dataStarts.clear();
    maxSizes.clear();
    sizes.clear();
    origClauseSizes.clear();

    dataStarts.push(newDataStarts);
    maxSizes.push(newMaxSize);
    sizes.push(newSize);
    currentlyUsedSize.clear();
    currentlyUsedSize.push(newSize);
    origClauseSizes.clear();
    origClauseSizes.push();
    newOrigClauseSizes.moveTo(origClauseSizes[0]);

    if (solver->verbosity >= 1) {
        std::cout << "c Consolidated memory. Time: "
        << cpuTime() - myTime << std::endl;
    }
}
/**
@brief If needed, compacts stacks, removing unused clauses

Firstly, the algorithm determines if the number of useless slots is large or
small compared to the problem size. If it is small, it does nothing. If it is
large, then it allocates new stacks, copies the non-freed clauses to these new
stacks, updates all pointers and offsets, and frees the original stacks.
*/
void ClauseAllocator::consolidate(
    Solver* solver
    , const bool force
) {
    //If re-allocation is not really neccessary, don't do it
    //Neccesities:
    //1) There is too much memory allocated. Re-allocation will save space
    //   Avoiding segfault (max is 16 outerOffsets, more than 10 is near)
    //2) There is too much empty, unused space (>30%)
    if (!force
        && (float_div(currentlyUsedSize, size) > 0.8 || currentlyUsedSize < (100ULL*1000ULL))
    ) {
        if (solver->conf.verbosity >= 3) {
            cout << "c Not consolidating memory." << endl;
        }
        return;
    }
    const double myTime = cpuTime();

    //Pointers that will be moved along
    BASE_DATA_TYPE * const newDataStart = (BASE_DATA_TYPE*)malloc(currentlyUsedSize*sizeof(BASE_DATA_TYPE));
    BASE_DATA_TYPE * new_ptr = newDataStart;

    assert(sizeof(BASE_DATA_TYPE) % sizeof(Lit) == 0);
    for(auto& ws: solver->watches) {
        for(Watched& w: ws) {
            if (w.isClause()) {
                Clause* old = ptr(w.get_offset());
                assert(!old->freed());
                Lit blocked = w.getBlockedLit();
                if (old->reloced) {
                    Lit newoffset = (*old)[0];
                    w = Watched(newoffset.toInt(), blocked);
                } else {
                    uint32_t new_offset = move_cl(newDataStart, new_ptr, old);
                    w = Watched(new_offset, blocked);
                }
            }
        }
    }

    #ifdef USE_GAUSS
    for (Gaussian* gauss : solver->gauss_matrixes) {
        for(GaussClauseToClear& gcl: gauss->clauses_toclear) {
            ClOffset& off = gcl.offs;
            Clause* old = ptr(off);
            if (old->reloced) {
                uint32_t new_offset = (*old)[0].toInt();
                off = new_offset;
            } else {
                uint32_t new_offset = move_cl(newDataStart, new_ptr, old);
                off = new_offset;
            }
            assert(!old->freed());
        }
    }
    #endif //USE_GAUSS

    update_offsets(solver->longIrredCls);
    for(auto& lredcls: solver->longRedCls) {
        update_offsets(lredcls);
    }

    //Fix up propBy
    for (size_t i = 0; i < solver->nVars(); i++) {
        VarData& vdata = solver->varData[i];
        if (vdata.reason.isClause()) {
            if (vdata.removed == Removed::none
                && solver->decisionLevel() >= vdata.level
                && vdata.level != 0
                && solver->value(i) != l_Undef
            ) {
                Clause* old = ptr(vdata.reason.get_offset());
                assert(!old->freed());
                uint32_t new_offset = (*old)[0].toInt();
                vdata.reason = PropBy(new_offset);
            } else {
                vdata.reason = PropBy();
            }
        }
    }

    //Update sizes
    const uint32_t old_size = size;
    size = new_ptr-newDataStart;
    capacity = currentlyUsedSize;
    currentlyUsedSize = size;
    free(dataStart);
    dataStart = newDataStart;

    const double time_used = cpuTime() - myTime;
    if (solver->conf.verbosity) {
        cout << "c [mem] Consolidated memory ";
        cout << " old size"; print_value_kilo_mega(old_size);
        cout << " new size"; print_value_kilo_mega(size);
        cout << solver->conf.print_times(time_used)
        << endl;
    }
    if (solver->sqlStats) {
        solver->sqlStats->time_passed_min(
            solver
            , "consolidate"
            , time_used
        );
    }
}
Example #8
0
/**
@brief If needed, compacts stacks, removing unused clauses

Firstly, the algorithm determines if the number of useless slots is large or
small compared to the problem size. If it is small, it does nothing. If it is
large, then it allocates new stacks, copies the non-freed clauses to these new
stacks, updates all pointers and offsets, and frees the original stacks.
*/
void ClauseAllocator::consolidate(
    Solver* solver
    , const bool force
    , bool lower_verb
) {
    //If re-allocation is not really neccessary, don't do it
    //Neccesities:
    //1) There is too much memory allocated. Re-allocation will save space
    //   Avoiding segfault (max is 16 outerOffsets, more than 10 is near)
    //2) There is too much empty, unused space (>30%)
    if (!force
        && (float_div(currentlyUsedSize, size) > 0.8 || currentlyUsedSize < (100ULL*1000ULL))
    ) {
        if (solver->conf.verbosity >= 3
            || (lower_verb && solver->conf.verbosity)
        ) {
            cout << "c Not consolidating memory." << endl;
        }
        return;
    }
    const double myTime = cpuTime();

    //Pointers that will be moved along
    BASE_DATA_TYPE * const newDataStart = (BASE_DATA_TYPE*)malloc(currentlyUsedSize*sizeof(BASE_DATA_TYPE));
    BASE_DATA_TYPE * new_ptr = newDataStart;

    assert(sizeof(BASE_DATA_TYPE) % sizeof(Lit) == 0);

    vector<bool> visited(solver->watches.size(), 0);
    Heap<Solver::VarOrderLt> &order_heap = solver->VSIDS ? solver->order_heap_vsids : solver->order_heap_maple;
    if (solver->conf.static_mem_consolidate_order) {
        for(auto& ws: solver->watches) {
            move_one_watchlist(ws, newDataStart, new_ptr);
        }
    } else {
        for(uint32_t i = 0; i < order_heap.size(); i++) {
            for(uint32_t i2 = 0; i2 < 2; i2++) {
                Lit lit = Lit(order_heap[i], i2);
                assert(lit.toInt() < solver->watches.size());
                move_one_watchlist(solver->watches[lit], newDataStart, new_ptr);
                visited[lit.toInt()] = 1;
            }
        }
        for(uint32_t i = 0; i < solver->watches.size(); i++) {
            Lit lit = Lit::toLit(i);
            watch_subarray ws = solver->watches[lit];
            if (!visited[lit.toInt()]) {
                move_one_watchlist(ws, newDataStart, new_ptr);
                visited[lit.toInt()] = 1;
            }
        }
    }

    #ifdef USE_GAUSS
    for (EGaussian* gauss : solver->gmatrixes) {
        if (gauss == NULL) {
            continue;
        }

        for(auto& gcl: gauss->clauses_toclear) {
            Clause* old = ptr(gcl.first);
            if (old->reloced) {
                ClOffset new_offset = (*old)[0].toInt();
                #ifdef LARGE_OFFSETS
                new_offset += ((uint64_t)(*old)[1].toInt())<<32;
                #endif
                gcl.first = new_offset;
            } else {
                ClOffset new_offset = move_cl(newDataStart, new_ptr, old);
                gcl.first = new_offset;
            }
            assert(!old->freed());
        }
    }
    #endif //USE_GAUSS

    update_offsets(solver->longIrredCls);
    for(auto& lredcls: solver->longRedCls) {
        update_offsets(lredcls);
    }

    //Fix up propBy
    for (size_t i = 0; i < solver->nVars(); i++) {
        VarData& vdata = solver->varData[i];
        if (vdata.reason.isClause()) {
            if (vdata.removed == Removed::none
                && solver->decisionLevel() >= vdata.level
                && vdata.level != 0
                && solver->value(i) != l_Undef
            ) {
                Clause* old = ptr(vdata.reason.get_offset());
                assert(!old->freed());
                ClOffset new_offset = (*old)[0].toInt();
                #ifdef LARGE_OFFSETS
                new_offset += ((uint64_t)(*old)[1].toInt())<<32;
                #endif
                vdata.reason = PropBy(new_offset);
            } else {
                vdata.reason = PropBy();
            }
        }
    }

    //Update sizes
    const uint64_t old_size = size;
    size = new_ptr-newDataStart;
    capacity = currentlyUsedSize;
    currentlyUsedSize = size;
    free(dataStart);
    dataStart = newDataStart;

    const double time_used = cpuTime() - myTime;
    if (solver->conf.verbosity >= 2
        || (lower_verb && solver->conf.verbosity)
    ) {
        size_t log_2_size = 0;
        if (size > 0) {
            //yes, it can be 0 (only binary clauses, for example)
            std::log2(size);
        }
        cout << "c [mem] consolidate ";
        cout << " old-sz: "; print_value_kilo_mega(old_size*sizeof(BASE_DATA_TYPE));
        cout << " new-sz: "; print_value_kilo_mega(size*sizeof(BASE_DATA_TYPE));
        cout << " new bits offs: " << std::fixed << std::setprecision(2) << log_2_size;
        cout << solver->conf.print_times(time_used)
        << endl;
    }
    if (solver->sqlStats) {
        solver->sqlStats->time_passed_min(
            solver
            , "consolidate"
            , time_used
        );
    }
}