// Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. /*! \file This file contains helper functions for CoinPresolve. The declarations needed for use are included in CoinPresolveMatrix.hpp. */ #include #include #include #include "CoinHelperFunctions.hpp" #include "CoinPresolveMatrix.hpp" /*! \defgroup PMMDVX Packed Matrix Major Dimension Vector Expansion \brief Functions to help with major-dimension vector expansion in a packed matrix structure. This next block of functions handles the problems associated with expanding a column in a column-major representation or a row in a row-major representation. We need to be able to answer the questions: * Is there room to expand a major vector in place? * Is there sufficient free space at the end of the element and minor index storage areas (bulk storage) to hold the major vector? When the answer to the first question is `no', we need to be able to move the major vector to the free space at the end of bulk storage. When the answer to the second question is `no', we need to be able to compact the major vectors in the bulk storage area in order to regain a block of useable space at the end. presolve_make_memlists initialises a linked list that tracks the position of major vectors in the bulk storage area. It's used to locate physically adjacent vectors. presolve_expand deals with adding a coefficient to a major vector, either in-place or by moving it to free space at the end of the storage areas. There are two inline wrappers, presolve_expand_col and presolve_expand_row, defined in CoinPresolveMatrix.hpp. compact_rep compacts the major vectors in the storage areas to leave a single block of free space at the end. */ //@{ /* This first function doesn't need to be known outside of this file. */ namespace { /* compact_rep This routine compacts the major vectors in the bulk storage area, leaving a single block of free space at the end. The vectors are not reordered, just shifted down to remove gaps. */ void compact_rep (double *elems, int *indices, CoinBigIndex *starts, const int *lengths, int n, const presolvehlink *link) { # if PRESOLVE_SUMMARY printf("****COMPACTING****\n") ; # endif // for now, just look for the first element of the list int i = n ; while (link[i].pre != NO_LINK) i = link[i].pre ; int j = 0 ; for (; i != n; i = link[i].suc) { CoinBigIndex s = starts[i] ; CoinBigIndex e = starts[i] + lengths[i] ; // because of the way link is organized, j <= s starts[i] = j ; for (CoinBigIndex k = s; k < e; k++) { elems[j] = elems[k] ; indices[j] = indices[k] ; j++ ; } } } } /* end unnamed namespace */ /* \brief Initialise linked list for major vector order in bulk storage Initialise the linked list that will track the order of major vectors in the element and row index bulk storage arrays. When finished, link[j].pre contains the index of the previous non-empty vector in the storage arrays and link[j].suc contains the index of the next non-empty vector. For an empty vector j, link[j].pre = link[j].suc = NO_LINK. If n is the number of major-dimension vectors, link[n] is valid; link[n].pre is the index of the last non-empty vector, and link[n].suc = NO_LINK. This routine makes the implicit assumption that the order of vectors in the storage areas matches the order in starts. (I.e., there's no check that starts[j] > starts[i] for j < i.) */ void presolve_make_memlists (CoinBigIndex *starts, int *lengths, presolvehlink *link, int n) { int i ; int pre = NO_LINK ; for (i=0; i= bulkCap) { return (true) ; } } /* The most complicated case --- we need to move k from its current location to empty space at the end of the bulk storage. And we may need to make that! Compaction is identical to the above case. */ else { int lastcol = majlinks[nmaj].pre ; int newkcsx = majstrts[lastcol]+majlens[lastcol] ; int newkcex = newkcsx+majlens[k] ; if (newkcex+1 >= bulkCap) { compact_rep(els,minndxs,majstrts,majlens,nmaj,majlinks) ; kcsx = majstrts[k] ; kcex = kcsx + majlens[k] ; newkcsx = majstrts[lastcol]+majlens[lastcol] ; newkcex = newkcsx+majlens[k] ; if (newkcex+1 >= bulkCap) { return (true) ; } } /* Moving the vector requires three actions. First we move the data, then update the packed matrix vector start, then relink the storage order list, */ memcpy((void*)&minndxs[newkcsx], (void*)&minndxs[kcsx],majlens[k]*sizeof(int)) ; memcpy((void*)&els[newkcsx], (void*)&els[kcsx],majlens[k]*sizeof(double)) ; majstrts[k] = newkcsx ; PRESOLVE_REMOVE_LINK(majlinks,k) ; PRESOLVE_INSERT_LINK(majlinks,k,lastcol) ; } /* Success --- the vector has room for one more coefficient. */ return (false) ; } //@} /* Helper function to duplicate a major-dimension vector. */ /* A major-dimension vector is composed of paired element and minor index arrays. We want to duplicate length entries from both arrays, starting at offset. If tgt > 0, we'll run a more complicated copy loop which will elide the entry with minor index == tgt. In this case, we want to reduce the size of the allocated array by 1. Pigs will fly before sizeof(int) > sizeof(double), but if it ever happens this code will fail. */ double *presolve_dupmajor (const double *elems, const int *indices, int length, CoinBigIndex offset, int tgt) { int n ; if (tgt >= 0) length-- ; if (2*sizeof(int) <= sizeof(double)) n = (3*length+1)>>1 ; else n = 2*length ; double *dArray = new double [n] ; int *iArray = reinterpret_cast(dArray+length) ; if (tgt < 0) { memcpy(dArray,elems+offset,length*sizeof(double)) ; memcpy(iArray,indices+offset,length*sizeof(int)) ; } else { int korig ; int kcopy = 0 ; indices += offset ; elems += offset ; for (korig = 0 ; korig <= length ; korig++) { int i = indices[korig] ; if (i != tgt) { dArray[kcopy] = elems[korig] ; iArray[kcopy++] = indices[korig] ; } } } return (dArray) ; } /* Routines to find the position of the entry for a given minor index in a major vector. Inline wrappers with column-major and row-major parameter names are defined in CoinPresolveMatrix.hpp. The threaded matrix used in postsolve exists only as a column-major form, so only one wrapper is defined. */ /* presolve_find_minor Find the position (k) of the entry for a given minor index (tgt) within the range of entries for a major vector (ks, ke). Print a tag and abort (DIE) if there's no entry for tgt. */ CoinBigIndex presolve_find_minor (int tgt, CoinBigIndex ks, CoinBigIndex ke, const int *minndxs) { CoinBigIndex k ; for (k = ks ; k < ke ; k++) { if (minndxs[k] == tgt) return (k) ; } DIE("FIND_MINOR") ; abort () ; return -1; } /* As presolve_find_minor, but return a position one past the end of the major vector when the entry is not already present. */ CoinBigIndex presolve_find_minor1 (int tgt, CoinBigIndex ks, CoinBigIndex ke, const int *minndxs) { CoinBigIndex k ; for (k = ks ; k < ke ; k++) { if (minndxs[k] == tgt) return (k) ; } return (k) ; } /* In a threaded matrix, the major vector does not occupy a contiguous block in the bulk storage area. For example, in a threaded column-major matrix, if a is in pos'n kp of hrow, the next coefficient a will be in pos'n kq = link[kp]. Abort if we don't find it. */ CoinBigIndex presolve_find_minor2 (int tgt, CoinBigIndex ks, int majlen, const int *minndxs, const CoinBigIndex *majlinks) { for (int i = 0 ; i < majlen ; ++i) { if (minndxs[ks] == tgt) return (ks) ; ks = majlinks[ks] ; } DIE("FIND_MINOR2") ; abort () ; return -1; } /* As presolve_find_minor2, but return -1 if the entry is missing */ CoinBigIndex presolve_find_minor3 (int tgt, CoinBigIndex ks, int majlen, const int *minndxs, const CoinBigIndex *majlinks) { for (int i = 0 ; i < majlen ; ++i) { if (minndxs[ks] == tgt) return (ks) ; ks = majlinks[ks] ; } return (-1) ; } /* Delete the entry for a minor index from a major vector. The last entry in the major vector is moved into the hole left by the deleted entry. This leaves some space between the end of this major vector and the start of the next in the bulk storage areas (this is termed loosely packed). Inline wrappers with column-major and row-major parameter names are defined in CoinPresolveMatrix.hpp. The threaded matrix used in postsolve exists only as a column-major form, so only one wrapper is defined. */ void presolve_delete_from_major (int majndx, int minndx, const CoinBigIndex *majstrts, int *majlens, int *minndxs, double *els) { CoinBigIndex ks = majstrts[majndx] ; CoinBigIndex ke = ks + majlens[majndx] ; CoinBigIndex kmi = presolve_find_minor(minndx,ks,ke,minndxs) ; minndxs[kmi] = minndxs[ke-1] ; els[kmi] = els[ke-1] ; majlens[majndx]-- ; return ; } // Delete all marked and zero marked void presolve_delete_many_from_major (int majndx, char * marked, const CoinBigIndex *majstrts, int *majlens, int *minndxs, double *els) { CoinBigIndex ks = majstrts[majndx] ; CoinBigIndex ke = ks + majlens[majndx] ; CoinBigIndex put=ks; for (CoinBigIndex k=ks;k= 0) ; return ; }