Пример #1
0
 /// return the index vectors I_{k,ell} and J_{k,ell}
 /// (simple representation uses I[i] = i and J[j] = j)
 virtual void index(size_t k, size_t ell, SizeVector& I, SizeVector& J)
 {   assert( I.size() >= m_ + 1 );
     assert( J.size() >= n_ );
     for(size_t i = 0; i <= m_; i++)
         I[i] = i;
     for(size_t j = 0; j < n_; j++)
         J[j] = j;
 }
Пример #2
0
Game::Game(Dimension dimensioncount, SizeVector dimensions, NullTimer *timer, ProgramOptions opts):
	timer(timer), dimensions(dimensions), dimensioncount(dimensioncount),
	allpositions_initialised(false), minecount(0), flagcount(0), pressedcount(0),
	state(GAMESTATE_INIT), window(NULL), opts(opts) {

	assert(dimensions.size() == dimensioncount);
	assert(dimensioncount > 0);
	this->inittiles(0);
}
Пример #3
0
FunctionCallPtr
Interpreter::newFunctionCall (const std::string &functionName)
{
    Lock lock (_data->mutex);
    
    //
    // Calling a CTL function with variable-size array arguments
    // from C++ is not supported.
    //

    const SymbolInfoPtr info = symtab().lookupSymbol (functionName);

    if (!info)
	THROW (ArgExc, "Cannot find CTL function " << functionName << ".");

    if (!info->isFunction())
	THROW (TypeExc, "CTL object " << functionName << " is not a function "
			"(it is of type " << info->type()->asString() << ").");

    const FunctionTypePtr fType = info->type();
    const ParamVector &parameters = fType->parameters();

    for (int i = parameters.size() - 1; i >= 0; --i)
    {
	const Param &param = parameters[i];
        ArrayTypePtr aType = param.type.cast<ArrayType>();

        if(aType)
        {
            SizeVector sizes;
            aType->sizes (sizes);
	    
            for (int j = 0; j < sizes.size(); j++)
            {
                if (sizes[j] == 0)
                    THROW (ArgExc, "CTL function " << functionName << " "
				   "has a variable-size array "
				   "argument, " << param.name << ", and can "
				   "only be called by another CTL function.");
            }
        }
    }
    
    return newFunctionCallInternal (info, functionName);
}
Пример #4
0
void LuInvert(
	const SizeVector  &ip, 
	const SizeVector  &jp, 
	const FloatVector &LU,
	FloatVector       &B )
{	size_t k; // column index in X
	size_t p; // index along diagonal in LU
	size_t i; // row index in LU and X

	typedef typename FloatVector::value_type Float;

	// check numeric type specifications
	CheckNumericType<Float>();

	// check simple vector class specifications
	CheckSimpleVector<Float, FloatVector>();
	CheckSimpleVector<size_t, SizeVector>();

	Float etmp;
	
	size_t n = ip.size();
	CPPAD_ASSERT_KNOWN(
		size_t(jp.size()) == n,
		"Error in LuInvert: jp must have size equal to n * n"
	);
	CPPAD_ASSERT_KNOWN(
		size_t(LU.size()) == n * n,
		"Error in LuInvert: Lu must have size equal to n * m"
	);
	size_t m = size_t(B.size()) / n;
	CPPAD_ASSERT_KNOWN(
		size_t(B.size()) == n * m,
		"Error in LuSolve: B must have size equal to a multiple of n"
	);

	// temporary storage for reordered solution
	FloatVector x(n);

	// loop over equations
	for(k = 0; k < m; k++)
	{	// invert the equation c = L * b
		for(p = 0; p < n; p++)
		{	// solve for c[p]
			etmp = B[ ip[p] * m + k ] / LU[ ip[p] * n + jp[p] ];
			B[ ip[p] * m + k ] = etmp;
			// subtract off effect on other variables
			for(i = p+1; i < n; i++)
				B[ ip[i] * m + k ] -=
					etmp * LU[ ip[i] * n + jp[p] ];
		}

		// invert the equation x = U * c
		p = n;
		while( p > 0 )
		{	--p;
			etmp       = B[ ip[p] * m + k ];
			x[ jp[p] ] = etmp;
			for(i = 0; i < p; i++ )
				B[ ip[i] * m + k ] -= 
					etmp * LU[ ip[i] * n + jp[p] ];
		}

		// copy reordered solution into B
		for(i = 0; i < n; i++)
			B[i * m + k] = x[i];
	}
	return;
}
Пример #5
0
int LuFactor(SizeVector &ip, SizeVector &jp, FloatVector &LU)           //
{
	// type of the elements of LU                                   //
	typedef typename FloatVector::value_type Float;                 //

	// check numeric type specifications
	CheckNumericType<Float>();

	// check simple vector class specifications
	CheckSimpleVector<Float, FloatVector>();
	CheckSimpleVector<size_t, SizeVector>();

	size_t  i, j;          // some temporary indices
	const Float zero( 0 ); // the value zero as a Float object
	size_t  imax;          // row index of maximum element
	size_t  jmax;          // column indx of maximum element
	Float    emax;         // maximum absolute value
	size_t  p;             // count pivots
	int     sign;          // sign of the permutation
	Float   etmp;          // temporary element
	Float   pivot;         // pivot element

	// -------------------------------------------------------
	size_t n = ip.size();
	CPPAD_ASSERT_KNOWN(
		size_t(jp.size()) == n,
		"Error in LuFactor: jp must have size equal to n"
	);
	CPPAD_ASSERT_KNOWN(
		size_t(LU.size()) == n * n,
		"Error in LuFactor: LU must have size equal to n * m"
	);
	// -------------------------------------------------------

	// initialize row and column order in matrix not yet pivoted
	for(i = 0; i < n; i++)
	{	ip[i] = i;
		jp[i] = i;
	}
	// initialize the sign of the permutation
	sign = 1;
	// ---------------------------------------------------------

	// Reduce the matrix P to L * U using n pivots
	for(p = 0; p < n; p++)
	{	// determine row and column corresponding to element of
		// maximum absolute value in remaining part of P
		imax = jmax = n;
		emax = zero;
		for(i = p; i < n; i++)
		{	for(j = p; j < n; j++)
			{	CPPAD_ASSERT_UNKNOWN(
					(ip[i] < n) & (jp[j] < n)
				);
				etmp = LU[ ip[i] * n + jp[j] ];

				// check if maximum absolute value so far
				if( AbsGeq (etmp, emax) )
				{	imax = i;
					jmax = j;
					emax = etmp;
				}
			}
		}
		CPPAD_ASSERT_KNOWN(
		(imax < n) & (jmax < n) ,
		"LuFactor can't determine an element with "
		"maximum absolute value.\n"
		"Perhaps original matrix contains not a number or infinity.\n"
		"Perhaps your specialization of AbsGeq is not correct."
		);
		if( imax != p )
		{	// switch rows so max absolute element is in row p
			i        = ip[p];
			ip[p]    = ip[imax];
			ip[imax] = i;
			sign     = -sign;
		}
		if( jmax != p )
		{	// switch columns so max absolute element is in column p
			j        = jp[p];
			jp[p]    = jp[jmax];
			jp[jmax] = j;
			sign     = -sign;
		}
		// pivot using the max absolute element
		pivot   = LU[ ip[p] * n + jp[p] ];

		// check for determinant equal to zero
		if( pivot == zero )
		{	// abort the mission
			return   0;
		}

		// Reduce U by the elementary transformations that maps
		// LU( ip[p], jp[p] ) to one.  Only need transform elements
		// above the diagonal in U and LU( ip[p] , jp[p] ) is
		// corresponding value below diagonal in L.
		for(j = p+1; j < n; j++)
			LU[ ip[p] * n + jp[j] ] /= pivot;

		// Reduce U by the elementary transformations that maps
		// LU( ip[i], jp[p] ) to zero. Only need transform elements
		// above the diagonal in U and LU( ip[i], jp[p] ) is
		// corresponding value below diagonal in L.
		for(i = p+1; i < n; i++ )
		{	etmp = LU[ ip[i] * n + jp[p] ];
			for(j = p+1; j < n; j++)
			{	LU[ ip[i] * n + jp[j] ] -=
					etmp * LU[ ip[p] * n + jp[j] ];
			}
		}
	}
	return sign;
}
Пример #6
0
Файл: UCK.C Проект: PierFio/ball
	void UCK::makePathMatrix(const PairVector& e, SizeVector& sp, const Size e_size)
	{
		std::vector<Size>* line;
		// create bond-matrix, because Floyd's Algorithm requires a reachability matrix
		SizeVector* bond_matrix;
		line = new vector<Size>;
		bond_matrix = new SizeVector;
		
		// initialize bond-matrix with 0 at every position
		for (Size i = 0; i != e_size; ++i)
		{
			line->clear();
			for(Size j = 0; j != e_size; ++j)
			{
				line->push_back(0);
			}
			bond_matrix->push_back(*line);
		}
		// proceed all edges and set corresponding position in bond_matrix to 1
		for (Size i = 0; i != e.size(); ++i)
		{
			(*bond_matrix)[e[i].first][e[i].second] = 1;
		}
		
		// initialize sp-matrix
		for(Size i = 0; i != bond_matrix->size(); ++i)
		{
			line->clear();
			for(Size j = 0; j != bond_matrix->size(); ++j)
			{
				if (i == j) // distance from a node to itself = 0
				{
					line->push_back(0);
				}
				else if((*bond_matrix)[i][j] == 1)	// if an edge exists between node i and j,
				{
					line->push_back(1);								// the distance between them is 1
				}
				else
				{
					line->push_back(std::numeric_limits<Index>::max()); // otherwise the distance is set to infinity
				}
			}
			sp.push_back(*line);
		}
		
		// Floyd's Algorithm
		for(Size i = 0; i != sp.size(); ++i)
		{
			for(Size j = 0; j != sp.size(); ++j)
			{
				for(Size k = 0; k != sp.size(); k++)
				{
					if(sp[j][k] > (sp[j][i] + sp[i][k]))
					{
						sp[j][k] = (sp[j][i] + sp[i][k]);
					}
				}
			}
		}
		
		delete bond_matrix;
		delete line;
		return;
	}
Пример #7
0
int LuRatio(SizeVector &ip, SizeVector &jp, ADvector &LU, AD<Base> &ratio) //
{
	typedef ADvector FloatVector;                                       //
	typedef AD<Base>       Float;                                       //

	// check numeric type specifications
	CheckNumericType<Float>();

	// check simple vector class specifications
	CheckSimpleVector<Float, FloatVector>();
	CheckSimpleVector<size_t, SizeVector>();

	size_t  i, j;          // some temporary indices
	const Float zero( 0 ); // the value zero as a Float object
	size_t  imax;          // row index of maximum element
	size_t  jmax;          // column indx of maximum element
	Float    emax;         // maximum absolute value
	size_t  p;             // count pivots
	int     sign;          // sign of the permutation
	Float   etmp;          // temporary element
	Float   pivot;         // pivot element

	// -------------------------------------------------------
	size_t n = size_t(ip.size());
	CPPAD_ASSERT_KNOWN(
		size_t(jp.size()) == n,
		"Error in LuFactor: jp must have size equal to n"
	);
	CPPAD_ASSERT_KNOWN(
		size_t(LU.size()) == n * n,
		"Error in LuFactor: LU must have size equal to n * m"
	);
	// -------------------------------------------------------

	// initialize row and column order in matrix not yet pivoted
	for(i = 0; i < n; i++)
	{	ip[i] = i;
		jp[i] = i;
	}
	// initialize the sign of the permutation
	sign = 1;
	// initialize the ratio                                             //
	ratio = Float(1);                                                   //
	// ---------------------------------------------------------

	// Reduce the matrix P to L * U using n pivots
	for(p = 0; p < n; p++)
	{	// determine row and column corresponding to element of
		// maximum absolute value in remaining part of P
		imax = jmax = n;
		emax = zero;
		for(i = p; i < n; i++)
		{	for(j = p; j < n; j++)
			{	CPPAD_ASSERT_UNKNOWN(
					(ip[i] < n) & (jp[j] < n)
				);
				etmp = LU[ ip[i] * n + jp[j] ];

				// check if maximum absolute value so far
				if( AbsGeq (etmp, emax) )
				{	imax = i;
					jmax = j;
					emax = etmp;
				}
			}
		}
		for(i = p; i < n; i++)                                       //
		{	for(j = p; j < n; j++)                               //
			{	etmp  = abs(LU[ ip[i] * n + jp[j] ] / emax); //
				ratio =                                      //
				CondExpGt(etmp, ratio, etmp, ratio);         //
			}                                                    //
		}                                                            //
		CPPAD_ASSERT_KNOWN(
			(imax < n) & (jmax < n) ,
			"AbsGeq must return true when second argument is zero"
		);
		if( imax != p )
		{	// switch rows so max absolute element is in row p
			i        = ip[p];
			ip[p]    = ip[imax];
			ip[imax] = i;
			sign     = -sign;
		}
		if( jmax != p )
		{	// switch columns so max absolute element is in column p
			j        = jp[p];
			jp[p]    = jp[jmax];
			jp[jmax] = j;
			sign     = -sign;
		}
		// pivot using the max absolute element
		pivot   = LU[ ip[p] * n + jp[p] ];

		// check for determinant equal to zero
		if( pivot == zero )
		{	// abort the mission
			return   0;
		}

		// Reduce U by the elementary transformations that maps
		// LU( ip[p], jp[p] ) to one.  Only need transform elements
		// above the diagonal in U and LU( ip[p] , jp[p] ) is
		// corresponding value below diagonal in L.
		for(j = p+1; j < n; j++)
			LU[ ip[p] * n + jp[j] ] /= pivot;

		// Reduce U by the elementary transformations that maps
		// LU( ip[i], jp[p] ) to zero. Only need transform elements
		// above the diagonal in U and LU( ip[i], jp[p] ) is
		// corresponding value below diagonal in L.
		for(i = p+1; i < n; i++ )
		{	etmp = LU[ ip[i] * n + jp[p] ];
			for(j = p+1; j < n; j++)
			{	LU[ ip[i] * n + jp[j] ] -=
					etmp * LU[ ip[p] * n + jp[j] ];
			}
		}
	}
	return sign;
}
Пример #8
0
void color_general_cppad(
    const SetVector&        pattern ,
    const SizeVector&       row     ,
    const SizeVector&       col     ,
    CppAD::vector<size_t>&  color   )
{
    size_t K = row.size();
    size_t m = pattern.n_set();
    size_t n = pattern.end();

    CPPAD_ASSERT_UNKNOWN( size_t( col.size() )   == K );
    CPPAD_ASSERT_UNKNOWN( size_t( color.size() ) == m );

    // We define the set of rows, columns, and pairs that appear
    // by the set ( row[k], col[k] ) for k = 0, ... , K-1.

    // initialize rows that appear
    CppAD::vector<bool> row_appear(m);
    for(size_t i = 0; i < m; i++)
            row_appear[i] = false;

    // rows and columns that appear
    SetVector c2r_appear, r2c_appear;
    c2r_appear.resize(n, m);
    r2c_appear.resize(m, n);
    for(size_t k = 0;  k < K; k++)
    {   CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k], col[k]) );
        row_appear[ row[k] ] = true;
        c2r_appear.post_element(col[k], row[k]);
        r2c_appear.post_element(row[k], col[k]);
    }
    // process posts
    for(size_t j = 0; j < n; ++j)
        c2r_appear.process_post(j);
    for(size_t i = 0; i < m; ++i)
        r2c_appear.process_post(i);

    // for each column, which rows are non-zero and do not appear
    SetVector not_appear;
    not_appear.resize(n, m);
    for(size_t i = 0; i < m; i++)
    {   typename SetVector::const_iterator pattern_itr(pattern, i);
        size_t j = *pattern_itr;
        while( j != pattern.end() )
        {   if( ! c2r_appear.is_element(j , i) )
                not_appear.post_element(j, i);
            j = *(++pattern_itr);
        }
    }
    // process posts
    for(size_t j = 0; j < n; ++j)
        not_appear.process_post(j);

    // initial coloring
    color.resize(m);
    size_t ell = 0;
    for(size_t i = 0; i < m; i++)
    {   if( row_appear[i] )
            color[i] = ell++;
        else
            color[i] = m;
    }
    /*
    See GreedyPartialD2Coloring Algorithm Section 3.6.2 of
    Graph Coloring in Optimization Revisited by
    Assefaw Gebremedhin, Fredrik Maane, Alex Pothen

    The algorithm above was modified (by Brad Bell) to take advantage of the
    fact that only the entries (subset of the sparsity pattern) specified by
    row and col need to be computed.
    */
    CppAD::vector<bool> forbidden(m);
    for(size_t i = 1; i < m; i++) // for each row that appears
    if( color[i] < m )
    {
        // initial all colors as ok for this row
        // (value of forbidden for ell > initial color[i] does not matter)
        for(ell = 0; ell <= color[i]; ell++)
            forbidden[ell] = false;

        // -----------------------------------------------------
        // Forbid colors for which this row would destroy results:
        //
        // for each column that is non-zero for this row
        typename SetVector::const_iterator pattern_itr(pattern, i);
        size_t j = *pattern_itr;
        while( j != pattern.end() )
        {   // for each row that appears with this column
            typename SetVector::const_iterator c2r_itr(c2r_appear, j);
            size_t r = *c2r_itr;
            while( r != c2r_appear.end() )
            {   // if this is not the same row, forbid its color
                if( (r < i) & (color[r] < m) )
                    forbidden[ color[r] ] = true;
                r = *(++c2r_itr);
            }
            j = *(++pattern_itr);
        }


        // -----------------------------------------------------
        // Forbid colors that destroy results needed for this row.
        //
        // for each column that appears with this row
        typename SetVector::const_iterator r2c_itr(r2c_appear, i);
        j = *r2c_itr;
        while( j != r2c_appear.end() )
        {   // For each row that is non-zero for this column
            // (the appear rows have already been checked above).
            typename SetVector::const_iterator not_itr(not_appear, j);
            size_t r = *not_itr;
            while( r != not_appear.end() )
            {   // if this is not the same row, forbid its color
                if( (r < i) & (color[r] < m) )
                    forbidden[ color[r] ] = true;
                r = *(++not_itr);
            }
            j = *(++r2c_itr);
        }

        // pick the color with smallest index
        ell = 0;
        while( forbidden[ell] )
        {   ell++;
            CPPAD_ASSERT_UNKNOWN( ell <= color[i] );
        }
        color[i] = ell;
    }
    return;
}
Пример #9
0
void ADFun<Base,RecBase>::subgraph_jac_rev(
    const BoolVector&                   select_domain  ,
    const BoolVector&                   select_range   ,
    const BaseVector&                   x              ,
    sparse_rcv<SizeVector, BaseVector>& matrix_out     )
{   size_t m = Range();
    size_t n = Domain();
    //
    // point at which we are evaluating Jacobian
    Forward(0, x);
    //
    // nnz and row, column, and row_major vectors for subset
    local::pod_vector<size_t> row_out;
    local::pod_vector<size_t> col_out;
    local::pod_vector_maybe<Base>   val_out;
    //
    // initialize reverse mode computation on subgraphs
    subgraph_reverse(select_domain);
    //
    // memory used to hold subgraph_reverse results
    BaseVector dw;
    SizeVector col;
    //
    // loop through selected independent variables
    for(size_t i = 0; i < m; ++i) if( select_range[i] )
    {   // compute Jacobian and sparsity for this dependent variable
        size_t q   = 1;
        subgraph_reverse(q, i, col, dw);
        CPPAD_ASSERT_UNKNOWN( size_t( dw.size() ) == n );
        //
        // offset for this dependent variable
        size_t index = row_out.size();
        CPPAD_ASSERT_UNKNOWN( col_out.size() == index );
        CPPAD_ASSERT_UNKNOWN( val_out.size() == index );
        //
        // extend vectors to hold results for this dependent variable
        size_t col_size = size_t( col.size() );
        row_out.extend( col_size );
        col_out.extend( col_size );
        val_out.extend( col_size );
        //
        // store results for this dependent variable
        for(size_t c = 0; c < col_size; ++c)
        {   row_out[index + c] = i;
            col_out[index + c] = col[c];
            val_out[index + c] = dw[ col[c] ];
        }
    }
    //
    // create sparsity pattern corresponding to row_out, col_out
    size_t nr  = m;
    size_t nc  = n;
    size_t nnz = row_out.size();
    sparse_rc<SizeVector> pattern(nr, nc, nnz);
    for(size_t k = 0; k < nnz; ++k)
        pattern.set(k, row_out[k], col_out[k]);
    //
    // create sparse matrix
    sparse_rcv<SizeVector, BaseVector> matrix(pattern);
    for(size_t k = 0; k < nnz; ++k)
        matrix.set(k,  val_out[k]);
    //
    // return matrix
    matrix_out = matrix;
    //
    return;
}
Пример #10
0
bool abs_min_linear(
    size_t            level   ,
    size_t            n       ,
    size_t            m       ,
    size_t            s       ,
    const DblVector&  g_hat   ,
    const DblVector&  g_jac   ,
    const DblVector&  bound   ,
    const DblVector&  epsilon ,
    const SizeVector& maxitr  ,
    DblVector&        delta_x )
// END PROTOTYPE
{   using std::fabs;
    bool ok    = true;
    double inf = std::numeric_limits<double>::infinity();
    //
    CPPAD_ASSERT_KNOWN(
        level <= 4,
        "abs_min_linear: level is not less that or equal 4"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(epsilon.size()) == 2,
        "abs_min_linear: size of epsilon not equal to 2"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(maxitr.size()) == 2,
        "abs_min_linear: size of maxitr not equal to 2"
    );
    CPPAD_ASSERT_KNOWN(
        m == 1,
        "abs_min_linear: m is not equal to 1"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(delta_x.size()) == n,
        "abs_min_linear: size of delta_x not equal to n"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(bound.size()) == n,
        "abs_min_linear: size of bound not equal to n"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(g_hat.size()) == m + s,
        "abs_min_linear: size of g_hat not equal to m + s"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(g_jac.size()) == (m + s) * (n + s),
        "abs_min_linear: size of g_jac not equal to (m + s)*(n + s)"
    );
    CPPAD_ASSERT_KNOWN(
        size_t(bound.size()) == n,
        "abs_min_linear: size of bound is not equal to n"
    );
    if( level > 0 )
    {   std::cout << "start abs_min_linear\n";
        CppAD::abs_print_mat("bound", n, 1, bound);
        CppAD::abs_print_mat("g_hat", m + s, 1, g_hat);
        CppAD::abs_print_mat("g_jac", m + s, n + s, g_jac);

    }
    // partial y(x, u) w.r.t x (J in reference)
    DblVector py_px(n);
    for(size_t j = 0; j < n; j++)
        py_px[ j ] = g_jac[ j ];
    //
    // partial y(x, u) w.r.t u (Y in reference)
    DblVector py_pu(s);
    for(size_t j = 0; j < s; j++)
        py_pu[ j ] = g_jac[ n + j ];
    //
    // partial z(x, u) w.r.t x (Z in reference)
    DblVector pz_px(s * n);
    for(size_t i = 0; i < s; i++)
    {   for(size_t j = 0; j < n; j++)
        {   pz_px[ i * n + j ] = g_jac[ (n + s) * (i + m) + j ];
        }
    }
    // partial z(x, u) w.r.t u (L in reference)
    DblVector pz_pu(s * s);
    for(size_t i = 0; i < s; i++)
    {   for(size_t j = 0; j < s; j++)
        {   pz_pu[ i * s + j ] = g_jac[ (n + s) * (i + m) + n + j ];
        }
    }
    // initailize delta_x
    for(size_t j = 0; j < n; j++)
        delta_x[j] = 0.0;
    //
    // value of approximation for g(x, u) at current delta_x
    DblVector g_tilde = CppAD::abs_eval(n, m, s, g_hat, g_jac, delta_x);
    //
    // value of sigma at delta_x = 0; i.e., sign( z(x, u) )
    CppAD::vector<double> sigma(s);
    for(size_t i = 0; i < s; i++)
        sigma[i] = CppAD::sign( g_tilde[m + i] );
    //
    // current set of cutting planes
    DblVector C(maxitr[0] * n), c(maxitr[0]);
    //
    //
    size_t n_plane = 0;
    for(size_t itr = 0; itr < maxitr[0]; itr++)
    {
        // Equation (5), Propostion 3.1 of reference
        // dy_dx = py_px + py_pu * Sigma * (I - pz_pu * Sigma)^-1 * pz_px
        //
        // tmp_ss = I - pz_pu * Sigma
        DblVector tmp_ss(s * s);
        for(size_t i = 0; i < s; i++)
        {   for(size_t j = 0; j < s; j++)
                tmp_ss[i * s + j] = - pz_pu[i * s + j] * sigma[j];
            tmp_ss[i * s + i] += 1.0;
        }
        // tmp_sn = (I - pz_pu * Sigma)^-1 * pz_px
        double logdet;
        DblVector tmp_sn(s * n);
        LuSolve(s, n, tmp_ss, pz_px, tmp_sn, logdet);
        //
        // tmp_sn = Sigma * (I - pz_pu * Sigma)^-1 * pz_px
        for(size_t i = 0; i < s; i++)
        {   for(size_t j = 0; j < n; j++)
                tmp_sn[i * n + j] *= sigma[i];
        }
        // dy_dx = py_px + py_pu * Sigma * (I - pz_pu * Sigma)^-1 * pz_px
        DblVector dy_dx(n);
        for(size_t j = 0; j < n; j++)
        {   dy_dx[j] = py_px[j];
            for(size_t k = 0; k < s; k++)
                dy_dx[j] += py_pu[k] * tmp_sn[ k * n + j];
        }
        //
        // check for case where derivative of hyperplane is zero
        // (in convex case, this is the minimizer)
        bool near_zero = true;
        for(size_t j = 0; j < n; j++)
            near_zero &= std::fabs( dy_dx[j] ) < epsilon[1];
        if( near_zero )
        {   if( level > 0 )
                std::cout << "end abs_min_linear: local derivative near zero\n";
            return true;
        }

        // value of hyperplane at delta_x
        double plane_at_zero = g_tilde[0];
        // value of hyperplane at 0
        for(size_t j = 0; j < n; j++)
            plane_at_zero -= dy_dx[j] * delta_x[j];
        //
        // add a cutting plane with value g_tilde[0] at delta_x
        // and derivative dy_dx
        c[n_plane] = plane_at_zero;
        for(size_t j = 0; j < n; j++)
            C[n_plane * n + j] = dy_dx[j];
        ++n_plane;
        //
        // variables for cutting plane problem are (dx, w)
        // c[i] + C[i,:]*dx <= w
        DblVector b_box(n_plane), A_box(n_plane * (n + 1));
        for(size_t i = 0; i < n_plane; i++)
        {   b_box[i] = c[i];
            for(size_t j = 0; j < n; j++)
                A_box[i * (n+1) + j] = C[i * n + j];
            A_box[i *(n+1) + n] = -1.0;
        }
        // w is the objective
        DblVector c_box(n + 1);
        for(size_t i = 0; i < size_t(c_box.size()); i++)
            c_box[i] = 0.0;
        c_box[n] = 1.0;
        //
        // d_box
        DblVector d_box(n+1);
        for(size_t j = 0; j < n; j++)
            d_box[j] = bound[j];
        d_box[n] = inf;
        //
        // solve the cutting plane problem
        DblVector xout_box(n + 1);
        size_t level_box = 0;
        if( level > 0 )
            level_box = level - 1;
        ok &= CppAD::lp_box(
            level_box,
            A_box,
            b_box,
            c_box,
            d_box,
            maxitr[1],
            xout_box
        );
        if( ! ok )
        {   if( level > 0 )
            {   CppAD::abs_print_mat("delta_x", n, 1, delta_x);
                std::cout << "end abs_min_linear: lp_box failed\n";
            }
            return false;
        }
        //
        // check for convergence
        double max_diff = 0.0;
        for(size_t j = 0; j < n; j++)
        {   double diff = delta_x[j] - xout_box[j];
            max_diff    = std::max( max_diff, std::fabs(diff) );
        }
        //
        // check for descent in value of approximation objective
        DblVector delta_new(n);
        for(size_t j = 0; j < n; j++)
            delta_new[j] = xout_box[j];
        DblVector g_new = CppAD::abs_eval(n, m, s, g_hat, g_jac, delta_new);
        if( level > 0 )
        {   std::cout << "itr = " << itr << ", max_diff = " << max_diff
                << ", y_cur = " << g_tilde[0] << ", y_new = " << g_new[0]
                << "\n";
            CppAD::abs_print_mat("delta_new", n, 1, delta_new);
        }
        //
        g_tilde = g_new;
        delta_x = delta_new;
        //
        // value of sigma at new delta_x; i.e., sign( z(x, u) )
        for(size_t i = 0; i < s; i++)
            sigma[i] = CppAD::sign( g_tilde[m + i] );
        //
        if( max_diff < epsilon[0] )
        {   if( level > 0 )
                std::cout << "end abs_min_linear: change in delta_x near zero\n";
            return true;
        }
    }
    if( level > 0 )
        std::cout << "end abs_min_linear: maximum number of iterations exceeded\n";
    return false;
}