Beispiel #1
0
    def greedyCliquesSemiExhaustive(this, weight=None, progressStack=False):
        untouched = set(xrange(this.size))
        weights = None
        maxormin = max
        if isinstance(weight, (int, float)):
            if weight < 0:
                maxormin = min
        elif weight is not None:
            weights = [weight(v) for v in this.sections]

        wMax = -common.Infinity
        QMax = set()
        if progressStack is not None:
            progressStack.push(title="Iterating remaining initial conditions for clique searching", maximum=this.size)
            
        while len(untouched) != 0:
            v0 = this.pickMaxWeightNode(untouched, weights=weights, maxormin=maxormin)
            curGC = this.greedyCliques(v0, weight=weight, progressStack=None)
            if curGC[1] > wMax:
                (QMax, wMax) = curGC
            untouched.difference_update(curGC[0])

            if progressStack is not None:
                if not progressStack.update(this.size - len(untouched), message="Evaluating initial conditions: %d candidates left (current score: %g)..." % (len(untouched), wMax)):
                    break
                
        if progressStack is not None:
            progressStack.pop()

        return (QMax, wMax)
Beispiel #2
0
    def reduceNet(this, progressStack=None):
        if len(this.sectionBuffer) != 0:
            if not progressStack is None:
                progressStack.push(title='Simplying course structure', maximum=len(this.sectionBuffer))
            
            for newsects in this.sectionBuffer:
                noEquiv = True
                for oldsects in this.sections:
                    if oldsects == newsects:
                        h = str(oldsects)
                        if h in this.otherEquivalentSections:
                            this.otherEquivalentSections[h].append(newsects)
                        else:
                            this.otherEquivalentSections[h] = [newsects]
                        noEquiv = False
                        break
                if noEquiv:
                    this.sections.append(newsects)

                if not progressStack is None:
                    progressStack.increase(1, message='Evaluating section %s for network construction...'%str(newsects))
                
            oldsize = this.size
            this.size = len(this.sections)
            this.adjlist.extend([set() for i in xrange(this.size - oldsize)]) # cannot use * operator because we need N *copies* of set().

            if not progressStack is None:
                progressStack.pop()
Beispiel #3
0
    def greedyCliques(this, initNode=None, weight=None, progressStack=None):
        maxormin = max
        weights = None
        if isinstance(weight, (int, float)) and weight < 0:
            maxormin = min
        elif weight is not None:
            weights = [weight(s) for s in this.sections]

        rg = common.randomGenerator()
        xr = xrange(this.size)

        V0 = this.pickMaxWeightNode(xrange(this.size), weights=weights, maxormin=maxormin, rg=rg) if initNode is None else initNode
            
        Q = set((V0,))
        rho = set(this.adjlist[V0])
        totalweight = 1 if weights is None else weights[V0]

        initRhoSize = len(rho)
        hasProgress = isinstance(progressStack, IProgressStack)

        if hasProgress:
            progressStack.push(title="Searching for cliques", maximum=initRhoSize)
        
        while len(rho) != 0: # O(k)*
            if hasProgress:
                if not progressStack.update(initRhoSize - len(rho), message="Enlarging cliques: %d candidates left (current score: %g)..." % (len(rho), totalweight)):
                    break
            
            # find all new common neighbors, and
            # pick the one with most common neighbors
            maxv = None
            if weights is None:
                vmax = maxormin([(len(rho & this.adjlist[v]), rg, v) for v in rho])[2] # O(k^2)
                Q.add(vmax)
                rho.intersection_update(this.adjlist[vmax])
                totalweight += 1
            else:
                adjweights = dict((v, sum(weights[u] for u in this.adjlist[v] & rho)) for v in rho)
                maxp = max((weights[v], adjweights[v], rg, v) for v in rho)
                Q.add(maxp[-1])
                rho.intersection_update(this.adjlist[maxp[-1]])
                totalweight += weights[maxp[-1]]

        if hasProgress:
            progressStack.pop()
            
        return (Q, totalweight if maxormin == max else -totalweight) # O(k^3)
Beispiel #4
0
 def evaluateAllVertices(this, progressStack=None):
     if progressStack is not None:
         progressStack.push(title='Constructing course network', maximum=this.size)
 
     for v in xrange(this.size):
         this.evaluateVertex(v)
         if progressStack is not None:
             progressStack.increase(1, message='Evaluating vertex #%d for network construction...'%v)
    
     if progressStack is not None:
         progressStack.pop()
Beispiel #5
0
    def __shuffle(self, x, random=None):
        """x, random=random.random -> shuffle list x in place; return None.

        Optional arg random is a 0-argument function returning a random
        float in [0.0, 1.0); by default, the standard random.random.

        taken from python2.7 because 3.5 does something different with
        different results
        """

        if random is None:
            random = self.random
        _int = int
        for i in reversed(xrange(1, len(x))):
            # pick an element in x[:i+1] with which to exchange x[i]
            j = _int(random() * (i+1))
            x[i], x[j] = x[j], x[i]
Beispiel #6
0
    def greedyCliquesExhaustive(this, weight=None, progressStack=False):
        hasProgress = isinstance(progressStack, IProgressStack)

        if hasProgress:
            progressStack.push(title="Iterating initial conditions for clique searching", maximum=this.size)
        
        #if not allResults:
            
        QMax = set()
        wMax = -common.Infinity
        for v in xrange(this.size):
            if hasProgress:
                if not progressStack.increase(1, message="Evaluating vertex #%d for cliques (current score: %g)"%(v,wMax)):
                    break
                
            curGC = this.greedyCliques(v, weight=weight, progressStack=None)
            if curGC[1] > wMax:
                (QMax, wMax) = curGC

        if hasProgress:
            progressStack.pop()
            
        return (QMax, wMax)
Beispiel #7
0
    def __sample(self, population, k):
        """Chooses k unique random elements from a population sequence.

        Returns a new list containing elements from the population while
        leaving the original population unchanged.  The resulting list is
        in selection order so that all sub-slices will also be valid random
        samples.  This allows raffle winners (the sample) to be partitioned
        into grand prize and second place winners (the subslices).

        Members of the population need not be hashable or unique.  If the
        population contains repeats, then each occurrence is a possible
        selection in the sample.

        To choose a sample in a range of integers, use xrange as an argument.
        This is especially fast and space efficient for sampling from a
        large population:   sample(xrange(10000000), 60)

        taken from python2.7 because 3.5 does something different with
        different results
        """

        # Sampling without replacement entails tracking either potential
        # selections (the pool) in a list or previous selections in a set.

        # When the number of selections is small compared to the
        # population, then tracking selections is efficient, requiring
        # only a small set and an occasional reselection.  For
        # a larger number of selections, the pool tracking method is
        # preferred since the list takes less space than the
        # set and it doesn't suffer from frequent reselections.

        n = len(population)
        if not 0 <= k <= n:
            raise ValueError("sample larger than population")
        random = self.random
        _int = int
        result = [None] * k
        setsize = 21        # size of a small set minus size of an empty list
        if k > 5:
            setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets
        if n <= setsize or hasattr(population, "keys"):
            # An n-length list is smaller than a k-length set, or this is a
            # mapping type so the other algorithm wouldn't work.
            pool = list(population)
            for i in xrange(k):         # invariant:  non-selected at [0,n-i)
                j = _int(random() * (n-i))
                result[i] = pool[j]
                pool[j] = pool[n-i-1]   # move non-selected item into vacancy
        else:
            try:
                selected = set()
                selected_add = selected.add
                for i in xrange(k):
                    j = _int(random() * n)
                    while j in selected:
                        j = _int(random() * n)
                    selected_add(j)
                    result[i] = population[j]
            except (TypeError, KeyError):   # handle (at least) sets
                if isinstance(population, list):
                    raise
                return self.sample(tuple(population), k)
        return result
Beispiel #8
0
 def evaluateVertex(this, v):
     for i in xrange(v+1, this.size):
         if this.sections[i].course != this.sections[v].course and not this.sections[i].intersect(this.sections[v]):
             this.adjlist[i].add(v)
             this.adjlist[v].add(i)
Beispiel #9
0
    def exactCliques(this, weight=None, progressStack=False):

        hasProgress = isinstance(progressStack, IProgressStack)

        if hasProgress:
            progressStack.push(title="Search for cliques exactly", maximum=this.size, unitstep=1)
        
        
        QMax = []
        wMax = -common.Infinity

        QsPrev = dict( ((v,), 1) for v in xrange(this.size) )
        
        weights = None
        searchformax = True
        
        if isinstance(weight, (int, float)):
            if weight < 0:
                searchformax = False
        elif weight is not None:
            weights = [weight(v) for v in this.sections]
            QsPrev = dict( ((v,), w) for (v, w) in enumerate(weights) )
            
        for QSize in xrange(this.size):
            if hasProgress:
                progressStack.push(message="Current clique size: %d (current score: %g)"%(QSize, wMax), maximum=len(QsPrev))
            
            QsNext = dict()
            
            # find all total neighbors and append to list.
            for (Q, W) in QsPrev.items():
                if hasProgress:
                    if not progressStack.increase(1, message="Current clique size %d (current score: %g)"%(QSize, wMax)):
                        progressStack.pop()
                        progressStack.pop()
                        return (QMax, wMax)
                
                neis = [this.adjlist[v] for v in Q]
                totalNeis = set(neis[0])

                for nei in neis[1:]:
                    totalNeis.intersection_update(nei)

                if len(totalNeis) == 0:
                    if not searchformax:
                        if hasProgress:
                            progressStack.pop()
                            progressStack.pop()
                        return (set(Q), -W)
                    else:
                        if W > wMax:
                            (QMax, wMax) = (set(Q), W)
                    
                for n in totalNeis:
                    Q2 = common.appendSorted(Q, n)
                    W2 = W
                    if weights is not None:
                        W2 += weights[n]
                    else:
                        W2 += 1
                    QsNext[Q2] = W2

            QsPrev = QsNext
            
            if hasProgress:
                progressStack.pop()

            if len(QsPrev) == 0:
                break

        if hasProgress:
            progressStack.pop()

        return (QMax, wMax)
Beispiel #10
0
 def vertexWithMaxDegree(this):
     this.evaluateAllVertices()
     return max(xrange(this.size), key=lambda v:len(this.adjlist[v]))
Beispiel #11
0
 def verticesWithDegree(this, k):
     this.evaluateAllVertices()
     return [v for v in xrange(this.size) if len(this.adjlist[v]) == k]