1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.constraintlayout.core; 18 19 import static androidx.constraintlayout.core.LinearSystem.FULL_DEBUG; 20 21 import java.util.Arrays; 22 import java.util.HashSet; 23 24 /** 25 * Represents a given variable used in the {@link LinearSystem linear expression solver}. 26 */ 27 public class SolverVariable implements Comparable<SolverVariable> { 28 29 private static final boolean INTERNAL_DEBUG = FULL_DEBUG; 30 private static final boolean VAR_USE_HASH = false; 31 private static final boolean DO_NOT_USE = false; 32 33 34 @SuppressWarnings("WeakerAccess") 35 public static final int STRENGTH_NONE = 0; 36 public static final int STRENGTH_LOW = 1; 37 public static final int STRENGTH_MEDIUM = 2; 38 public static final int STRENGTH_HIGH = 3; 39 @SuppressWarnings("WeakerAccess") 40 public static final int STRENGTH_HIGHEST = 4; 41 public static final int STRENGTH_EQUALITY = 5; 42 public static final int STRENGTH_BARRIER = 6; 43 public static final int STRENGTH_CENTERING = 7; 44 public static final int STRENGTH_FIXED = 8; 45 46 private static int sUniqueSlackId = 1; 47 private static int sUniqueErrorId = 1; 48 private static int sUniqueUnrestrictedId = 1; 49 private static int sUniqueConstantId = 1; 50 private static int sUniqueId = 1; 51 public boolean inGoal; 52 53 private String mName; 54 55 public int id = -1; 56 int mDefinitionId = -1; 57 public int strength = 0; 58 public float computedValue; 59 public boolean isFinalValue = false; 60 61 static final int MAX_STRENGTH = 9; 62 float[] mStrengthVector = new float[MAX_STRENGTH]; 63 float[] mGoalStrengthVector = new float[MAX_STRENGTH]; 64 65 Type mType; 66 67 ArrayRow[] mClientEquations = new ArrayRow[16]; 68 int mClientEquationsCount = 0; 69 public int usageInRowCount = 0; 70 boolean mIsSynonym = false; 71 int mSynonym = -1; 72 float mSynonymDelta = 0; 73 74 /** 75 * Type of variables 76 */ 77 public enum Type { 78 /** 79 * The variable can take negative or positive values 80 */ 81 UNRESTRICTED, 82 /** 83 * The variable is actually not a variable :) , but a constant number 84 */ 85 CONSTANT, 86 /** 87 * The variable is restricted to positive values and represents a slack 88 */ 89 SLACK, 90 /** 91 * The variable is restricted to positive values and represents an error 92 */ 93 ERROR, 94 /** 95 * Unknown (invalid) type. 96 */ 97 UNKNOWN 98 } 99 increaseErrorId()100 static void increaseErrorId() { 101 sUniqueErrorId++; 102 } 103 getUniqueName(Type type, String prefix)104 private static String getUniqueName(Type type, String prefix) { 105 if (prefix != null) { 106 return prefix + sUniqueErrorId; 107 } 108 switch (type) { 109 case UNRESTRICTED: 110 return "U" + ++sUniqueUnrestrictedId; 111 case CONSTANT: 112 return "C" + ++sUniqueConstantId; 113 case SLACK: 114 return "S" + ++sUniqueSlackId; 115 case ERROR: { 116 return "e" + ++sUniqueErrorId; 117 } 118 case UNKNOWN: 119 return "V" + ++sUniqueId; 120 } 121 throw new AssertionError(type.name()); 122 } 123 124 /** 125 * Base constructor 126 * 127 * @param name the variable name 128 * @param type the type of the variable 129 */ SolverVariable(String name, Type type)130 public SolverVariable(String name, Type type) { 131 mName = name; 132 mType = type; 133 } 134 SolverVariable(Type type, String prefix)135 public SolverVariable(Type type, String prefix) { 136 mType = type; 137 if (INTERNAL_DEBUG) { 138 //mName = getUniqueName(type, prefix); 139 } 140 } 141 clearStrengths()142 void clearStrengths() { 143 for (int i = 0; i < MAX_STRENGTH; i++) { 144 mStrengthVector[i] = 0; 145 } 146 } 147 strengthsToString()148 String strengthsToString() { 149 String representation = this + "["; 150 boolean negative = false; 151 boolean empty = true; 152 for (int j = 0; j < mStrengthVector.length; j++) { 153 representation += mStrengthVector[j]; 154 if (mStrengthVector[j] > 0) { 155 negative = false; 156 } else if (mStrengthVector[j] < 0) { 157 negative = true; 158 } 159 if (mStrengthVector[j] != 0) { 160 empty = false; 161 } 162 if (j < mStrengthVector.length - 1) { 163 representation += ", "; 164 } else { 165 representation += "] "; 166 } 167 } 168 if (negative) { 169 representation += " (-)"; 170 } 171 if (empty) { 172 representation += " (*)"; 173 } 174 // representation += " {id: " + id + "}"; 175 return representation; 176 } 177 178 HashSet<ArrayRow> mInRows = VAR_USE_HASH ? new HashSet<ArrayRow>() : null; 179 180 // @TODO: add description addToRow(ArrayRow row)181 public final void addToRow(ArrayRow row) { 182 if (VAR_USE_HASH) { 183 mInRows.add(row); 184 } else { 185 for (int i = 0; i < mClientEquationsCount; i++) { 186 if (mClientEquations[i] == row) { 187 return; 188 } 189 } 190 if (mClientEquationsCount >= mClientEquations.length) { 191 mClientEquations = Arrays.copyOf(mClientEquations, mClientEquations.length * 2); 192 } 193 mClientEquations[mClientEquationsCount] = row; 194 mClientEquationsCount++; 195 } 196 } 197 198 // @TODO: add description removeFromRow(ArrayRow row)199 public final void removeFromRow(ArrayRow row) { 200 if (VAR_USE_HASH) { 201 mInRows.remove(row); 202 } else { 203 final int count = mClientEquationsCount; 204 for (int i = 0; i < count; i++) { 205 if (mClientEquations[i] == row) { 206 for (int j = i; j < count - 1; j++) { 207 mClientEquations[j] = mClientEquations[j + 1]; 208 } 209 mClientEquationsCount--; 210 return; 211 } 212 } 213 } 214 } 215 216 // @TODO: add description updateReferencesWithNewDefinition(LinearSystem system, ArrayRow definition)217 public final void updateReferencesWithNewDefinition(LinearSystem system, ArrayRow definition) { 218 if (VAR_USE_HASH) { 219 for (ArrayRow row : mInRows) { 220 row.updateFromRow(system, definition, false); 221 } 222 mInRows.clear(); 223 } else { 224 final int count = mClientEquationsCount; 225 for (int i = 0; i < count; i++) { 226 mClientEquations[i].updateFromRow(system, definition, false); 227 } 228 mClientEquationsCount = 0; 229 } 230 } 231 232 // @TODO: add description setFinalValue(LinearSystem system, float value)233 public void setFinalValue(LinearSystem system, float value) { 234 if (DO_NOT_USE && INTERNAL_DEBUG) { 235 System.out.println("Set final value for " + this + " of " + value); 236 } 237 computedValue = value; 238 isFinalValue = true; 239 mIsSynonym = false; 240 mSynonym = -1; 241 mSynonymDelta = 0; 242 final int count = mClientEquationsCount; 243 mDefinitionId = -1; 244 for (int i = 0; i < count; i++) { 245 mClientEquations[i].updateFromFinalVariable(system, this, false); 246 } 247 mClientEquationsCount = 0; 248 } 249 250 // @TODO: add description setSynonym(LinearSystem system, SolverVariable synonymVariable, float value)251 public void setSynonym(LinearSystem system, SolverVariable synonymVariable, float value) { 252 if (INTERNAL_DEBUG) { 253 System.out.println("Set synonym for " + this + " = " + synonymVariable + " + " + value); 254 } 255 mIsSynonym = true; 256 mSynonym = synonymVariable.id; 257 mSynonymDelta = value; 258 final int count = mClientEquationsCount; 259 mDefinitionId = -1; 260 for (int i = 0; i < count; i++) { 261 mClientEquations[i].updateFromSynonymVariable(system, this, false); 262 } 263 mClientEquationsCount = 0; 264 system.displayReadableRows(); 265 } 266 267 // @TODO: add description reset()268 public void reset() { 269 mName = null; 270 mType = Type.UNKNOWN; 271 strength = SolverVariable.STRENGTH_NONE; 272 id = -1; 273 mDefinitionId = -1; 274 computedValue = 0; 275 isFinalValue = false; 276 mIsSynonym = false; 277 mSynonym = -1; 278 mSynonymDelta = 0; 279 if (VAR_USE_HASH) { 280 mInRows.clear(); 281 } else { 282 final int count = mClientEquationsCount; 283 for (int i = 0; i < count; i++) { 284 mClientEquations[i] = null; 285 } 286 mClientEquationsCount = 0; 287 } 288 usageInRowCount = 0; 289 inGoal = false; 290 Arrays.fill(mGoalStrengthVector, 0); 291 } 292 293 /** 294 * Accessor for the name 295 * 296 * @return the name of the variable 297 */ getName()298 public String getName() { 299 return mName; 300 } 301 setName(String name)302 public void setName(String name) { 303 mName = name; 304 } 305 306 // @TODO: add description setType(Type type, String prefix)307 public void setType(Type type, String prefix) { 308 mType = type; 309 if (INTERNAL_DEBUG && mName == null) { 310 mName = getUniqueName(type, prefix); 311 } 312 } 313 314 @Override compareTo(SolverVariable v)315 public int compareTo(SolverVariable v) { 316 return this.id - v.id; 317 } 318 319 /** 320 * Override the toString() method to display the variable 321 */ 322 @Override toString()323 public String toString() { 324 String result = ""; 325 if (INTERNAL_DEBUG) { 326 result += mName + "(" + id + "):" + strength; 327 if (mIsSynonym) { 328 result += ":S(" + mSynonym + ")"; 329 } 330 if (isFinalValue) { 331 result += ":F(" + computedValue + ")"; 332 } 333 } else { 334 if (mName != null) { 335 result += mName; 336 } else { 337 result += id; 338 } 339 } 340 return result; 341 } 342 343 } 344