001/* Class for representing a solution. 002 003 Copyright (c) 2003-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_3 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.moml.unit; 028 029import java.awt.Color; 030import java.text.DecimalFormat; 031import java.util.Iterator; 032import java.util.Vector; 033 034import ptolemy.actor.IOPort; 035import ptolemy.actor.IORelation; 036import ptolemy.actor.TypedCompositeActor; 037import ptolemy.actor.TypedIOPort; 038import ptolemy.kernel.ComponentEntity; 039import ptolemy.kernel.util.Attribute; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.NamedObj; 042import ptolemy.moml.MoMLChangeRequest; 043 044/////////////////////////////////////////////////////////////////// 045//// Solution 046 047/** An instance of this class contains a "solution" of Unit constraints. 048 In essence, the solution represents the constraints between a set of Unit 049 variables, and a set of Units. 050 The table below illustrates this. 051 <table border = "1"> 052 <caption>Unit Constraints</caption> 053 <TR> 054 <TH></TH> 055 <TH>V1</TH> 056 <TH>V2</TH> 057 <TH>...</TH> 058 <TH>Vl</TH> 059 <TH></TH> 060 </TR> 061 062 <TR> 063 <TD>C1</TD> 064 <TD>P11</TD> 065 <TD>P12</TD> 066 <TD>...</TD> 067 <TD>P1l</TD> 068 <TD>U1</TD> 069 </TR> 070 071 <TR> 072 <TD>C2</TD> 073 <TD>P21</TD> 074 <TD>P22</TD> 075 <TD>...</TD> 076 <TD>P2l</TD> 077 <TD>U2</TD> 078 </TR> 079 080 <TR> 081 <TD>:</TD> 082 <TD>:</TD> 083 <TD>:</TD> 084 <TD>...</TD> 085 <TD>:</TD> 086 <TD>:</TD> 087 </TR> 088 089 <TR> 090 <TD>Ck</TD> 091 <TD>Pk1</TD> 092 <TD>Pk2</TD> 093 <TD>...</TD> 094 <TD>Pkl</TD> 095 <TD>Uk</TD> 096 </TR> 097 </TABLE> 098 Here, the columns V1, V2, ..., Vl represent l variables. 099 The columns C1, C2, ..., Ck represent k constraints. 100 The U1, U2, ..., Uk on the right represent Units. 101 The meaning of the ith row is that V1^Pi1 + V2^pi2 + .. +Vk^pik = Uk. 102 <p> 103 Generally, this class is used by creating an instance that is derived from 104 the Units specifications of a model. 105 Then, a method is invoked that results in other instances being created that 106 are transformations of the original instance. These transformed instances 107 are equivalent, in a sense, to the original instance. The difference is that 108 they provide a different perspective than that of the original instance. In 109 particular, some of the transformed instances can be used to highlight 110 inconsistencies not apparent in the original instance. 111 @author Rowland R Johnson 112 @version $Id$ 113 @since Ptolemy II 8.0 114 @Pt.ProposedRating Red (rowland) 115 @Pt.AcceptedRating Red (rowland) 116 */ 117public class Solution { 118 /** Construct an empty solution. 119 * This constructor is used only by the copy() method, and, can therefore, 120 * be made private. 121 * 122 */ 123 private Solution() { 124 } 125 126 /** 127 * Construct a Solution from a set of variables, and a set of constraints. 128 * 129 * @param model The model that is the source of the variables and 130 * constraints. 131 * @param vLabels The variables. 132 * @param constraints The constraints. 133 * @exception IllegalActionException If there are problems with transforming 134 * a constraint to canonical form. 135 */ 136 public Solution(TypedCompositeActor model, String[] vLabels, 137 Vector constraints) throws IllegalActionException { 138 _constraints = constraints; 139 _numConstraints = constraints.size(); 140 _variables = vLabels; 141 _model = model; 142 _numVariables = _variables.length; 143 _vectorA = new Unit[_numConstraints]; 144 _source = new NamedObj[_numConstraints]; 145 _done = new boolean[_numConstraints]; 146 _arrayP = new double[_numConstraints][]; 147 148 for (int i = 0; i < _numConstraints; i++) { 149 _arrayP[i] = new double[_numVariables]; 150 _done[i] = false; 151 } 152 153 for (int constraintNum = 0; constraintNum < _numConstraints; constraintNum++) { 154 UnitEquation constraint = (UnitEquation) constraints 155 .elementAt(constraintNum); 156 UnitEquation canonicalEquation = constraint.canonicalize(); 157 Vector rightUTerms = canonicalEquation.getRhs().getUTerms(); 158 159 if (rightUTerms.size() != 1) { 160 throw new IllegalActionException("canonicalEquation " 161 + canonicalEquation + " has nonsingular RHS"); 162 } 163 164 UnitTerm rhsUterm = (UnitTerm) rightUTerms.elementAt(0); 165 166 if (!rhsUterm.isUnit()) { 167 throw new IllegalActionException("canonicalEquation " 168 + canonicalEquation + " has nonUnit RHS"); 169 } 170 171 _vectorA[constraintNum] = rhsUterm.getUnit(); 172 _source[constraintNum] = constraint.getSource(); 173 174 Vector leftUTerms = canonicalEquation.getLhs().getUTerms(); 175 176 for (int i = 0; i < leftUTerms.size(); i++) { 177 UnitTerm leftUTerm = (UnitTerm) leftUTerms.elementAt(i); 178 179 if (leftUTerm == null) { 180 throw new IllegalActionException("canonicalEquation " 181 + canonicalEquation + " has nonVar LHS"); 182 } 183 184 String variableLabel = leftUTerm.getVariable(); 185 double exponent = leftUTerm.getExponent(); 186 int varIndex = -1; 187 188 for (int j = 0; j < _variables.length; j++) { 189 if (_variables[j].equals(variableLabel)) { 190 varIndex = j; 191 break; 192 } 193 } 194 195 _arrayP[constraintNum][varIndex] = exponent; 196 } 197 } 198 } 199 200 /////////////////////////////////////////////////////////////////// 201 //// public methods //// 202 203 /** 204 * Annotates the model so that when it is displayed it will be color coded 205 * and have tooltips that will convey various aspects of the solution. 206 */ 207 public void annotateGraph() { 208 if (_debug) { 209 trace(); 210 } 211 212 String colorString; 213 StringBuffer moml = new StringBuffer(); 214 215 for (int j = 0; j < _numVariables; j++) { 216 String explanation = _varBindings[j]; 217 Color colorValue = null; 218 219 if (_varState[j] == _CONSISTENT) { 220 colorValue = Color.GREEN; 221 } else if (_varState[j] == _INCONSISTENT) { 222 colorValue = Color.RED; 223 } 224 225 colorString = _getColorString(colorValue); 226 moml.append("<port name=\"" + _variables[j] + "\">" 227 + " <property name=\"_color\" " 228 + "class = \"ptolemy.actor.gui.ColorAttribute\" " 229 + "value = \"" + colorString + "\"/>" 230 + "<property name=\"_explanation\" " 231 + "class = \"ptolemy.kernel.util.StringAttribute\" " 232 + "value = \"" + explanation + "\"/>" + "</port>"); 233 } 234 235 for (int constraintNum = 0; constraintNum < _numConstraints; constraintNum++) { 236 NamedObj source = _source[constraintNum]; 237 String expression = _constraintExplanations[constraintNum]; 238 Color colorValue = null; 239 240 if (_constraintState[constraintNum] == _CONSISTENT) { 241 colorValue = Color.GREEN; 242 } else if (_constraintState[constraintNum] == _INCONSISTENT) { 243 colorValue = Color.RED; 244 } 245 246 colorString = _getColorString(colorValue); 247 if (source instanceof IOPort) { 248 IOPort port = (IOPort) source; 249 ComponentEntity actor = (ComponentEntity) port.getContainer(); 250 moml.append("<entity name=\"" + actor.getName() + "\">" 251 + _momlAnnotate(port, colorString, expression) 252 + "</entity>"); 253 } else if (source instanceof IORelation) { 254 IORelation relation = (IORelation) source; 255 moml.append(_momlAnnotate(relation, colorString, expression)); 256 } else if (source instanceof ComponentEntity) { 257 ComponentEntity componentEntity = (ComponentEntity) source; 258 moml.append(_momlAnnotate(componentEntity, colorString, 259 expression)); 260 } 261 } 262 263 if (moml.length() > 0) { 264 String momlUpdate = "<group>" + moml.toString() + "</group>"; 265 MoMLChangeRequest request = new MoMLChangeRequest(this, _model, 266 momlUpdate); 267 request.setUndoable(true); 268 request.setPersistent(false); 269 _debug("Solver.annotateGraph moml " + momlUpdate); 270 _model.requestChange(request); 271 } 272 } 273 274 /** Search for a complete solution. 275 * @return The solution. 276 */ 277 public Solution completeSolution() { 278 _debug("Solver.completeSolution.initial " + headerInfo() + stateInfo()); 279 280 Index g; 281 282 while ((g = _findG()) != null) { 283 _eliminate(g); 284 _debug("Solver.completeSolution " + stateInfo()); 285 } 286 287 for (int i = 0; i < _numConstraints; i++) { 288 _done[i] = true; 289 } 290 291 _analyzeState(); 292 293 if (_debug) { 294 trace(); 295 } 296 297 return this; 298 } 299 300 /** Make a copy of this solution. 301 * @return The copy. 302 */ 303 public Solution copy() { 304 Solution retv = new Solution(); 305 retv._numConstraints = _numConstraints; 306 retv._variables = _variables; 307 retv._model = _model; 308 retv._numVariables = _numVariables; 309 retv._source = _source; 310 retv._debug = _debug; 311 retv._constraints = _constraints; 312 retv._vectorA = new Unit[_numConstraints]; 313 retv._done = new boolean[_numConstraints]; 314 retv._arrayP = new double[_numConstraints][]; 315 316 for (int i = 0; i < _numConstraints; i++) { 317 retv._arrayP[i] = new double[_numVariables]; 318 319 for (int j = 0; j < _numVariables; j++) { 320 retv._arrayP[i][j] = _arrayP[i][j]; 321 } 322 323 retv._done[i] = _done[i]; 324 retv._vectorA[i] = _vectorA[i].copy(); 325 } 326 327 retv._upper = this; 328 return retv; 329 } 330 331 /** Get the state of the solution. 332 * @return The state of the solution. 333 */ 334 public String getShortStateDesc() { 335 switch (_solveState) { 336 case _UNKNOWN: 337 return "UnKnown"; 338 339 case _NONUNIQUE: 340 return "No Unique Solution"; 341 342 case _INCONSISTENT: 343 return "Inconsistent"; 344 345 case _CONSISTENT: 346 return "Consistent"; 347 } 348 349 return "Unknown"; 350 } 351 352 /** Get the state of the solution. 353 * @return The state of the solution. 354 */ 355 public String getStateDesc() { 356 return _stateDescription; 357 } 358 359 /** 360 * Create a human readable presentation of the parts of the solution that 361 * won't change as a result of 362 * the operations necessary to carry out the Gaussian elimination. 363 * I.e. the variable names, and the constraints. 364 * @return A StringBuffer with a human readable presentation of the 365 * invariant parts of the solution. 366 */ 367 public StringBuffer headerInfo() { 368 StringBuffer retv = new StringBuffer(); 369 retv.append("Header\nVariables\n"); 370 371 for (int j = 0; j < _numVariables; j++) { 372 retv.append( 373 " " + _vNumFormat.format(j) + " " + _variables[j] + "\n"); 374 } 375 376 retv.append("\n"); 377 retv.append("ConstrNum Source\n"); 378 379 for (int i = 0; i < _numConstraints; i++) { 380 NamedObj source = _source[i]; 381 retv.append( 382 "" + _vNumFormat.format(i) + " " + source.toString() 383 + " " + ((UnitEquation) _constraints.elementAt(i)) 384 .descriptiveForm() 385 + "\n"); 386 } 387 388 retv.append("\\Header\n"); 389 return retv; 390 } 391 392 /** Produce all of the minimal span solutions that can be generated from 393 * this instance. A minimal span solution is one in which a minimal number 394 * of constraints that are connected yield an inconsistency. 395 * @return The vector of minimal span solutions. 396 */ 397 public Vector minimalSpanSolutions() { 398 Vector solutions = new Vector(); 399 _debug("Solver.minimalSpanSolutions " + headerInfo() + " initial\n" 400 + stateInfo()); 401 402 Solution root = copy(); 403 404 // First eliminate all the singletons. These are due to statically bound 405 // ports. 406 Iterator allG = root._findAllG().iterator(); 407 408 while (allG.hasNext()) { 409 Index g = (Index) allG.next(); 410 root._eliminate(g); 411 } 412 413 // The solution may already be inconsistent. This would be the case if 414 // two statically bound ports are connected but have different units. 415 root._checkForInConsistency(); 416 417 if (root._solveState == _INCONSISTENT) { 418 root._analyzeState(); 419 solutions.add(root); 420 } else { 421 // The root solution is consistent. Now use the root as the starting 422 // point to generate all possible minimally spanning solutions. 423 root._branchPoint = null; 424 _debug("Solver.solve root\n" + root.stateInfo()); 425 root._branchPoints = root._findAllG(); 426 427 if (root._branchPoints.size() > 0) { 428 for (int i = 0; i < root._branchPoints.size(); i++) { 429 Solution s = root.copy(); 430 Vector results = s._partialSolveRecursively(1, 431 (Index) root._branchPoints.elementAt(i)); 432 solutions.addAll(results); 433 } 434 } else { 435 root._analyzeState(); 436 solutions.add(root); 437 } 438 } 439 440 if (_debug) { 441 for (int i = 0; i < solutions.size(); i++) { 442 Solution solution = (Solution) solutions.elementAt(i); 443 System.out.println("A Solution\n" + solution.stateInfo()); 444 } 445 } 446 447 return solutions; 448 } 449 450 /** 451 * The current state of the solver. A StringBuffer is produced that shows 452 * the variables, done vector, P array, and A vector in a human readable 453 * arrangement. 454 * 455 * @return A StringBuffer with the state of the solver. 456 */ 457 public StringBuffer stateInfo() { 458 StringBuffer retv = new StringBuffer(); 459 retv.append("State\n"); 460 retv.append("BranchPoints " + _branchPoints + "\n "); 461 462 for (int j = 0; j < _numVariables; j++) { 463 retv.append(" " + _vNumFormat.format(j)); 464 } 465 466 retv.append("\n"); 467 468 for (int i = 0; i < _numConstraints; i++) { 469 if (_done[i]) { 470 retv.append("T "); 471 } else { 472 retv.append("F "); 473 } 474 475 retv.append("" + _vNumFormat.format(i) + " "); 476 477 for (int j = 0; j < _numVariables; j++) { 478 retv.append("" + _pFormat.format(_arrayP[i][j]) + " "); 479 } 480 481 retv.append("" + _vectorA[i] + " " + _vectorA[i].descriptiveForm()); 482 retv.append(" " + ((UnitEquation) _constraints.elementAt(i)) 483 .descriptiveForm()); 484 retv.append("\n"); 485 } 486 487 if (_branchPoint == null) { 488 retv.append("BranchPoint = null\n"); 489 } else { 490 retv.append("BranchPoint = " + _branchPoint.toString() + "\n"); 491 } 492 493 retv.append("Solution: " + getStateDesc()); 494 retv.append("\n\\State\n"); 495 return retv; 496 } 497 498 public void trace() { 499 System.out.print("Solver.trace\n"); 500 501 Solution s = this; 502 503 while (s != null) { 504 System.out.print(s.stateInfo()); 505 s = s._upper; 506 } 507 508 System.out.print(headerInfo()); 509 } 510 511 /////////////////////////////////////////////////////////////////// 512 ///// private methods ////// 513 private void _analyzeState() { 514 _varBindings = new String[_numVariables]; 515 _constraintExplanations = new String[_numConstraints]; 516 _varState = new int[_numVariables]; 517 _constraintState = new int[_numConstraints]; 518 519 StringBuffer inconsistencyDesc = new StringBuffer(); 520 521 for (int i = 0; i < _numConstraints; i++) { 522 _constraintState[i] = _UNKNOWN; 523 _constraintExplanations[i] = ""; 524 525 if (_done[i]) { 526 int numNonZeroP = 0; 527 528 for (int j = 0; j < _numVariables; j++) { 529 if (_arrayP[i][j] != 0) { 530 numNonZeroP++; 531 } 532 } 533 534 if (numNonZeroP == 0 535 && !_vectorA[i].equals(UnitLibrary.Identity)) { 536 Unit factor = _vectorA[i].invert(); 537 String uString = factor.descriptiveForm(); 538 _constraintState[i] = _INCONSISTENT; 539 _constraintExplanations[i] = uString; 540 } else if (numNonZeroP > 1 541 && _vectorA[i].equals(UnitLibrary.Identity)) { 542 _constraintState[i] = _NONUNIQUE; 543 } else { 544 String uString = _vectorA[i].descriptiveForm(); 545 _constraintState[i] = _CONSISTENT; 546 _constraintExplanations[i] = uString; 547 } 548 } 549 } 550 551 for (int j = 0; j < _numVariables; j++) { 552 _varBindings[j] = ""; 553 554 int numNonZeroP = 0; 555 556 for (int i = 0; i < _numConstraints; i++) { 557 if (_done[i] && _arrayP[i][j] != 0) { 558 Unit U = _vectorA[i].pow(1.0 / _arrayP[i][j]); 559 560 if (numNonZeroP > 0) { 561 _varBindings[j] += ";"; 562 } 563 564 _varBindings[j] += U.descriptiveForm(); 565 numNonZeroP++; 566 } 567 } 568 569 if (numNonZeroP > 1) { 570 _varBindings[j] = "*AMBIGUOUS* " + _varBindings[j]; 571 _varState[j] = _INCONSISTENT; 572 } 573 574 if (numNonZeroP == 1) { 575 _varState[j] = _CONSISTENT; 576 } else { 577 _varBindings[j] = "<Unbound>"; 578 _varState[j] = _NONUNIQUE; 579 } 580 } 581 582 boolean stateInconsistent = false; 583 boolean stateNonUnique = false; 584 _solveState = _CONSISTENT; 585 586 for (int i = 0; i < _numConstraints; i++) { 587 switch (_constraintState[i]) { 588 case _INCONSISTENT: { 589 stateInconsistent = true; 590 591 NamedObj source = _source[i]; 592 String sourceName = "NoSource"; 593 594 if (source instanceof IORelation) { 595 sourceName = ((IORelation) source).getName(); 596 } else if (source instanceof ComponentEntity) { 597 sourceName = ((ComponentEntity) source).getName(); 598 } else if (source instanceof TypedIOPort) { 599 sourceName = source 600 .getName(source.getContainer().getContainer()); 601 } 602 603 inconsistencyDesc.append( 604 " " + sourceName + " " + _constraintExplanations[i]); 605 break; 606 } 607 608 case _NONUNIQUE: { 609 stateNonUnique = true; 610 break; 611 } 612 } 613 } 614 615 if (stateInconsistent && stateNonUnique) { 616 _debug("State is both Inconsistent and NonUnique"); 617 } 618 619 for (int j = 0; j < _numVariables; j++) { 620 if (_varState[j] == _INCONSISTENT) { 621 stateInconsistent = true; 622 inconsistencyDesc 623 .append(" " + _variables[j] + "=" + _varBindings[j]); 624 } 625 } 626 627 if (stateInconsistent) { 628 _solveState = _INCONSISTENT; 629 } else if (stateNonUnique) { 630 _solveState = _NONUNIQUE; 631 } else { 632 _solveState = _CONSISTENT; 633 } 634 635 switch (_solveState) { 636 case _UNKNOWN: { 637 _stateDescription = "UnKnown"; 638 break; 639 } 640 641 case _NONUNIQUE: { 642 _stateDescription = "No Unique Solution"; 643 break; 644 } 645 646 case _INCONSISTENT: { 647 _stateDescription = "Inconsistent" + inconsistencyDesc; 648 break; 649 } 650 651 case _CONSISTENT: { 652 _stateDescription = "Consistent"; 653 break; 654 } 655 } 656 } 657 658 private int[] _branchesFrom(Index g) { 659 int k = g.getK(); 660 int l = g.getL(); 661 int num = 0; 662 663 for (int i = 0; i < _numConstraints; i++) { 664 if (i != k && _arrayP[i][l] != 0) { 665 num++; 666 } 667 } 668 669 int[] retv = new int[num]; 670 int index = 0; 671 672 for (int i = 0; i < _numConstraints; i++) { 673 if (i != k && _arrayP[i][l] != 0) { 674 retv[index++] = i; 675 } 676 } 677 678 return retv; 679 } 680 681 private void _checkForInConsistency() { 682 for (int i = 0; i < _numConstraints; i++) { 683 if (!_vectorA[i].equals(UnitLibrary.Identity)) { 684 boolean inconsistent = true; 685 686 for (int j = 0; j < _numVariables; j++) { 687 if (_arrayP[i][j] != 0) { 688 inconsistent = false; 689 } 690 } 691 692 if (inconsistent) { 693 _done[i] = true; 694 _solveState = _INCONSISTENT; 695 } 696 } 697 } 698 } 699 700 private void _debug(String msg) { 701 if (_debug) { 702 System.out.println(msg); 703 } 704 } 705 706 /** 707 * @param g 708 */ 709 private void _eliminate(Index g) { 710 int k = g.getK(); 711 int l = g.getL(); 712 _debug("Eliminating (" + k + ", " + l + ")"); 713 714 Unit U = _vectorA[k].pow(1.0 / _arrayP[k][l]); 715 _vectorA[k] = U; 716 _arrayP[k][l] = 1; 717 718 for (int i = 0; i < _numConstraints; i++) { 719 if (i != k && !_done[i] && _arrayP[i][l] != 0) { 720 _vectorA[i] = _vectorA[i].divideBy(U.pow(_arrayP[i][l])); 721 _arrayP[i][l] = 0; 722 } 723 } 724 725 _branchPoint = g; 726 _done[k] = true; 727 } 728 729 /** 730 * Finds all Index(i, l) such that P[i][l] != 0 and 1) all other P in row i 731 * is equal to 0 732 * 733 * @return Index(i, l) 734 */ 735 private Vector _findAllG() { 736 Vector retv = new Vector(); 737 738 for (int i = 0; i < _numConstraints; i++) { 739 if (!_done[i]) { 740 int l = -1; 741 boolean possible = false; 742 743 for (int j = 0; j < _numVariables; j++) { 744 if (_arrayP[i][j] != 0) { 745 if (l == -1) { 746 possible = true; 747 l = j; 748 } else { 749 possible = false; 750 break; 751 } 752 } 753 } 754 755 if (possible) { 756 retv.add(new Index(i, l)); 757 continue; 758 } 759 } 760 } 761 762 return retv; 763 } 764 765 /** 766 * @param rows 767 * @return A vector of Indexes. 768 */ 769 private Vector _findAllGInRows(int[] rows) { 770 Vector retv = new Vector(); 771 772 for (int k : rows) { 773 Index g = _findGInRow(k); 774 775 if (g != null) { 776 retv.add(g); 777 } 778 } 779 780 return retv; 781 } 782 783 /** 784 * Finds an Index(i, l) such that P[i][l] != 0 and 1) all other P in row i 785 * is equal to 0 786 * 787 * @return Index(i, l) 788 */ 789 private Index _findG() { 790 for (int i = 0; i < _numConstraints; i++) { 791 if (!_done[i]) { 792 int l = -1; 793 boolean possible = false; 794 795 for (int j = 0; j < _numVariables; j++) { 796 if (_arrayP[i][j] != 0) { 797 if (l == -1) { 798 possible = true; 799 l = j; 800 } else { 801 possible = false; 802 break; 803 } 804 } 805 } 806 807 if (possible) { 808 return new Index(i, l); 809 } 810 } 811 } 812 813 return null; 814 } 815 816 private Index _findGInRow(int k) { 817 int l = -1; 818 819 for (int j = 0; j < _numVariables; j++) { 820 if (_arrayP[k][j] != 0) { 821 if (l == -1) { 822 l = j; 823 } else { 824 return null; 825 } 826 } 827 } 828 829 if (l == -1) { 830 return null; 831 } 832 833 return new Index(k, l); 834 } 835 836 /** Return the string representation of the color value. 837 * @param colorValue The input color value. 838 * @return The string representation of the color as a Ptolemy expression 839 * string array of double values. 840 */ 841 private String _getColorString(Color colorValue) { 842 if (colorValue == null) { 843 return ""; 844 } else { 845 float[] colorArray = colorValue.getRGBComponents(null); 846 return "{ " + colorArray[0] + ", " + colorArray[1] + ", " 847 + colorArray[2] + ", " + colorArray[3] + " }"; 848 } 849 } 850 851 private String _momlAnnotate(NamedObj entity, String color, 852 String expression) { 853 String colorProperty = null; 854 // We don't use ptolemy.actor.gui.ColorAttribute here 855 // because we don't want to add a dependency between 856 // moml.unit and actor.gui 857 Attribute currentColor = entity.getAttribute("_color"); 858 859 if (currentColor != null && color == null) { 860 colorProperty = "<deleteProperty _name=_color/>"; 861 } else if (color != null) { 862 colorProperty = "<property name=\"_color\" " 863 + "class = \"ptolemy.actor.gui.ColorAttribute\" " 864 + "value = \"" + color + "\"/>"; 865 } 866 867 return "<" + entity.getElementName() + " name=\"" + entity.getName() 868 + "\" class=\"" + entity.getClassName() + "\">" + colorProperty 869 + "<property name=\"_explanation\" " 870 + "class = \"ptolemy.kernel.util.StringAttribute\" " 871 + "value = \"" + expression + "\"/></" + entity.getElementName() 872 + ">"; 873 } 874 875 private Vector _partialSolveRecursively(int level, Index g) { 876 Vector retv = new Vector(); 877 _debug("\nSolver._eliminateRecursively level " + level + " BrancPoint " 878 + g + "\n" + stateInfo()); 879 880 int[] rows = _branchesFrom(g); 881 _eliminate(g); 882 _checkForInConsistency(); 883 _branchPoints = _findAllGInRows(rows); 884 885 if (_solveState != _INCONSISTENT && _branchPoints.size() > 0) { 886 if (_debug) { 887 System.out.print("Branch Rows at level " + level + " for " + g); 888 889 for (int row : rows) { 890 System.out.print(" " + row); 891 } 892 893 System.out.print("\nRemaining BranchPoints"); 894 895 for (int a = 0; a < _branchPoints.size(); a++) { 896 System.out.print(" " + _branchPoints.elementAt(a)); 897 } 898 899 System.out.print("\n"); 900 } 901 902 for (int gi = 0; gi < _branchPoints.size(); gi++) { 903 Solution s = copy(); 904 Vector results = s._partialSolveRecursively(level + 1, 905 (Index) _branchPoints.elementAt(gi)); 906 907 if (results != null) { 908 retv.addAll(results); 909 } 910 } 911 } else { 912 _analyzeState(); 913 914 if (_debug) { 915 trace(); 916 } 917 918 retv.add(this); 919 } 920 921 return retv; 922 } 923 924 /////////////////////////////////////////////////////////////////// 925 //// private variables //// 926 private static final int _UNKNOWN = -1; 927 928 private static final int _CONSISTENT = 0; 929 930 private static final int _INCONSISTENT = 1; 931 932 private static final int _NONUNIQUE = 2; 933 934 double[][] _arrayP; 935 936 Index _branchPoint = null; 937 938 Vector _branchPoints = null; 939 940 Vector _constraints = null; 941 942 String[] _constraintExplanations = null; 943 944 int[] _constraintState = null; 945 946 boolean _debug = false; 947 948 boolean[] _done; 949 950 TypedCompositeActor _model; 951 952 int _numConstraints = 0; 953 954 int _numVariables = 0; 955 956 private static final DecimalFormat _pFormat = new DecimalFormat(" 0;-0"); 957 958 private int _solveState = _UNKNOWN; 959 960 NamedObj[] _source; 961 962 String _stateDescription = "No description"; 963 964 Solution _upper = null; 965 966 String[] _varBindings = null; 967 968 String[] _variables; 969 970 int[] _varState = null; 971 972 Unit[] _vectorA; 973 974 private static final DecimalFormat _vNumFormat = new DecimalFormat("00"); 975 976 /////////////////////////////////////////////////////////////////// 977 //// inner class //// 978 979 /** 980 * Class that represents an index in the P array. 981 * 982 */ 983 private static class Index { 984 // FindBugs suggests making this class static so as to decrease 985 // the size of instances and avoid dangling references. 986 int k; 987 988 int l; 989 990 private Index(int k1, int l1) { 991 k = k1; 992 l = l1; 993 } 994 995 public int getK() { 996 return k; 997 } 998 999 public int getL() { 1000 return l; 1001 } 1002 1003 @Override 1004 public String toString() { 1005 return "(" + k + "," + l + ")"; 1006 } 1007 } 1008}