ContentsIndexHome
PreviousUpNext
C# Performance Example

The Performance example in C#.

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