/**
 * @param equality A matrix of equality constraints \f$A_{eq}\f$(the number of
 * columns must match number of parameters)
 *                 where \f$A_{eq} x = 0\f$
 * @param inequality A matrix of inequality constraints (the number of columns
 * must match number of parameters
 *                 where \f$A_{eq} x \geq 0\f$
 */
void AugmentedLagrangianOptimizer::checkConstraints(
    const DblMatrix &equality, const DblMatrix &inequality) {
  const size_t totalNumConstr =
      numEqualityConstraints() + numInequalityConstraints();
  if (totalNumConstr == 0)
    return;

  // Sanity checks on matrix sizes
  for (size_t i = 0; i < 2; ++i) {
    size_t ncols(0);
    std::string matrix("");
    if (i == 0) {
      ncols = equality.numCols();
      matrix = "equality";
    } else {
      ncols = inequality.numCols();
      matrix = "inequality";
    }

    if (ncols > 0 && ncols != numParameters()) {
      std::ostringstream os;
      os << "AugmentedLagrangianOptimizer::initializeConstraints - Invalid "
         << matrix << " constraint matrix. Number of columns must match number "
                      "of parameters. ncols=" << ncols
         << ", nparams=" << numParameters();
      throw std::invalid_argument(os.str());
    }
  }
}
/**
  Get the UB matrix corresponding to the real space edge vectors a,b,c.
  The inverse of the matrix with vectors a,b,c as rows will be stored in UB.

  @param  UB      A 3x3 matrix that will be set to the UB matrix.
  @param  a_dir   The real space edge vector for side a of the unit cell
  @param  b_dir   The real space edge vector for side b of the unit cell
  @param  c_dir   The real space edge vector for side c of the unit cell

  @return true if UB was set to the new matrix and false if UB could not be
          set since the matrix with a,b,c as rows could not be inverted.
 */
bool OrientedLattice::GetUB(DblMatrix &UB, const V3D &a_dir, const V3D &b_dir,
                            const V3D &c_dir) {
  if (UB.numRows() != 3 || UB.numCols() != 3) {
    throw std::invalid_argument("Find_UB(): UB matrix NULL or not 3X3");
  }

  UB.setRow(0, a_dir);
  UB.setRow(1, b_dir);
  UB.setRow(2, c_dir);
  try {
    UB.Invert();
  } catch (...) {
    return false;
  }
  return true;
}
/**
  Get the real space edge vectors a,b,c corresponding to the UB matrix.
  The rows of the inverse of the matrix with will be stored in a_dir,
  b_dir, c_dir.

  @param  UB      A 3x3 matrix containing a UB matrix.
  @param  a_dir   Will be set to the real space edge vector for side a
                  of the unit cell
  @param  b_dir   Will be set to the real space edge vector for side b
                  of the unit cell
  @param  c_dir   Will be set to the real space edge vector for side c
                  of the unit cell

  @return true if the inverse of the matrix UB could be found and the
          a_dir, b_dir and c_dir vectors have been set to the rows of
          UB inverse.
 */
bool OrientedLattice::GetABC(const DblMatrix &UB, V3D &a_dir, V3D &b_dir,
                             V3D &c_dir) {
  if (UB.numRows() != 3 || UB.numCols() != 3) {
    throw std::invalid_argument("GetABC(): UB matrix NULL or not 3X3");
  }

  DblMatrix UB_inverse(UB);
  try {
    UB_inverse.Invert();
  } catch (...) {
    return false;
  }
  a_dir(UB_inverse[0][0], UB_inverse[0][1], UB_inverse[0][2]);
  b_dir(UB_inverse[1][0], UB_inverse[1][1], UB_inverse[1][2]);
  c_dir(UB_inverse[2][0], UB_inverse[2][1], UB_inverse[2][2]);

  return true;
}