File: SNC.cpp

package info (click to toggle)
deap 1.4.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,372 kB
  • sloc: python: 9,874; ansic: 1,054; cpp: 592; javascript: 153; makefile: 95; sh: 7
file content (165 lines) | stat: -rw-r--r-- 6,089 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
    This file is part of DEAP.

    DEAP is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    DEAP is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with DEAP. If not, see <http://www.gnu.org/licenses/>.
*/

/* This file is an example of a C evaluation function interfaced with DEAP;
 * It implements the evaluator of the sorting network problems, making it
 * about five times faster (up to 16x if used in combination with the
 * optimized cTools.nsga2 selection algorithm).
 * 
 * To compile it, you may want to use distutils to simplify the linking, like
 * the installSN.py script provided with this package. 
 * You may then import it like any other Python module :

 import SNC
 SNC.evalNetwork(dimension, individual)
 
 * See 4_5_home_made_eval_func.py for a comprehensive example.
 */
#include <Python.h>
#include <map>
#include <vector>
#include <iostream>

// Set of connectors that can be applied in parallel.
typedef std::map<unsigned int,unsigned int> Level;


static PyObject* evalNetwork(PyObject *self, PyObject *args){
    
    // Retrieve arguments (first : network dimensions; second : list of connectors [tuples])
    PyObject *inDimensions = PyTuple_GetItem(args, 0);
    PyObject *listNetwork = PyTuple_GetItem(args, 1);
    
    std::vector<Level> mNetwork;
    
    const unsigned int inputs_size = (unsigned int)PyInt_AS_LONG(inDimensions);
    const unsigned int lNbTests = (1u << inputs_size);
    unsigned long lCountMisses = 0;
    unsigned int inWire1, inWire2;
    const unsigned long lgth = PyList_Size(listNetwork);
    
    // Network creation
    for(unsigned int k = 0; k < lgth; k++){
        // Retrieve endpoint values
        inWire1 = (unsigned int)PyInt_AS_LONG(PyTuple_GetItem(PyList_GetItem(listNetwork,k),0));
        inWire2 = (unsigned int)PyInt_AS_LONG(PyTuple_GetItem(PyList_GetItem(listNetwork,k),1));
               
        // Check values of inWire1 and inWire2
        if(inWire1 == inWire2) continue;
        if(inWire1 > inWire2) {
            const unsigned int lTmp = inWire1;
            inWire1 = inWire2;
            inWire2 = lTmp;
        }
        
        // Nothing in network, create new level and connector
        if(mNetwork.empty()) {
            Level lLevel;
            lLevel[inWire1] = inWire2;
            mNetwork.push_back(lLevel);
            continue;
        }
        
        // Iterator to the connector at current level, after mWire1
        bool lConflict = false;
        Level::const_iterator lIterConnNext = mNetwork.back().begin();
        for(; (lIterConnNext != mNetwork.back().end()) && (inWire1 > lIterConnNext->first); ++lIterConnNext);
        if(lIterConnNext != mNetwork.back().end()) {
            // Check if conflict with next connector and inWire2
            if(inWire2 >= lIterConnNext->first) lConflict = true;
        }
        if(lIterConnNext != mNetwork.back().begin()) {
            // Iterator to the connector at current level, before mWire1
            Level::const_iterator lIterConnPrev = lIterConnNext;
            --lIterConnPrev;
            // Check if conflict with previous connector and inWire1
            if(inWire1 <= lIterConnPrev->second) lConflict = true;
        }
        
        // Add connector
        if(lConflict) {                          // Add new level of connectors
            Level lNextLevel;
            lNextLevel[inWire1] = inWire2;
            mNetwork.push_back(lNextLevel);
        }
        else {                                   // Add connector to current level
            mNetwork.back()[inWire1] = inWire2;
        }
    }

    // Network test
    for(unsigned int i=0; i<lNbTests; ++i) {
        std::vector<double> lSeqIOrig(inputs_size, 0.0);
        
        for(unsigned int j=0; j<inputs_size; ++j) {
            const unsigned int lValIJ = (1u << j);
            if((i & lValIJ) == lValIJ) lSeqIOrig[j] = 1.0;
        }
        
        std::vector<double> lSeqISorted(lSeqIOrig);
                            
        for(unsigned int z=0; z<mNetwork.size(); ++z) {
            for(Level::const_iterator lIter = mNetwork[z].begin();
                lIter != mNetwork[z].end(); ++lIter) {
                const unsigned int lId1 = lIter->first;
                const unsigned int lId2 = lIter->second;
                if(lSeqISorted[lId1] > lSeqISorted[lId2]) {
                    const double lTmp = lSeqISorted[lId1];
                    lSeqISorted[lId1] = lSeqISorted[lId2];
                    lSeqISorted[lId2] = lTmp;
                }
            }
        }
        
        bool lIsSorted = true;
        bool lLastWasOne = false;
        for(unsigned int w=0; w<lSeqISorted.size(); ++w) {
            if(lLastWasOne && (lSeqISorted[w] == 0.0)) {
                lIsSorted = false;
                break;
            }
            lLastWasOne = (lSeqISorted[w] == 1.0);
        }
        if(lIsSorted == false)
            ++lCountMisses;
    }
    
    // Compute the number of comparison-swap used.
    unsigned int lengthWanted = 0;
    for(unsigned int z=0; z<mNetwork.size(); ++z) {
        lengthWanted += mNetwork[z].size();
    }
    
    // Pack the return values into a tuple (fit, depth, length)
    PyObject* retVal = Py_BuildValue("(i,i,i)", lCountMisses, mNetwork.size(), lengthWanted);
    
    return retVal;
}


static PyMethodDef SNCMethods[] = {
    {"evalNetwork", evalNetwork, METH_VARARGS,
     "Evaluate a sorting network."},
    {NULL, NULL, 0, NULL}        /* Sentinel (?!?) */
};

// Needed by Python to initialize the SNC module
PyMODINIT_FUNC
initSNC(void)
{
    (void) Py_InitModule("SNC", SNCMethods);
}