Coverage Report - net.sourceforge.combean.mathprog.grooml.GTerm
 
Classes in this File Line Coverage Branch Coverage Complexity
GTerm
95%
40/42
67%
35/52
0
GTerm$_parseTerm_closure1
100%
2/2
83%
5/6
0
GTerm$_parseTerm_closure2
100%
1/1
N/A
0
 
 1  
 /*
 2  
     This file is part of Combean.
 3  
 
 4  
     Combean is free software; you can redistribute it and/or modify
 5  
     it under the terms of the GNU General Public License as published by
 6  
     the Free Software Foundation; either version 2 of the License, or
 7  
     (at your option) any later version.
 8  
 
 9  
     Combean is distributed in the hope that it will be useful,
 10  
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  
     GNU General Public License for more details.
 13  
 
 14  
     You should have received a copy of the GNU General Public License
 15  
     along with Foobar; if not, write to the Free Software
 16  
     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 17  
 */
 18  
 package net.sourceforge.combean.mathprog.grooml;
 19  
 
 20  
 import net.sourceforge.combean.interfaces.mathprog.lp.model.LPVectorValue;
 21  
 import net.sourceforge.combean.interfaces.mathprog.lp.model.LPVectorLabel;
 22  
 import net.sourceforge.combean.interfaces.mathprog.lp.model.LPModelComponent;
 23  
 import net.sourceforge.combean.interfaces.mathprog.linalg.VectorOrientation;
 24  
 import net.sourceforge.combean.mathprog.lp.model.LPVectorLabelImpl;
 25  
 
 26  
 import net.sourceforge.combean.except.GModelException;
 27  
 
 28  
 /**
 29  
  * An single, linear term in the model.
 30  
  * 
 31  
  * Consists of
 32  
  * - a double coefficient,
 33  
  * - a variable name and
 34  
  * - an abstract index (which may be any type)
 35  
  * The mapping of the abstract index to an integer index in a concrete LP model
 36  
  * happens later when the expression, to which the term belongs is bound to a
 37  
  * concrete LP model with well-defined variables. These variables then do this
 38  
  * mapping.
 39  
  */
 40  
 class GTerm {
 41  
 
 42  
         String var;
 43  
         Object idx;
 44  
         double coeff;
 45  
         
 46  
         /**
 47  
          * Constructor
 48  
          * 
 49  
          * @params var name of the variable in the term
 50  
          * @params idx variable index (may be a single string or integer or a tuple
 51  
          * of such values)
 52  
          * @params coeff linear coefficient of the term
 53  
          */
 54  
         public GTerm(String var, Object idx, double coeff) {
 55  7195
             assert var != null;
 56  7195
             assert coeff != 0.0;
 57  
             
 58  7195
             this.var = var;
 59  7195
             this.idx = idx;
 60  7195
             this.coeff = coeff;
 61  
         }
 62  
         
 63  
         public String toString() {
 64  645
             String idxStr;
 65  645
             if (idx == null) {
 66  35
                 idxStr = "";
 67  
             }
 68  610
             else if (idx instanceof List) {
 69  375
                 idxStr = idx.join(",")
 70  
             }
 71  
             else {
 72  235
                 idxStr = idx.toString();
 73  
             }
 74  645
             return "$coeff $var[$idxStr]";
 75  
         }
 76  
 
 77  
         public double doubleValue() {
 78  1170
             return this.coeff;
 79  
         }
 80  
         
 81  
         public Object index() {
 82  1175
             return this.idx;
 83  
         }
 84  
         
 85  
         public void setIndex(Object idx) {
 86  1440
             this.idx = idx;
 87  
         }
 88  
         
 89  
         public GTerm clone() {
 90  1440
             return new GTerm(this.var, this.idx, this.coeff);
 91  
         }
 92  
         
 93  
         public GTerm scale(Number factor) {
 94  280
             return new GTerm(this.var, this.idx, this.coeff * factor);
 95  
         }
 96  
     
 97  
         /**
 98  
          * Parse a String that defines a term.
 99  
          * 
 100  
          * The term has the following format:
 101  
          * <Coefficient> *? <Variable Name> [ <Index> ]
 102  
          * The index may be
 103  
          * - a single string or a single number
 104  
          * - a list of strings or a list of numbers
 105  
          * 
 106  
          * @todo add support for simple variables (no index brackets required)
 107  
          */
 108  
     public static GTerm parseTerm(String term)
 109  
     throws GModelException
 110  
     {
 111  5290
             final String DOUBLENUM = /-?\s*\d*\.?\d*/;
 112  5290
             final String VARID = /[\w_]+/;
 113  5290
             final String INTEGER = /-?\s*\d+/;
 114  5290
             final String NAME = /[a-zA-Z_][\w\d_]*/;
 115  
 
 116  5290
             String termStripped = term.trim();
 117  
             def match =
 118  5290
                 termStripped =~ /^($DOUBLENUM)\s*\*?\s*($VARID)\s*\[([^]]*)\]$/;
 119  
             
 120  5290
             if (match.count != 1) {
 121  0
                 throw new GModelException(
 122  
             "Cannot parse term definition '$termStripped'.");
 123  
             }
 124  
 
 125  5290
             String coeffStr = match[0][1].replaceAll(/\s+/, "");
 126  5290
         double coeff = coeffStr.length() == 0 ? 1.0 : Double.parseDouble(coeffStr);
 127  
 
 128  5290
         String var = match[0][2];
 129  
 
 130  5290
             String idxStr = match[0][3].trim();
 131  5290
             Object idx = null;
 132  5290
             if (idxStr ==~ /\s*/) {
 133  45
                 idx = null;
 134  
             }
 135  5245
             else if (idxStr ==~ /$INTEGER/) {
 136  380
                 idx = new Integer(idxStr);
 137  
             }
 138  4865
             else if (idxStr ==~ /$NAME/) {
 139  80
                 idx = idxStr;
 140  
             }
 141  4785
             else if (idxStr ==~ /($INTEGER\s*,\s*)+$INTEGER/) {
 142  285
                 idx = idxStr.split(/\s*,\s*/).collect{
 143  570
                     new Integer(it.replaceAll(/\s+/, ""));
 144  
                     }
 145  
             }
 146  4500
             else if (idxStr ==~ /($NAME\s*,\s*)+$NAME/) {
 147  4500
                 idx = idxStr.split(/\s*,\s*/).collect{ it; }
 148  
             }
 149  
             else {
 150  0
                 throw new GModelException(
 151  
                         "Cannot parse index format '$idxStr' in term definition '$term'.");
 152  
             }
 153  
                 
 154  5290
             return new GTerm(var, idx, coeff);
 155  
     }
 156  
 }