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.SolverVariable.STRENGTH_EQUALITY; 20 import static androidx.constraintlayout.core.SolverVariable.STRENGTH_HIGH; 21 import static androidx.constraintlayout.core.SolverVariable.STRENGTH_HIGHEST; 22 import static androidx.constraintlayout.core.SolverVariable.STRENGTH_LOW; 23 import static androidx.constraintlayout.core.SolverVariable.STRENGTH_MEDIUM; 24 25 import java.util.ArrayList; 26 27 public class ArrayRow implements LinearSystem.Row { 28 private static final boolean DEBUG = false; 29 30 SolverVariable mVariable = null; 31 float mConstantValue = 0; 32 boolean mUsed = false; 33 private static final boolean FULL_NEW_CHECK = false; // full validation (debug purposes) 34 35 ArrayList<SolverVariable> mVariablesToUpdate = new ArrayList<>(); 36 37 public ArrayRowVariables variables; 38 39 public interface ArrayRowVariables { 40 41 // @TODO: add description getCurrentSize()42 int getCurrentSize(); 43 44 // @TODO: add description getVariable(int index)45 SolverVariable getVariable(int index); 46 47 // @TODO: add description getVariableValue(int index)48 float getVariableValue(int index); 49 50 // @TODO: add description get(SolverVariable variable)51 float get(SolverVariable variable); 52 53 // @TODO: add description indexOf(SolverVariable variable)54 int indexOf(SolverVariable variable); 55 56 // @TODO: add description display()57 void display(); 58 59 // @TODO: add description clear()60 void clear(); 61 62 // @TODO: add description contains(SolverVariable variable)63 boolean contains(SolverVariable variable); 64 65 // @TODO: add description put(SolverVariable variable, float value)66 void put(SolverVariable variable, float value); 67 68 // @TODO: add description sizeInBytes()69 int sizeInBytes(); 70 71 // @TODO: add description invert()72 void invert(); 73 74 // @TODO: add description remove(SolverVariable v, boolean removeFromDefinition)75 float remove(SolverVariable v, boolean removeFromDefinition); 76 77 // @TODO: add description divideByAmount(float amount)78 void divideByAmount(float amount); 79 80 // @TODO: add description add(SolverVariable v, float value, boolean removeFromDefinition)81 void add(SolverVariable v, float value, boolean removeFromDefinition); 82 83 // @TODO: add description use(ArrayRow definition, boolean removeFromDefinition)84 float use(ArrayRow definition, boolean removeFromDefinition); 85 } 86 87 boolean mIsSimpleDefinition = false; 88 ArrayRow()89 public ArrayRow() { 90 } 91 ArrayRow(Cache cache)92 public ArrayRow(Cache cache) { 93 variables = new ArrayLinkedVariables(this, cache); 94 //variables = new OptimizedSolverVariableValues(this, cache); 95 } 96 hasKeyVariable()97 boolean hasKeyVariable() { 98 return !( 99 (mVariable == null) 100 || (mVariable.mType != SolverVariable.Type.UNRESTRICTED 101 && mConstantValue < 0) 102 ); 103 } 104 105 // @TODO: add description 106 @Override toString()107 public String toString() { 108 return toReadableString(); 109 } 110 toReadableString()111 String toReadableString() { 112 String s = ""; 113 if (mVariable == null) { 114 s += "0"; 115 } else { 116 s += mVariable; 117 } 118 s += " = "; 119 boolean addedVariable = false; 120 if (mConstantValue != 0) { 121 s += mConstantValue; 122 addedVariable = true; 123 } 124 int count = variables.getCurrentSize(); 125 for (int i = 0; i < count; i++) { 126 SolverVariable v = variables.getVariable(i); 127 if (v == null) { 128 continue; 129 } 130 float amount = variables.getVariableValue(i); 131 if (amount == 0) { 132 continue; 133 } 134 String name = v.toString(); 135 if (!addedVariable) { 136 if (amount < 0) { 137 s += "- "; 138 amount *= -1; 139 } 140 } else { 141 if (amount > 0) { 142 s += " + "; 143 } else { 144 s += " - "; 145 amount *= -1; 146 } 147 } 148 if (amount == 1) { 149 s += name; 150 } else { 151 s += amount + " " + name; 152 } 153 addedVariable = true; 154 } 155 if (!addedVariable) { 156 s += "0.0"; 157 } 158 if (DEBUG) { 159 variables.display(); 160 } 161 return s; 162 } 163 164 // @TODO: add description reset()165 public void reset() { 166 mVariable = null; 167 variables.clear(); 168 mConstantValue = 0; 169 mIsSimpleDefinition = false; 170 } 171 hasVariable(SolverVariable v)172 boolean hasVariable(SolverVariable v) { 173 return variables.contains(v); 174 } 175 createRowDefinition(SolverVariable variable, int value)176 ArrayRow createRowDefinition(SolverVariable variable, int value) { 177 this.mVariable = variable; 178 variable.computedValue = value; 179 mConstantValue = value; 180 mIsSimpleDefinition = true; 181 return this; 182 } 183 184 // @TODO: add description createRowEquals(SolverVariable variable, int value)185 public ArrayRow createRowEquals(SolverVariable variable, int value) { 186 if (value < 0) { 187 mConstantValue = -1 * value; 188 variables.put(variable, 1); 189 } else { 190 mConstantValue = value; 191 variables.put(variable, -1); 192 } 193 return this; 194 } 195 196 // @TODO: add description createRowEquals(SolverVariable variableA, SolverVariable variableB, int margin)197 public ArrayRow createRowEquals(SolverVariable variableA, 198 SolverVariable variableB, 199 int margin) { 200 boolean inverse = false; 201 if (margin != 0) { 202 int m = margin; 203 if (m < 0) { 204 m = -1 * m; 205 inverse = true; 206 } 207 mConstantValue = m; 208 } 209 if (!inverse) { 210 variables.put(variableA, -1); 211 variables.put(variableB, 1); 212 } else { 213 variables.put(variableA, 1); 214 variables.put(variableB, -1); 215 } 216 return this; 217 } 218 219 // @TODO: add description addSingleError(SolverVariable error, int sign)220 ArrayRow addSingleError(SolverVariable error, int sign) { 221 variables.put(error, (float) sign); 222 return this; 223 } 224 225 // @TODO: add description createRowGreaterThan(SolverVariable variableA, SolverVariable variableB, SolverVariable slack, int margin)226 public ArrayRow createRowGreaterThan(SolverVariable variableA, 227 SolverVariable variableB, SolverVariable slack, 228 int margin) { 229 boolean inverse = false; 230 if (margin != 0) { 231 int m = margin; 232 if (m < 0) { 233 m = -1 * m; 234 inverse = true; 235 } 236 mConstantValue = m; 237 } 238 if (!inverse) { 239 variables.put(variableA, -1); 240 variables.put(variableB, 1); 241 variables.put(slack, 1); 242 } else { 243 variables.put(variableA, 1); 244 variables.put(variableB, -1); 245 variables.put(slack, -1); 246 } 247 return this; 248 } 249 250 // @TODO: add description createRowGreaterThan(SolverVariable a, int b, SolverVariable slack)251 public ArrayRow createRowGreaterThan(SolverVariable a, int b, SolverVariable slack) { 252 mConstantValue = b; 253 variables.put(a, -1); 254 return this; 255 } 256 257 // @TODO: add description createRowLowerThan(SolverVariable variableA, SolverVariable variableB, SolverVariable slack, int margin)258 public ArrayRow createRowLowerThan(SolverVariable variableA, SolverVariable variableB, 259 SolverVariable slack, int margin) { 260 boolean inverse = false; 261 if (margin != 0) { 262 int m = margin; 263 if (m < 0) { 264 m = -1 * m; 265 inverse = true; 266 } 267 mConstantValue = m; 268 } 269 if (!inverse) { 270 variables.put(variableA, -1); 271 variables.put(variableB, 1); 272 variables.put(slack, -1); 273 } else { 274 variables.put(variableA, 1); 275 variables.put(variableB, -1); 276 variables.put(slack, 1); 277 } 278 return this; 279 } 280 281 // @TODO: add description createRowEqualMatchDimensions(float currentWeight, float totalWeights, float nextWeight, SolverVariable variableStartA, SolverVariable variableEndA, SolverVariable variableStartB, SolverVariable variableEndB)282 public ArrayRow createRowEqualMatchDimensions(float currentWeight, 283 float totalWeights, float nextWeight, 284 SolverVariable variableStartA, 285 SolverVariable variableEndA, 286 SolverVariable variableStartB, 287 SolverVariable variableEndB) { 288 mConstantValue = 0; 289 if (totalWeights == 0 || (currentWeight == nextWeight)) { 290 // endA - startA == endB - startB 291 // 0 = startA - endA + endB - startB 292 variables.put(variableStartA, 1); 293 variables.put(variableEndA, -1); 294 variables.put(variableEndB, 1); 295 variables.put(variableStartB, -1); 296 } else { 297 if (currentWeight == 0) { 298 variables.put(variableStartA, 1); 299 variables.put(variableEndA, -1); 300 } else if (nextWeight == 0) { 301 variables.put(variableStartB, 1); 302 variables.put(variableEndB, -1); 303 } else { 304 float cw = currentWeight / totalWeights; 305 float nw = nextWeight / totalWeights; 306 float w = cw / nw; 307 308 // endA - startA == w * (endB - startB) 309 // 0 = startA - endA + w * (endB - startB) 310 variables.put(variableStartA, 1); 311 variables.put(variableEndA, -1); 312 variables.put(variableEndB, w); 313 variables.put(variableStartB, -w); 314 } 315 } 316 return this; 317 } 318 319 // @TODO: add description createRowEqualDimension(float currentWeight, float totalWeights, float nextWeight, SolverVariable variableStartA, int marginStartA, SolverVariable variableEndA, int marginEndA, SolverVariable variableStartB, int marginStartB, SolverVariable variableEndB, int marginEndB)320 public ArrayRow createRowEqualDimension(float currentWeight, 321 float totalWeights, float nextWeight, 322 SolverVariable variableStartA, int marginStartA, 323 SolverVariable variableEndA, int marginEndA, 324 SolverVariable variableStartB, int marginStartB, 325 SolverVariable variableEndB, int marginEndB) { 326 if (totalWeights == 0 || (currentWeight == nextWeight)) { 327 // endA - startA + marginStartA + marginEndA 328 // == endB - startB + marginStartB + marginEndB 329 // 0 = startA - endA - marginStartA - marginEndA 330 // + endB - startB + marginStartB + marginEndB 331 // 0 = (- marginStartA - marginEndA + marginStartB + marginEndB) 332 // + startA - endA + endB - startB 333 mConstantValue = -marginStartA - marginEndA + marginStartB + marginEndB; 334 variables.put(variableStartA, 1); 335 variables.put(variableEndA, -1); 336 variables.put(variableEndB, 1); 337 variables.put(variableStartB, -1); 338 } else { 339 float cw = currentWeight / totalWeights; 340 float nw = nextWeight / totalWeights; 341 float w = cw / nw; 342 // (endA - startA + marginStartA + marginEndA) = 343 // w * (endB - startB) + marginStartB + marginEndB; 344 // 0 = (startA - endA - marginStartA - marginEndA) 345 // + w * (endB - startB) + marginStartB + marginEndB 346 // 0 = (- marginStartA - marginEndA + marginStartB + marginEndB) 347 // + startA - endA + w * endB - w * startB 348 mConstantValue = -marginStartA - marginEndA + w * marginStartB + w * marginEndB; 349 variables.put(variableStartA, 1); 350 variables.put(variableEndA, -1); 351 variables.put(variableEndB, w); 352 variables.put(variableStartB, -w); 353 } 354 return this; 355 } 356 createRowCentering(SolverVariable variableA, SolverVariable variableB, int marginA, float bias, SolverVariable variableC, SolverVariable variableD, int marginB)357 ArrayRow createRowCentering(SolverVariable variableA, SolverVariable variableB, 358 int marginA, float bias, SolverVariable variableC, 359 SolverVariable variableD, int marginB) { 360 if (variableB == variableC) { 361 // centering on the same position 362 // B - A == D - B 363 // 0 = A + D - 2 * B 364 variables.put(variableA, 1); 365 variables.put(variableD, 1); 366 variables.put(variableB, -2); 367 return this; 368 } 369 if (bias == 0.5f) { 370 // don't bother applying the bias, we are centered 371 // A - B = C - D 372 // 0 = A - B - C + D 373 // with margin: 374 // A - B - Ma = C - D - Mb 375 // 0 = A - B - C + D - Ma + Mb 376 variables.put(variableA, 1f); 377 variables.put(variableB, -1f); 378 variables.put(variableC, -1f); 379 variables.put(variableD, 1f); 380 if (marginA > 0 || marginB > 0) { 381 mConstantValue = -marginA + marginB; 382 } 383 } else if (bias <= 0) { 384 // A = B + m 385 variables.put(variableA, -1); 386 variables.put(variableB, 1); 387 mConstantValue = marginA; 388 } else if (bias >= 1) { 389 // D = C - m 390 variables.put(variableD, -1); 391 variables.put(variableC, 1); 392 mConstantValue = -marginB; 393 } else { 394 variables.put(variableA, 1 * (1 - bias)); 395 variables.put(variableB, -1 * (1 - bias)); 396 variables.put(variableC, -1 * bias); 397 variables.put(variableD, 1 * bias); 398 if (marginA > 0 || marginB > 0) { 399 mConstantValue = -marginA * (1 - bias) + marginB * bias; 400 } 401 } 402 return this; 403 } 404 405 // @TODO: add description addError(LinearSystem system, int strength)406 public ArrayRow addError(LinearSystem system, int strength) { 407 variables.put(system.createErrorVariable(strength, "ep"), 1); 408 variables.put(system.createErrorVariable(strength, "em"), -1); 409 return this; 410 } 411 createRowDimensionPercent(SolverVariable variableA, SolverVariable variableC, float percent)412 ArrayRow createRowDimensionPercent(SolverVariable variableA, 413 SolverVariable variableC, float percent) { 414 variables.put(variableA, -1); 415 variables.put(variableC, percent); 416 return this; 417 } 418 419 /** 420 * Create a constraint to express {@code A = B + (C - D)} * ratio 421 * We use this for ratio, where for example {@code Right = Left + (Bottom - Top) * percent} 422 * 423 * @param variableA variable A 424 * @param variableB variable B 425 * @param variableC variable C 426 * @param variableD variable D 427 * @param ratio ratio between AB and CD 428 * @return the row 429 */ createRowDimensionRatio(SolverVariable variableA, SolverVariable variableB, SolverVariable variableC, SolverVariable variableD, float ratio)430 public ArrayRow createRowDimensionRatio(SolverVariable variableA, SolverVariable variableB, 431 SolverVariable variableC, SolverVariable variableD, 432 float ratio) { 433 // A = B + (C - D) * ratio 434 variables.put(variableA, -1); 435 variables.put(variableB, 1); 436 variables.put(variableC, ratio); 437 variables.put(variableD, -ratio); 438 return this; 439 } 440 441 /** 442 * Create a constraint to express At + (Ab-At)/2 = Bt + (Bb-Bt)/2 - angle 443 */ createRowWithAngle(SolverVariable at, SolverVariable ab, SolverVariable bt, SolverVariable bb, float angleComponent)444 public ArrayRow createRowWithAngle(SolverVariable at, 445 SolverVariable ab, 446 SolverVariable bt, 447 SolverVariable bb, 448 float angleComponent) { 449 variables.put(bt, 0.5f); 450 variables.put(bb, 0.5f); 451 variables.put(at, -0.5f); 452 variables.put(ab, -0.5f); 453 mConstantValue = -angleComponent; 454 return this; 455 } 456 sizeInBytes()457 int sizeInBytes() { 458 int size = 0; 459 if (mVariable != null) { 460 size += 4; // object 461 } 462 size += 4; // constantValue 463 size += 4; // used 464 465 size += variables.sizeInBytes(); 466 return size; 467 } 468 ensurePositiveConstant()469 void ensurePositiveConstant() { 470 // Ensure that if we have a constant it's positive 471 if (mConstantValue < 0) { 472 // If not, simply multiply the equation by -1 473 mConstantValue *= -1; 474 variables.invert(); 475 } 476 } 477 478 /** 479 * Pick a subject variable out of the existing ones. 480 * - if a variable is unrestricted 481 * - or if it's a negative new variable (not found elsewhere) 482 * - otherwise we have to add a new additional variable 483 * 484 * @return true if we added an extra variable to the system 485 */ chooseSubject(LinearSystem system)486 boolean chooseSubject(LinearSystem system) { 487 boolean addedExtra = false; 488 SolverVariable pivotCandidate = chooseSubjectInVariables(system); 489 if (pivotCandidate == null) { 490 // need to add extra variable 491 addedExtra = true; 492 } else { 493 pivot(pivotCandidate); 494 } 495 if (variables.getCurrentSize() == 0) { 496 mIsSimpleDefinition = true; 497 } 498 return addedExtra; 499 } 500 501 /** 502 * Pick a subject variable out of the existing ones. 503 * - if a variable is unrestricted 504 * - or if it's a negative new variable (not found elsewhere) 505 * - otherwise we return null 506 * 507 * @return a candidate variable we can pivot on or null if not found 508 */ chooseSubjectInVariables(LinearSystem system)509 SolverVariable chooseSubjectInVariables(LinearSystem system) { 510 // if unrestricted, pick it 511 // if restricted, needs to be < 0 and new 512 // 513 SolverVariable restrictedCandidate = null; 514 SolverVariable unrestrictedCandidate = null; 515 float unrestrictedCandidateAmount = 0; 516 float restrictedCandidateAmount = 0; 517 boolean unrestrictedCandidateIsNew = false; 518 boolean restrictedCandidateIsNew = false; 519 520 final int currentSize = variables.getCurrentSize(); 521 for (int i = 0; i < currentSize; i++) { 522 float amount = variables.getVariableValue(i); 523 SolverVariable variable = variables.getVariable(i); 524 if (variable.mType == SolverVariable.Type.UNRESTRICTED) { 525 if (unrestrictedCandidate == null) { 526 unrestrictedCandidate = variable; 527 unrestrictedCandidateAmount = amount; 528 unrestrictedCandidateIsNew = isNew(variable, system); 529 } else if (unrestrictedCandidateAmount > amount) { 530 unrestrictedCandidate = variable; 531 unrestrictedCandidateAmount = amount; 532 unrestrictedCandidateIsNew = isNew(variable, system); 533 } else if (!unrestrictedCandidateIsNew && isNew(variable, system)) { 534 unrestrictedCandidate = variable; 535 unrestrictedCandidateAmount = amount; 536 unrestrictedCandidateIsNew = true; 537 } 538 } else if (unrestrictedCandidate == null) { 539 if (amount < 0) { 540 if (restrictedCandidate == null) { 541 restrictedCandidate = variable; 542 restrictedCandidateAmount = amount; 543 restrictedCandidateIsNew = isNew(variable, system); 544 } else if (restrictedCandidateAmount > amount) { 545 restrictedCandidate = variable; 546 restrictedCandidateAmount = amount; 547 restrictedCandidateIsNew = isNew(variable, system); 548 } else if (!restrictedCandidateIsNew && isNew(variable, system)) { 549 restrictedCandidate = variable; 550 restrictedCandidateAmount = amount; 551 restrictedCandidateIsNew = true; 552 } 553 } 554 } 555 } 556 557 if (unrestrictedCandidate != null) { 558 return unrestrictedCandidate; 559 } 560 return restrictedCandidate; 561 } 562 563 /** 564 * Returns true if the variable is new to the system, i.e. is already present 565 * in one of the rows. This function is called while choosing the subject of a new row. 566 * 567 * @param variable the variable to check for 568 * @param system the linear system we check 569 */ isNew(SolverVariable variable, LinearSystem system)570 private boolean isNew(SolverVariable variable, LinearSystem system) { 571 if (FULL_NEW_CHECK) { 572 boolean isNew = true; 573 for (int i = 0; i < system.mNumRows; i++) { 574 ArrayRow row = system.mRows[i]; 575 if (row.hasVariable(variable)) { 576 isNew = false; 577 } 578 } 579 if (variable.usageInRowCount <= 1 != isNew) { 580 System.out.println("Problem with usage tracking"); 581 } 582 return isNew; 583 } 584 // We maintain a usage count -- variables are ref counted if they are present 585 // in the right side of a row or not. If the count is zero or one, the variable 586 // is new (if one, it means it exist in a row, but this is the row we insert) 587 return variable.usageInRowCount <= 1; 588 } 589 pivot(SolverVariable v)590 void pivot(SolverVariable v) { 591 if (mVariable != null) { 592 // first, move back the variable to its column 593 variables.put(mVariable, -1f); 594 mVariable.mDefinitionId = -1; 595 mVariable = null; 596 } 597 598 float amount = variables.remove(v, true) * -1; 599 mVariable = v; 600 if (amount == 1) { 601 return; 602 } 603 mConstantValue = mConstantValue / amount; 604 variables.divideByAmount(amount); 605 } 606 607 // Row compatibility 608 609 @Override isEmpty()610 public boolean isEmpty() { 611 return (mVariable == null && mConstantValue == 0 && variables.getCurrentSize() == 0); 612 } 613 614 @Override updateFromRow(LinearSystem system, ArrayRow definition, boolean removeFromDefinition)615 public void updateFromRow(LinearSystem system, 616 ArrayRow definition, 617 boolean removeFromDefinition) { 618 float value = variables.use(definition, removeFromDefinition); 619 620 mConstantValue += definition.mConstantValue * value; 621 if (removeFromDefinition) { 622 definition.mVariable.removeFromRow(this); 623 } 624 if (LinearSystem.SIMPLIFY_SYNONYMS 625 && mVariable != null && variables.getCurrentSize() == 0) { 626 mIsSimpleDefinition = true; 627 system.hasSimpleDefinition = true; 628 } 629 } 630 631 // @TODO: add description 632 @Override updateFromFinalVariable(LinearSystem system, SolverVariable variable, boolean removeFromDefinition)633 public void updateFromFinalVariable(LinearSystem system, 634 SolverVariable variable, 635 boolean removeFromDefinition) { 636 if (variable == null || !variable.isFinalValue) { 637 return; 638 } 639 float value = variables.get(variable); 640 mConstantValue += variable.computedValue * value; 641 variables.remove(variable, removeFromDefinition); 642 if (removeFromDefinition) { 643 variable.removeFromRow(this); 644 } 645 if (LinearSystem.SIMPLIFY_SYNONYMS 646 && variables.getCurrentSize() == 0) { 647 mIsSimpleDefinition = true; 648 system.hasSimpleDefinition = true; 649 } 650 } 651 652 // @TODO: add description updateFromSynonymVariable(LinearSystem system, SolverVariable variable, boolean removeFromDefinition)653 public void updateFromSynonymVariable(LinearSystem system, 654 SolverVariable variable, 655 boolean removeFromDefinition) { 656 if (variable == null || !variable.mIsSynonym) { 657 return; 658 } 659 float value = variables.get(variable); 660 mConstantValue += variable.mSynonymDelta * value; 661 variables.remove(variable, removeFromDefinition); 662 if (removeFromDefinition) { 663 variable.removeFromRow(this); 664 } 665 variables.add(system.mCache.mIndexedVariables[variable.mSynonym], 666 value, removeFromDefinition); 667 if (LinearSystem.SIMPLIFY_SYNONYMS 668 && variables.getCurrentSize() == 0) { 669 mIsSimpleDefinition = true; 670 system.hasSimpleDefinition = true; 671 } 672 } 673 pickPivotInVariables(boolean[] avoid, SolverVariable exclude)674 private SolverVariable pickPivotInVariables(boolean[] avoid, SolverVariable exclude) { 675 boolean all = true; 676 float value = 0; 677 SolverVariable pivot = null; 678 SolverVariable pivotSlack = null; 679 float valueSlack = 0; 680 681 final int currentSize = variables.getCurrentSize(); 682 for (int i = 0; i < currentSize; i++) { 683 float currentValue = variables.getVariableValue(i); 684 if (currentValue < 0) { 685 // We can return the first negative candidate as in ArrayLinkedVariables 686 // they are already sorted by id 687 SolverVariable v = variables.getVariable(i); 688 if (!((avoid != null && avoid[v.id]) || (v == exclude))) { 689 if (all) { 690 if (v.mType == SolverVariable.Type.SLACK 691 || v.mType == SolverVariable.Type.ERROR) { 692 if (currentValue < value) { 693 value = currentValue; 694 pivot = v; 695 } 696 } 697 } else { 698 if (v.mType == SolverVariable.Type.SLACK) { 699 if (currentValue < valueSlack) { 700 valueSlack = currentValue; 701 pivotSlack = v; 702 } 703 } else if (v.mType == SolverVariable.Type.ERROR) { 704 if (currentValue < value) { 705 value = currentValue; 706 pivot = v; 707 } 708 } 709 } 710 } 711 } 712 } 713 if (all) { 714 return pivot; 715 } 716 return pivot != null ? pivot : pivotSlack; 717 } 718 719 // @TODO: add description pickPivot(SolverVariable exclude)720 public SolverVariable pickPivot(SolverVariable exclude) { 721 return pickPivotInVariables(null, exclude); 722 } 723 724 @Override getPivotCandidate(LinearSystem system, boolean[] avoid)725 public SolverVariable getPivotCandidate(LinearSystem system, boolean[] avoid) { 726 return pickPivotInVariables(avoid, null); 727 } 728 729 @Override clear()730 public void clear() { 731 variables.clear(); 732 mVariable = null; 733 mConstantValue = 0; 734 } 735 736 /** 737 * Used to initiate a goal from a given row (to see if we can remove an extra var) 738 */ 739 @Override initFromRow(@uppressWarnings"HiddenTypeParameter") LinearSystem.Row row)740 public void initFromRow(@SuppressWarnings("HiddenTypeParameter") LinearSystem.Row row) { 741 if (row instanceof ArrayRow) { 742 ArrayRow copiedRow = (ArrayRow) row; 743 mVariable = null; 744 variables.clear(); 745 for (int i = 0; i < copiedRow.variables.getCurrentSize(); i++) { 746 SolverVariable var = copiedRow.variables.getVariable(i); 747 float val = copiedRow.variables.getVariableValue(i); 748 variables.add(var, val, true); 749 } 750 } 751 } 752 753 @Override addError(SolverVariable error)754 public void addError(SolverVariable error) { 755 float weight = 1; 756 if (error.strength == STRENGTH_LOW) { 757 weight = 1F; 758 } else if (error.strength == STRENGTH_MEDIUM) { 759 weight = 1E3F; 760 } else if (error.strength == STRENGTH_HIGH) { 761 weight = 1E6F; 762 } else if (error.strength == STRENGTH_HIGHEST) { 763 weight = 1E9F; 764 } else if (error.strength == STRENGTH_EQUALITY) { 765 weight = 1E12F; 766 } 767 variables.put(error, weight); 768 } 769 770 @Override getKey()771 public SolverVariable getKey() { 772 return mVariable; 773 } 774 775 @Override updateFromSystem(LinearSystem system)776 public void updateFromSystem(LinearSystem system) { 777 if (system.mRows.length == 0) { 778 return; 779 } 780 781 boolean done = false; 782 while (!done) { 783 int currentSize = variables.getCurrentSize(); 784 for (int i = 0; i < currentSize; i++) { 785 SolverVariable variable = variables.getVariable(i); 786 if (variable.mDefinitionId != -1 || variable.isFinalValue || variable.mIsSynonym) { 787 mVariablesToUpdate.add(variable); 788 } 789 } 790 final int size = mVariablesToUpdate.size(); 791 if (size > 0) { 792 for (int i = 0; i < size; i++) { 793 SolverVariable variable = mVariablesToUpdate.get(i); 794 if (variable.isFinalValue) { 795 updateFromFinalVariable(system, variable, true); 796 } else if (variable.mIsSynonym) { 797 updateFromSynonymVariable(system, variable, true); 798 } else { 799 updateFromRow(system, system.mRows[variable.mDefinitionId], true); 800 } 801 } 802 mVariablesToUpdate.clear(); 803 } else { 804 done = true; 805 } 806 } 807 if (LinearSystem.SIMPLIFY_SYNONYMS 808 && mVariable != null && variables.getCurrentSize() == 0) { 809 mIsSimpleDefinition = true; 810 system.hasSimpleDefinition = true; 811 } 812 } 813 } 814