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 move contrained GLM fix from master to release branch (#16317) [nochecks][nocheck] #16383

Merged
merged 1 commit into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading