Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-16312 constrainted glm issues [nocheck] #16317

Merged
merged 14 commits into from
Aug 9, 2024
Merged
5 changes: 2 additions & 3 deletions h2o-algos/src/main/java/hex/glm/ComputationState.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ public final class ComputationState {
int _totalBetaLength; // actual coefficient length without taking into account active columns only
int _betaLengthPerClass;
public boolean _noReg;
public boolean _hasConstraints;
public ConstrainedGLMUtils.ConstraintGLMStates _csGLMState;

public ComputationState(Job job, GLMParameters parms, DataInfo dinfo, BetaConstraint bc, GLM.BetaInfo bi){
Expand Down Expand Up @@ -1414,7 +1413,7 @@ protected GramXY computeNewGram(DataInfo activeData, double [] beta, GLMParamete
double obj_reg = _parms._obj_reg;
if(_glmw == null) _glmw = new GLMModel.GLMWeightsFun(_parms);
GLMTask.GLMIterationTask gt = new GLMTask.GLMIterationTask(_job._key, activeData, _glmw, beta,
_activeClass, _hasConstraints).doAll(activeData._adaptedFrame);
_activeClass).doAll(activeData._adaptedFrame);
gt._gram.mul(obj_reg);
if (_parms._glmType.equals(GLMParameters.GLMType.gam)) { // add contribution from GAM smoothness factor
Integer[] activeCols=null;
Expand Down Expand Up @@ -1463,7 +1462,7 @@ protected GramGrad computeGram(double [] beta, GLMGradientInfo gradientInfo){
double obj_reg = _parms._obj_reg;
if(_glmw == null) _glmw = new GLMModel.GLMWeightsFun(_parms);
GLMTask.GLMIterationTask gt = new GLMTask.GLMIterationTask(_job._key, activeData, _glmw, beta,
_activeClass, _hasConstraints).doAll(activeData._adaptedFrame);
_activeClass).doAll(activeData._adaptedFrame);
double[][] fullGram = gt._gram.getXX(); // only extract gram matrix
mult(fullGram, obj_reg);
if (_gramEqual != null)
Expand Down
75 changes: 45 additions & 30 deletions h2o-algos/src/main/java/hex/glm/ConstrainedGLMUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public static class ConstraintGLMStates {
double _ckCS;
double _ckCSHalf; // = ck/2
double _epsilonkCS;
double _epsilonkCSSquare;
public double _epsilonkCSSquare;
double _etakCS;
double _etakCSSquare;
double _epsilon0;
Expand Down Expand Up @@ -137,30 +137,35 @@ public static int[] extractBetaConstraints(ComputationState state, String[] coef
List<LinearConstraints> equalityC = new ArrayList<>();
List<LinearConstraints> lessThanEqualToC = new ArrayList<>();
List<Integer> betaIndexOnOff = new ArrayList<>();
if (betaC._betaLB != null) {
int numCons = betaC._betaLB.length-1;
for (int index=0; index<numCons; index++) {
if (!Double.isInfinite(betaC._betaUB[index]) && (betaC._betaLB[index] == betaC._betaUB[index])) { // equality constraint
addBCEqualityConstraint(equalityC, betaC, coefNames, index);
betaIndexOnOff.add(1);
} else if (!Double.isInfinite(betaC._betaUB[index]) && !Double.isInfinite(betaC._betaLB[index]) &&
(betaC._betaLB[index] < betaC._betaUB[index])) { // low < beta < high, generate two lessThanEqualTo constraints
addBCGreaterThanConstraint(lessThanEqualToC, betaC, coefNames, index);
addBCLessThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
betaIndexOnOff.add(0);
} else if (Double.isInfinite(betaC._betaUB[index]) && !Double.isInfinite(betaC._betaLB[index])) { // low < beta < infinity
addBCGreaterThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
} else if (!Double.isInfinite(betaC._betaUB[index]) && Double.isInfinite(betaC._betaLB[index])) { // -infinity < beta < high
addBCLessThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
}
boolean bothEndsPresent = (betaC._betaUB != null) && (betaC._betaLB != null);
boolean lowerEndPresentOnly = (betaC._betaUB == null) && (betaC._betaLB != null);
boolean upperEndPresentOnly = (betaC._betaUB != null) && (betaC._betaLB == null);

int numCons = betaC._betaLB != null ? betaC._betaLB.length - 1 : betaC._betaUB.length - 1;
for (int index = 0; index < numCons; index++) {
if (bothEndsPresent && !Double.isInfinite(betaC._betaUB[index]) && (betaC._betaLB[index] == betaC._betaUB[index])) { // equality constraint
addBCEqualityConstraint(equalityC, betaC, coefNames, index);
betaIndexOnOff.add(1);
} else if (bothEndsPresent && !Double.isInfinite(betaC._betaUB[index]) && !Double.isInfinite(betaC._betaLB[index]) &&
(betaC._betaLB[index] < betaC._betaUB[index])) { // low < beta < high, generate two lessThanEqualTo constraints
addBCGreaterThanConstraint(lessThanEqualToC, betaC, coefNames, index);
addBCLessThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
betaIndexOnOff.add(0);
} else if ((lowerEndPresentOnly || (betaC._betaUB != null && Double.isInfinite(betaC._betaUB[index]))) &&
betaC._betaLB != null && !Double.isInfinite(betaC._betaLB[index])) { // low < beta < infinity
addBCGreaterThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
} else if ((upperEndPresentOnly || (betaC._betaLB != null && Double.isInfinite(betaC._betaLB[index]))) &&
betaC._betaUB != null && !Double.isInfinite(betaC._betaUB[index])) { // -infinity < beta < high
addBCLessThanConstraint(lessThanEqualToC, betaC, coefNames, index);
betaIndexOnOff.add(1);
}
}

state.setLinearConstraints(equalityC.toArray(new LinearConstraints[0]),
lessThanEqualToC.toArray(new LinearConstraints[0]), true);
return betaIndexOnOff.size()==0 ? null : betaIndexOnOff.stream().mapToInt(x->x).toArray();
return betaIndexOnOff.size() == 0 ? null : betaIndexOnOff.stream().mapToInt(x -> x).toArray();
}

/***
Expand Down Expand Up @@ -506,11 +511,10 @@ public static boolean extractCoeffNames(List<String> coeffList, LinearConstraint

public static List<String> foundRedundantConstraints(ComputationState state, final double[][] initConstraintMatrix) {
Matrix constMatrix = new Matrix(initConstraintMatrix);
Matrix constMatrixLessConstant = constMatrix.getMatrix(0, constMatrix.getRowDimension() -1, 1, constMatrix.getColumnDimension()-1);
Matrix constMatrixTConstMatrix = constMatrixLessConstant.times(constMatrixLessConstant.transpose());
int rank = constMatrixLessConstant.rank();
Matrix matrixSquare = constMatrix.times(constMatrix.transpose());
int rank = matrixSquare.rank();
if (rank < constMatrix.getRowDimension()) { // redundant constraints are specified
double[][] rMatVal = constMatrixTConstMatrix.qr().getR().getArray();
double[][] rMatVal = matrixSquare.qr().getR().getArray();
List<Double> diag = IntStream.range(0, rMatVal.length).mapToDouble(x->Math.abs(rMatVal[x][x])).boxed().collect(Collectors.toList());
int[] sortedIndices = IntStream.range(0, diag.size()).boxed().sorted((i, j) -> diag.get(i).compareTo(diag.get(j))).mapToInt(ele->ele).toArray();
List<Integer> duplicatedEleIndice = IntStream.range(0, diag.size()-rank).map(x -> sortedIndices[x]).boxed().collect(Collectors.toList());
Expand Down Expand Up @@ -645,6 +649,16 @@ public static void genInitialLambda(Random randObj, LinearConstraints[] constrai
}
}

public static void adjustLambda(LinearConstraints[] constraints, double[] lambda) {
int numC = constraints.length;
LinearConstraints oneC;
for (int index=0; index<numC; index++) {
oneC = constraints[index];
if (!oneC._active)
lambda[index]=0.0;
}
}


public static double[][] sumGramConstribution(ConstraintsGram[] gramConstraints, int numCoefs) {
if (gramConstraints == null)
Expand Down Expand Up @@ -714,16 +728,16 @@ public static void updateConstraintParameters(ComputationState state, double[] l
LinearConstraints[] equalConst, LinearConstraints[] lessThanConst,
GLMModel.GLMParameters parms) {
// calculate ||h(beta)|| square, ||gradient|| square
double hBetaMag = state._csGLMState._constraintMagSquare;
if (hBetaMag <= state._csGLMState._etakCSSquare) { // implement line 26 to line 29 of Algorithm 19.1
double hBetaMagSquare = state._csGLMState._constraintMagSquare;
if (hBetaMagSquare <= state._csGLMState._etakCSSquare) { // implement line 26 to line 29 of Algorithm 19.1
if (equalConst != null)
updateLambda(lambdaEqual, state._csGLMState._ckCS, equalConst);
if (lessThanConst != null)
updateLambda(lambdaLessThan, state._csGLMState._ckCS, lessThanConst);
state._csGLMState._epsilonkCS = state._csGLMState._epsilonkCS/state._csGLMState._ckCS;
state ._csGLMState._etakCS = state._csGLMState._etakCS/Math.pow(state._csGLMState._ckCS, parms._constraint_beta);
} else { // implement line 31 to 34 of Algorithm 19.1
state._csGLMState._ckCS = state._csGLMState._ckCS*parms._constraint_tau;
state._csGLMState._ckCS = state._csGLMState._ckCS*parms._constraint_tau; // tau belongs to [4,10]
state._csGLMState._ckCSHalf = state._csGLMState._ckCS*0.5;
state._csGLMState._epsilonkCS = state._csGLMState._epsilon0/state._csGLMState._ckCS;
state._csGLMState._etakCS = parms._constraint_eta0/Math.pow(state._csGLMState._ckCS, parms._constraint_alpha);
Expand Down Expand Up @@ -813,13 +827,14 @@ public static void updateConstraintValues(double[] betaCnd, List<String> coefNam
if (equalityConstraints != null) // equality constraints
Arrays.stream(equalityConstraints).forEach(constraint -> {
evalOneConstraint(constraint, betaCnd, coefNames);
constraint._active = (Math.abs(constraint._constraintsVal) > EPS2);
// constraint._active = (Math.abs(constraint._constraintsVal) > EPS2);
constraint._active = true;
});

if (lessThanEqualToConstraints != null) // less than or equal to constraints
Arrays.stream(lessThanEqualToConstraints).forEach(constraint -> {
evalOneConstraint(constraint, betaCnd, coefNames);
constraint._active = constraint._constraintsVal > 0;
constraint._active = constraint._constraintsVal >= 0;
});
}

Expand Down
Loading