1: package com.aimms.aimmssdk.examples.performance; 2: 3: import com.aimms.aimmssdk.*; 4: import java.util.Date; 5: import org.slf4j.Logger; 6: import org.slf4j.LoggerFactory; 7: 8: /** 9: * This example demonstrates the performance difference between three ways to 10: * assign data to a set and to assign a 3 dimensional parameter on 50% of its 11: * domain positions. 12: */ 13: class Performance { 14: 15: static private Logger logger = LoggerFactory.getLogger(Performance.class); 16: String m_Location; 17: String m_Project; 18: String[] m_Labels; 19: ISession m_Aimms = null; 20: ISetData m_SubSet = null; 21: IMultiDimData m_LargePar = null; 22: long m_StartTime = 0; 23: 24: public Performance(String aimmsLocation, String project, String[] labels) { 25: m_Location = aimmsLocation; 26: m_Project = project; 27: m_Labels = labels; 28: } 29: 30: /** 31: * The convenient way: Use a Tuple object constructed with labels to insert 32: * each data entry. This is inefficient due to the required string 33: * comparisons. 34: */ 35: public void convenientAssignLabels() { 36: 37: openSessionAndData(); 38: int setsize = m_Labels.length; 39: 40: start("Assign string labels using insert and the Tuple class"); 41: 42: double value = 0.0; 43: 44: for (int i = 0; i < setsize; i += 2) { // a density of 50%, skip all odd positions of this dimension 45: for (int j = 0; j < setsize; ++j) { 46: for (int k = 0; k < setsize; ++k) { 47: ++value; 48: m_LargePar.insert(new Tuple(m_Labels[i], m_Labels[j], m_Labels[k]), value); 49: } 50: } 51: } 52: m_Aimms.updateData(); 53: 54: stop(); 55: 56: closeDataAndSession(); 57: } 58: 59: /** 60: * Ordinals, ITuple and setValue: The more efficient way: Use ordinals to 61: * construct an ITuple and add the datapoint with it. Since the SDK uses the 62: * 'natural' Aimms ordering, the ordering of the data is not guaranteed to 63: * be the order in which the set data is supplied. So use ordinals with 64: * care. See also the section on "Set element ordering" in the Execution 65: * Efficiency Cookbook chapter in the Aimms Language Reference. 66: */ 67: public void efficientAssignLabels() { 68: 69: openSessionAndData(); 70: int setsize = m_Labels.length; 71: 72: start("Assign string labels first to the set and use the ITuple interface, ordinals and setValue to assign the values on the parameter"); 73: 74: 75: for (int i = 0; i < setsize; ++i) { 76: m_SubSet.add(m_Labels[i]); 77: } 78: 79: m_Aimms.updateData(); // Update the set data to make label lookup faster. 80: 81: ITuple tup = m_LargePar.createTuple(); 82: double value = 0.0; 83: try { 84: for (int i = 1; i <= setsize; i += 2) { // A density of 50%: skip al odd positions on this dimension. 85: 86: // Set each dimension only when it changes. 87: tup.getElement(0).setOrdinal(i); 88: for (int j = 1; j <= setsize; ++j) { 89: tup.getElement(1).setOrdinal(j); 90: for (int k = 1; k <= setsize; ++k) { 91: tup.getElement(2).setOrdinal(k); 92: ++value; 93: 94: m_LargePar.setValue(tup, value); 95: } 96: } 97: } 98: 99: m_Aimms.updateData(); 100: } catch (AimmsRuntimeException ex) { 101: // setValue throws an AimmsRuntimeException if the elements of the tuple are not present in the index domain. 102: logger.error("Catched a runtime exception: {}", ex.getMessage()); 103: m_Aimms.clearBuffers(); 104: 105: } finally { 106: 107: stop(); 108: closeDataAndSession(); 109: } 110: 111: 112: } 113: 114: /** 115: * setValues: Efficient and convenient if the data to assign is dense. The 116: * setLabels (for sets) and setValues (for data) methods do allow for dense 117: * allocation of an identifier. The data will be added in the natural 118: * ordering of the domains, thus combining ease of use with efficiency. 119: */ 120: public void denseAssignLabels() { 121: 122: openSessionAndData(); 123: int setsize = m_Labels.length; 124: logger.info("setsize: {} ", setsize); 125: start("Assign string labels first to the set using setLabels and then use setValues on the IMultiDimData to assign the values to the parameter"); 126: 127: 128: m_SubSet.setLabels(m_Labels); 129: 130: // UpdateData is not neccesary here because after the setLabels method the set is immediately up-to-date. 131: 132: double[] values = new double[setsize * setsize * setsize]; 133: 134: // Whether a loop like this is neccesary depends on the source of the values. 135: double value = 0; 136: int pos = 0; 137: for (int i = 0; i < setsize; i += 2) { 138: 139: for (int j = 0; j < setsize; ++j) { 140: for (int k = 0; k < setsize; ++k) { 141: values[pos++] = ++value; 142: } 143: } 144: // Now insert a two dimensional slice with zero's (the default value), because this is a dense assign method but the data is not fully dense. 145: for (int z = 0; z < setsize * setsize; ++z) { 146: values[pos++] = 0; 147: } 148: } 149: 150: m_LargePar.setValues(values); 151: 152: m_Aimms.updateData(); 153: 154: stop(); 155: 156: closeDataAndSession(); 157: } 158: 159: /** 160: * Slices: Efficient if the data to be assigned is sparse and distributed in 161: * a way slices can be defined. In this example multiple views are created 162: * that are all restricted on the same level on a single element. This 163: * reduces the dimension. 164: */ 165: public void sliceAssignLabels() { 166: 167: openSessionAndData(); 168: int setsize = m_Labels.length; 169: 170: start("Assign string labels first to the set using setLabels and then use setValues on IDataView slices of the IMultiDimData to assign the values to the parameter"); 171: 172: 173: m_SubSet.setLabels(m_Labels); 174: 175: 176: double[] values = new double[setsize * setsize]; 177: 178: // Create a filter to slice the parameter. 179: IFilter filter = m_LargePar.createFilter(); 180: 181: double value = 0; 182: for (int i = 0; i < setsize; i += 2) { 183: // For each position of this dimension to which we will assign data, construct the filter to create a DataView. 184: // Notice the +=2, we only need views on the even positions. 185: filter.restrict(0, m_Labels[i]); 186: IDataView slice = m_LargePar.openView(filter); 187: 188: int pos = 0; 189: for (int j = 0; j < setsize; ++j) { 190: for (int k = 0; k < setsize; ++k) { 191: values[pos++] = ++value; 192: } 193: } 194: slice.setValues(values); 195: } 196: 197: m_Aimms.updateData(); 198: 199: stop(); 200: 201: closeDataAndSession(); 202: } 203: 204: /** 205: * Filtering by call domain: Efficient if the data is sparse and an 206: * appropriate subset is available to filter with. 207: */ 208: public void filteredAssignLabels() { 209: 210: openSessionAndData(); 211: int setsize = m_Labels.length; 212: 213: start("Assign string labels first to the set using setLabels and use setValues on an IDataView filtered by a subset to assign the values on the parameter"); 214: 215: m_SubSet.setLabels(m_Labels); 216: 217: // Open a subset on the domainset to use as a call domain on the level to restrict. 218: ISetData subsubset = m_Aimms.openSet("SubSubSet"); 219: IElement element = m_SubSet.createElement(); 220: 221: for (int o = 1; o <= setsize; o += 2) { 222: element.setOrdinal(o); 223: subsubset.add(element); 224: } 225: m_Aimms.updateData(); 226: 227: double[] values = new double[setsize / 2 * setsize * setsize]; 228: 229: // Create a filter to slice the parameter. 230: IFilter filter = m_LargePar.createFilter(); 231: filter.restrict(0, subsubset); 232: IDataView view = m_LargePar.openView(filter); 233: 234: 235: double value = 0; 236: int pos = 0; 237: for (int i = 0; i < setsize; i += 2) { 238: for (int j = 0; j < setsize; ++j) { 239: for (int k = 0; k < setsize; ++k) { 240: values[pos++] = ++value; 241: } 242: } 243: } 244: view.setValues(values); 245: 246: m_Aimms.updateData(); 247: 248: stop(); 249: 250: subsubset.close(); 251: closeDataAndSession(); 252: 253: 254: } 255: 256: // Helper functions 257: private void openSessionAndData() { 258: m_Aimms = null; 259: m_Aimms = AIMMS.openSession(m_Location, m_Project); 260: if (m_Aimms == null) { 261: return; 262: } 263: m_SubSet = m_Aimms.openSet("LargeSubSet"); 264: m_LargePar = m_Aimms.openMultiDim("LargePar1"); 265: } 266: 267: private void closeDataAndSession() { 268: m_LargePar.close(); 269: m_SubSet.close(); 270: m_Aimms.close(); 271: } 272: 273: private void start(String testDescription) { 274: logger.info("Start Running {}...", testDescription); 275: m_StartTime = new Date().getTime(); 276: } 277: 278: private void stop() { 279: long stop = new Date().getTime(); 280: long dif = stop - m_StartTime; 281: logger.info("This took {} milliseconds", dif); 282: logger.info(""); 283: } 284: }