ContentsIndexHome
PreviousUpNext
C++ Peformance example

The Performance example in C++.

  1: #include "aimms/Include.h"
  2: #include <iostream>
  3: #include <time.h>
  4: #include <assert.h>
  5: 
  6: 
  7: // This example demonstrates the performance difference between three ways to
  8: // assign data to a set and to assign a 3 dimensional parameter on 50% of its
  9: // domain positions.   
 10: 
 11: 
 12: // the data used to fill the domainsets in this example
 13: const char* s_StringLabels[325] =  {"ab", "ac", "ad", "ae", "ah", "ai", "al", "am", "an", "ar", "as", "at", "aw", "ax", "ay", "aah", "aam", "abb", "abc", "abo", "abs", "abt", "aby", "ace", "ach", "act", "add", "adj", "ado", "ads", "adv", "adz", "afb", "aft", "aga", "age", "ago", "aha", "ahs", "ahu", "aid", "ail", "aim", "air", "ais", "ait", "ake", "ala", "alb", "ale", "all", "alp", "als", "alt", "ama", "amp", "amt", "amu", "amy", "ana", "and", "ani", "ann", "ano", "ant", "any", "ape", "apo", "app", "apt", "ara", "arc", "are", "arf", "ark", "arm", "ars", "art", "asa", "ash", "ask", "asp", "ass", "ate", "aud", "auf", "auk", "aum", "aux", "ava", "ave", "avg", "awe", "awk", "awl", "awm", "awn", "axe", "aye", "aahs", "abay", "abba", "abbe", "abbr", "abed", "abet", "abib", "abid", "abit", "able", "ably", "abox", "abra", "abut", "abye", "acct", "aced", "aces", "ache", "achy", "acid", "aclu", "acme", "acne", "acre", "acts", "acyl", "adam", "adar", "adaw", "adds", "adit", "ados", "adry", "advt", "adze", "aeon", "aero", "aery", "afar", "afer", "affy", "afro", "agar", "aged", "agen", "ages", "agha", "agin", "agio", "agni", "agog", "agon", "agre", "ague", "ahem", "ahey", "ahoy", "aide", "aids", "aiel", "ails", "aims", "aino", "airs", "airy", "ajar", "ajog", "akin", "alae", "alai", "alan", "alar", "alas", "alba", "albe", "albs", "alco", "alee", "alem", "ales", "alew", "alfa", "alga", "alii", "alit", "alls", "ally", "alma", "alme", "alms", "aloe", "alow", "alps", "also", "alto", "alum", "amah", "ambo", "amel", "amen", "amex", "amia", "amic", "amid", "amir", "amis", "amit", "amma", "ammo", "amok", "amps", "amts", "amyl", "anal", "anan", "anas", "ands", "anes", "anet", "anew", "anil", "anis", "ankh", "anna", "anne", "anno", "anoa", "anon", "ansa", "ansi", "anta", "ante", "anti", "ants", "anus", "apar", "aped", "aper", "apes", "apex", "apis", "apod", "apse", "apus", "aqua", "arab", "arak", "arch", "arco", "arcs", "area", "ares", "aret", "arew", "argo", "aria", "arid", "aril", "arks", "arms", "army", "arna", "arow", "arse", "arts", "arty", "arum", "asap", "asci", "asea", "ashy", "asia", "asks", "asps", "asse", "assn", "asst", "atma", "atmo", "atom", "atop", "atte", "attn", "atty", "atwo", "aube", "auks", "auld", "auln", "aune", "aunt", "aura", "auto", "avdp", "avel", "aver", "aves", "avid", "avie", "avis", "avow", "away", "awed", "awes", "awls", "awns", "awny", "awol", "awry", "axal", "axed", "axel", "axes", "axil", "axis", "axle", "axon", "ayah", "ayen", "ayes", "ayle", "ayme", "ayry", "azym"};
 14: 
 15: class Performance{
 16: 
 17: public:
 18:     Performance(const char* aimmsLocation, const char* project) 
 19:         : m_Location(aimmsLocation)
 20:         , m_Project(project)
 21:         , m_Aimms(0)
 22:         , m_SubSet(0)
 23:         , m_LargePar(0)
 24:         , m_StartTime(0)
 25:     {
 26:     }
 27: 
 28: 
 29: public:
 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:     void convenientAssignLabels(int setsize) {
 36: 
 37:         openSessionAndData();
 38: 
 39:         start("Assign string labels using insert and the Tuple class");
 40: 
 41:         double value = 0.0;
 42: 
 43:         for (int i = 0; i < setsize; i += 2) {  // a density  of 50%, skip al odd positions on this dimension
 44:             for (int j = 0; j < setsize; ++j) {
 45:                 for (int k = 0; k < setsize; ++k) {
 46:                     ++value;
 47:                     m_LargePar->insert(aimms::Tuple(s_StringLabels[i], s_StringLabels[j], s_StringLabels[k]), value);
 48:                 }
 49:             }
 50:         }
 51:         m_Aimms->updateData();
 52: 
 53:         stop();
 54: 
 55:         closeDataAndSession();
 56:     }
 57: 
 58:     /*
 59:     * Ordinals, ITuple and setValue: The more efficient way: Use ordinals to
 60:     * construct an ITuple and add the datapoint with it. Since the SDK uses the
 61:     * 'natural' Aimms ordering, the ordering of the data is not guaranteed to
 62:     * be the order in which the set data is supplied. So use ordinals with
 63:     * care. See also the section on "Set element ordering" in the Execution
 64:     * Efficiency Cookbook chapter in the Aimms Language Reference.
 65:     */
 66:     void efficientAssignLabels(int setsize) {
 67: 
 68:         openSessionAndData();
 69: 
 70:         start("Assign string labels first to the set and use the ITuple interface, ordinals and setValue to assign the values on the parameter");
 71: 
 72: 
 73:         for (int i = 0; i < setsize; ++i) {
 74:             m_SubSet->add(s_StringLabels[i]);
 75:         }
 76: 
 77:         m_Aimms->updateData(); // Update the set data to make label lookup faster.
 78: 
 79:         aimms::ITuple* tup = m_LargePar->createTuple();
 80: 
 81:         double value = 0.0;
 82:         try{
 83:             for (int i = 1; i <= setsize; i += 2) {    // A density  of 50%: skip all odd positions of this dimension.
 84: 
 85:                 // Set each dimension only when it changes. 
 86:                 tup->getElement(0)->setOrdinal(i);      // Here the getElement method is used to get access to the indivual elements per dimension
 87:                 // The operator [] is defined on ITuple as well. For hints on how to use these, see the language reference.
 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:                         m_LargePar->setValue(tup, value);
 94:                     }
 95:                 }
 96:             }
 97:             m_Aimms->updateData();
 98:         } catch( aimms::RuntimeException& ex){
 99:             std::cerr<< "Catched a runtime exception: " << ex.what() <<std::endl;
100:             m_Aimms->clearBuffers();
101:         }
102: 
103:         stop();
104: 
105:         closeDataAndSession();
106:     }
107: 
108:     /*
109:     * setValues: Efficient and convenient if the data to assign is dense. The
110:     * setLabels (for sets) and setValues (for data) methods do allow for dense
111:     * allocation of an identifier. The data will be added in the natural
112:     * ordering of the domains, thus combining ease of use with efficiency.
113:     */
114:     void denseAssignLabels(int setsize) {
115: 
116:         openSessionAndData();
117: 
118:         start("Assign string labels first to the set using setLabels and then use setValues on the IMultiDimData to assign the values to the parameter");
119: 
120:         m_SubSet->setLabels(s_StringLabels, setsize);
121:         // UpdateData is not neccesary here because after the setLabels method the set is immediately up-to-date.
122: 
123:         int datasize = setsize * setsize * setsize;
124:         double* values = new double[datasize];
125: 
126:         // Whether a loop like this is neccesary depends on the source of the values.
127:         double value = 0;
128:         int pos = 0;
129:         for (int i = 0; i < setsize; i += 2) {
130: 
131:             for (int j = 0; j < setsize; ++j) {
132:                 for (int k = 0; k < setsize; ++k) {
133:                     values[pos++] = ++value;
134:                 }
135:             }
136:             // 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.
137:             for (int z = 0; z < setsize * setsize; ++z) {
138:                 values[pos++] = 0;
139:             }
140:         }
141: 
142:         m_LargePar->setValues(values, datasize);
143:         delete [] values;
144: 
145:         m_Aimms->updateData();
146: 
147:         stop();
148: 
149:         closeDataAndSession();
150:     }
151: 
152:     /*
153:     * Slices: Efficient if the data to be assigned is sparse and distributed in
154:     * a way slices can be defined. In this example multiple views are created
155:     * that are all restricted on the same level on a single element. This
156:     * reduces the dimension.
157:     */
158:     void sliceAssignLabels( int setsize) {
159: 
160:         openSessionAndData();
161: 
162:         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");
163: 
164: 
165:         m_SubSet->setLabels(s_StringLabels, setsize);
166: 
167: 
168:         // Create a filter to slice the parameter.
169:         aimms::IFilter* filter = m_LargePar->createFilter();
170: 
171:         int vieweddatasize = setsize * setsize;
172:         double* values = new double[vieweddatasize];
173: 
174:         double value = 0;
175:         for (int i = 0; i < setsize; i += 2) {
176:             // For each position of this dimension to which we will assign data, construct the filter to create a DataView. 
177:             // Notice the +=2, we only need views on the even positions. 
178:             filter->restrict(0, s_StringLabels[i]);
179:             aimms::IDataView* slice = m_LargePar->openView(filter);
180: 
181:             int pos = 0;
182:             for (int j = 0; j < setsize; ++j) {
183:                 for (int k = 0; k < setsize; ++k) {
184:                     values[pos++] = ++value;
185:                 }
186:             }
187:             slice->setValues(values, vieweddatasize);
188:         }
189: 
190:         delete [] values;
191:         m_Aimms->updateData();
192: 
193:         stop();
194: 
195:         closeDataAndSession();
196:     }
197: 
198:     /*
199:     * Filtering by call domain: Efficient if the data is sparse and an
200:     * appropriate subset is available to filter with.
201:     */
202:     void filteredAssignLabels(int setsize) {
203: 
204:         openSessionAndData();
205: 
206:         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");
207: 
208:         m_SubSet->setLabels(s_StringLabels, setsize);
209: 
210:         // Open a subset on the domainset to use as a call domain on the level to restrict.
211:         aimms::ISetData* subsubset = m_Aimms->openSet("SubSubSet");
212:         aimms::IElement* element = m_SubSet->createElement();
213: 
214:         for (int o = 1; o <= setsize; o += 2) {
215:             element->setOrdinal(o);
216:             subsubset->add(element);
217:         }
218:         m_Aimms->updateData();
219: 
220:         int vieweddatasize = setsize / 2 * setsize * setsize;
221:         double* values = new double[vieweddatasize];
222: 
223:         // Create a filter to slice the parameter.
224:         aimms::IFilter* filter = m_LargePar->createFilter();
225:         filter->restrict(0, subsubset);
226:         aimms::IDataView* view = m_LargePar->openView(filter);
227: 
228: 
229:         double value = 0;
230:         int pos = 0;
231:         for (int i = 0; i < setsize; i += 2) {
232:             for (int j = 0; j < setsize; ++j) {
233:                 for (int k = 0; k < setsize; ++k) {
234:                     values[pos++] = ++value;
235:                 }
236:             }
237:         }
238:         view->setValues(values, vieweddatasize);
239: 
240:         delete [] values;
241:         m_Aimms->updateData();
242: 
243:         stop();
244: 
245:         subsubset->close();
246:         closeDataAndSession();
247:     }
248: 
249: 
250: 
251: private:
252:     // Helper functions
253:     void openSessionAndData() {
254:         m_Aimms = 0;
255:         m_Aimms = aimms::openSession(m_Location.c_str(), m_Project.c_str());
256:         if (m_Aimms == 0) {
257:             return;
258:         }
259:         m_SubSet = m_Aimms->openSet("LargeSubSet");
260:         m_LargePar = m_Aimms->openMultiDim("LargePar1");
261:     }
262: 
263:     void closeDataAndSession() {
264:         m_LargePar->close();
265:         m_SubSet->close();
266:         m_Aimms->close();
267:         m_Aimms = 0;
268:     }
269: 
270:     void start(const char* testDescription) {
271:         std::cout <<"Start Running " <<  testDescription << "..." << std::endl;
272:         time(&m_StartTime);
273:     }
274: 
275:     void stop() {
276:         time_t stop;
277:         time(&stop);
278:         std::cout<< "... " <<" took " << difftime (stop,m_StartTime) << " seconds."  << std::endl << std::endl;  
279:     }
280: 
281: 
282: 
283: private : 
284:     std::string m_Location;
285:     std::string m_Project;
286:     aimms::ISession* m_Aimms;
287:     aimms::ISetData* m_SubSet;
288:     aimms::IMultiDimData* m_LargePar;
289:     time_t m_StartTime;
290: };
291: 
292: 
293: 
294: 
295: 
296: int main(int argc, const char* argv[]) 
297: {
298:     if (argc != 3) {
299:         std::cerr << "Invalid number of arguments. usage: <location of AIMMS>  <location of project>" << std::endl; 
300:         return 1;
301:     }  
302:     int setsize = 150;
303: 
304:     Performance test(argv[1], argv[2]);
305: 
306:     try {
307: 
308:         test.convenientAssignLabels(setsize);
309:         test.efficientAssignLabels(setsize);
310:         test.denseAssignLabels(setsize);
311:         test.sliceAssignLabels(setsize);
312:         test.filteredAssignLabels(setsize);
313: 
314:     } catch (aimms::Exception& ex) {
315:         std::cerr<< "AIMMS exception:" << ex.what() << std::endl;
316:     } catch (std::exception& ex){
317:         std::cerr << "Exception:" << ex.what() << std::endl;
318:     }
319: }
320: 
321: