def _tile_search2(Jobs, X, Y, cfg=config.Config): global _CkpointTime, _Placements, _TBestTiling, _TBestScore r = random.Random() N = len(Jobs) # M is the number of jobs that will be placed randomly. # N-M is the number of jobs that will be searched exhaustively. M = N - config.RandomSearchExhaustiveJobs M = max(M,0) xspacing = cfg['xspacing'] yspacing = cfg['yspacing'] # Must escape with Ctrl-C while 1: T = tiling.Tiling(X,Y) joborder = r.sample(range(N), N) minInletSize = tiling.minDimension(Jobs) for ix in joborder[:M]: Xdim,Ydim,job,rjob = Jobs[ix] T.removeInlets(minInletSize) if r.choice([0,1]): addpoints = T.validAddPoints(Xdim+xspacing,Ydim+yspacing) if not addpoints: break pt = r.choice(addpoints) T.addJob(pt, Xdim+xspacing, Ydim+yspacing, job) else: addpoints = T.validAddPoints(Ydim+xspacing,Xdim+yspacing) if not addpoints: break pt = r.choice(addpoints) T.addJob(pt, Ydim+xspacing, Xdim+yspacing, rjob) else: # Do exhaustive search on remaining jobs if N-M: remainingJobs = [] for ix in joborder[M:]: remainingJobs.append(Jobs[ix]) tilesearch1.initialize(0) tilesearch1._tile_search1(remainingJobs, T, 1) T = tilesearch1.bestTiling() if T: score = T.area() if score < _TBestScore: _TBestTiling,_TBestScore = T,score elif score == _TBestScore: if T.corners() < _TBestTiling.corners(): _TBestTiling,_TBestScore = T,score _Placements += 1 # If we've been at this for 3 seconds, print some status information if time.time() > _CkpointTime: printTilingStats()
def _tile_search2(Jobs, X, Y, cfg=config.Config): global _CkpointTime, _Placements, _TBestTiling, _TBestScore r = random.Random() N = len(Jobs) # M is the number of jobs that will be placed randomly. # N-M is the number of jobs that will be searched exhaustively. M = N - config.RandomSearchExhaustiveJobs M = max(M, 0) xspacing = cfg['xspacing'] yspacing = cfg['yspacing'] # Must escape with Ctrl-C while 1: T = tiling.Tiling(X, Y) joborder = r.sample(range(N), N) minInletSize = tiling.minDimension(Jobs) for ix in joborder[:M]: Xdim, Ydim, job, rjob = Jobs[ix] T.removeInlets(minInletSize) if r.choice([0, 1]): addpoints = T.validAddPoints(Xdim + xspacing, Ydim + yspacing) if not addpoints: break pt = r.choice(addpoints) T.addJob(pt, Xdim + xspacing, Ydim + yspacing, job) else: addpoints = T.validAddPoints(Ydim + xspacing, Xdim + yspacing) if not addpoints: break pt = r.choice(addpoints) T.addJob(pt, Ydim + xspacing, Xdim + yspacing, rjob) else: # Do exhaustive search on remaining jobs if N - M: remainingJobs = [] for ix in joborder[M:]: remainingJobs.append(Jobs[ix]) tilesearch1.initialize(0) tilesearch1._tile_search1(remainingJobs, T, 1) T = tilesearch1.bestTiling() if T: score = T.area() if score < _TBestScore: _TBestTiling, _TBestScore = T, score elif score == _TBestScore: if T.corners() < _TBestTiling.corners(): _TBestTiling, _TBestScore = T, score _Placements += 1 # If we've been at this for 3 seconds, print some status information if time.time() > _CkpointTime: printTilingStats() # Check for timeout - changed to file config if (config.Config['searchtimeout'] > 0) and ( (time.time() - _StartTime) > config.Config['searchtimeout']): raise KeyboardInterrupt gerbmerge.updateGUI("Performing automatic layout...")
def _tile_search1(Jobs, TSoFar, firstAddPoint, cfg=config.Config): """This recursive function does the following with an existing tiling TSoFar: * For each 4-tuple (Xdim,Ydim,job,rjob) in Jobs, the non-rotated 'job' is selected * For the non-rotated job, the list of valid add-points is found * For each valid add-point, the job is placed at this point in a new, cloned tiling. * The function then calls its recursively with the remaining list of jobs. * The rotated job is then selected and the list of valid add-points is found. Again, for each valid add-point the job is placed there in a new, cloned tiling. * Once again, the function calls itself recursively with the remaining list of jobs. * The best tiling encountered from all recursive calls is returned. If TSoFar is None it means this combination of jobs is not tileable. The side-effect of this function is to set _TBestTiling and _TBestScore to the best tiling encountered so far. _TBestTiling could be None if no valid tilings have been found so far. """ global _StartTime, _CkpointTime, _Placements, _TBestTiling, _TBestScore, _Permutations, _PrintStats if not TSoFar: return (None, float(sys.maxint)) if not Jobs: # Update the best tiling and score. If the new tiling matches # the best score so far, compare on number of corners, trying to # minimize them. score = TSoFar.area() if score < _TBestScore: _TBestTiling,_TBestScore = TSoFar,score elif score == _TBestScore: if TSoFar.corners() < _TBestTiling.corners(): _TBestTiling,_TBestScore = TSoFar,score _Placements += 1 if firstAddPoint: _Permutations += 1 return xspacing = cfg['xspacing'] yspacing = cfg['yspacing'] minInletSize = tiling.minDimension(Jobs) TSoFar.removeInlets(minInletSize) for job_ix in range(len(Jobs)): # Pop off the next job and construct remaining_jobs, a sub-list # of Jobs with the job we've just popped off excluded. Xdim,Ydim,job,rjob = Jobs[job_ix] remaining_jobs = Jobs[:job_ix]+Jobs[job_ix+1:] if 0: print "Level %d (%s)" % (level, job.name) TSoFar.joblist() for J in remaining_jobs: print J[2].name, ", ", print print '-'*75 # Construct add-points for the non-rotated and rotated job. # As an optimization, do not construct add-points for the rotated # job if the job is a square (duh). addpoints1 = TSoFar.validAddPoints(Xdim+xspacing,Ydim+yspacing) # unrotated job if Xdim != Ydim: addpoints2 = TSoFar.validAddPoints(Ydim+xspacing,Xdim+yspacing) # rotated job else: addpoints2 = [] # Recursively construct tilings for the non-rotated job and # update the best-tiling-so-far as we do so. if addpoints1: for ix in addpoints1: # Clone the tiling we're starting with and add the job at this # add-point. T = TSoFar.clone() T.addJob(ix, Xdim+xspacing, Ydim+yspacing, job) # Recursive call with the remaining jobs and this new tiling. The # point behind the last parameter is simply so that _Permutations is # only updated once for each permutation, not once per add-point. # A permutation is some ordering of jobs (N! choices) and some # ordering of non-rotated and rotated within that ordering (2**N # possibilities per ordering). _tile_search1(remaining_jobs, T, firstAddPoint and ix==addpoints1[0]) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. _Permutations += 2L**len(remaining_jobs) if addpoints2: for ix in addpoints2: # Clone the tiling we're starting with and add the job at this # add-point. Remember that the job is rotated so swap X and Y # dimensions. T = TSoFar.clone() T.addJob(ix, Ydim+xspacing, Xdim+yspacing, rjob) # Recursive call with the remaining jobs and this new tiling. _tile_search1(remaining_jobs, T, firstAddPoint and ix==addpoints2[0]) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. _Permutations += 2L**len(remaining_jobs) # If we've been at this for 3 seconds, print some status information if _PrintStats and time.time() > _CkpointTime: printTilingStats() # Check for timeout - changed to file config if (config.Config['searchtimeout'] > 0) and ((time.time() - _StartTime) > config.Config['searchtimeout']): raise KeyboardInterrupt gerbmerge.updateGUI("Performing automatic layout...")
def _tile_search1(Jobs, TSoFar, firstAddPoint, cfg=config.Config): """This recursive function does the following with an existing tiling TSoFar: * For each 4-tuple (Xdim,Ydim,job,rjob) in Jobs, the non-rotated 'job' is selected * For the non-rotated job, the list of valid add-points is found * For each valid add-point, the job is placed at this point in a new, cloned tiling. * The function then calls its recursively with the remaining list of jobs. * The rotated job is then selected and the list of valid add-points is found. Again, for each valid add-point the job is placed there in a new, cloned tiling. * Once again, the function calls itself recursively with the remaining list of jobs. * The best tiling encountered from all recursive calls is returned. If TSoFar is None it means this combination of jobs is not tileable. The side-effect of this function is to set _TBestTiling and _TBestScore to the best tiling encountered so far. _TBestTiling could be None if no valid tilings have been found so far. """ global _StartTime, _CkpointTime, _Placements, _TBestTiling, _TBestScore, _Permutations, _PrintStats if not TSoFar: return (None, float(sys.maxint)) if not Jobs: # Update the best tiling and score. If the new tiling matches # the best score so far, compare on number of corners, trying to # minimize them. score = TSoFar.area() if score < _TBestScore: _TBestTiling,_TBestScore = TSoFar,score elif score == _TBestScore: if TSoFar.corners() < _TBestTiling.corners(): _TBestTiling,_TBestScore = TSoFar,score _Placements += 1 if firstAddPoint: _Permutations += 1 return xspacing = cfg['xspacing'] yspacing = cfg['yspacing'] minInletSize = tiling.minDimension(Jobs) TSoFar.removeInlets(minInletSize) for job_ix in range(len(Jobs)): # Pop off the next job and construct remaining_jobs, a sub-list # of Jobs with the job we've just popped off excluded. Xdim,Ydim,job,rjob = Jobs[job_ix] remaining_jobs = Jobs[:job_ix]+Jobs[job_ix+1:] if 0: print "Level %d (%s)" % (level, job.name) TSoFar.joblist() for J in remaining_jobs: print J[2].name, ", ", print print '-'*75 # Construct add-points for the non-rotated and rotated job. # As an optimization, do not construct add-points for the rotated # job if the job is a square (duh). addpoints1 = TSoFar.validAddPoints(Xdim+xspacing,Ydim+yspacing) # unrotated job if Xdim != Ydim: addpoints2 = TSoFar.validAddPoints(Ydim+xspacing,Xdim+yspacing) # rotated job else: addpoints2 = [] # Recursively construct tilings for the non-rotated job and # update the best-tiling-so-far as we do so. if addpoints1: for ix in addpoints1: # Clone the tiling we're starting with and add the job at this # add-point. T = TSoFar.clone() T.addJob(ix, Xdim+xspacing, Ydim+yspacing, job) # Recursive call with the remaining jobs and this new tiling. The # point behind the last parameter is simply so that _Permutations is # only updated once for each permutation, not once per add-point. # A permutation is some ordering of jobs (N! choices) and some # ordering of non-rotated and rotated within that ordering (2**N # possibilities per ordering). _tile_search1(remaining_jobs, T, firstAddPoint and ix==addpoints1[0]) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. _Permutations += 2L**len(remaining_jobs) if addpoints2: for ix in addpoints2: # Clone the tiling we're starting with and add the job at this # add-point. Remember that the job is rotated so swap X and Y # dimensions. T = TSoFar.clone() T.addJob(ix, Ydim+xspacing, Xdim+yspacing, rjob) # Recursive call with the remaining jobs and this new tiling. _tile_search1(remaining_jobs, T, firstAddPoint and ix==addpoints2[0]) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. _Permutations += 2L**len(remaining_jobs) # If we've been at this for 3 seconds, print some status information if _PrintStats and time.time() > _CkpointTime: printTilingStats() # Check for timeout if (config.SearchTimeout > 0) and (time.time() - _StartTime > config.SearchTimeout): raise KeyboardInterrupt gerbmerge.updateGUI("Performing automatic layout...")
def run(self, q): """Perform a random search through all possible jobs given the provided panel size. Only self.placements & lastCheckTime are modified within this method. """ r = random.Random() N = len(self.jobs) # M is the number of jobs that will be placed randomly. # N-M is the number of jobs that will be searched exhaustively. M = N - self.RandomSearchExhaustiveJobs M = max(M, 0) # Track if a new bestTiling has been found # Also track how many placements it's been since then foundBetter = False placementsSinceLastCheck = 0 # Must escape with Ctrl-C while 1: currentTiling = self.baseTiling.clone() joborder = r.sample(range(N), N) minInletSize = tiling.minDimension(self.jobs) for ix in joborder[:M]: Xdim, Ydim, job, rjob = self.jobs[ix] currentTiling.removeInlets(minInletSize) if r.choice([0, 1]): addpoints = currentTiling.validAddPoints(Xdim + self.xspacing, Ydim + self.yspacing) if not addpoints: break pt = r.choice(addpoints) currentTiling.addJob(pt, Xdim + self.xspacing, Ydim + self.yspacing, job) else: addpoints = currentTiling.validAddPoints(Ydim + self.xspacing, Xdim + self.yspacing) if not addpoints: break pt = r.choice(addpoints) currentTiling.addJob(pt, Ydim + self.xspacing, Xdim + self.yspacing, rjob) else: # Do exhaustive search on remaining jobs if N - M: remainingJobs = [] for ix in joborder[M:]: remainingJobs.append(self.jobs[ix]) finalSearch = ExhaustiveSearch(remainingJobs, self.x, self.y, self.xspacing, self.yspacing, 0, currentTiling) finalSearch.run(False) if finalSearch.bestScore < self.bestScore: self.bestScore = finalSearch.bestScore self.bestTiling = finalSearch.bestTiling foundBetter = True self.placements += 1 placementsSinceLastCheck += 1 # If we've been at this for one period and found a better # tiling since last checkTime, output the new one if time.time() > self.lastCheckTime + self.syncPeriod: self.lastCheckTime = time.time() # Only output a tiling if it's better. We still report # attempled placements though # We also reset the placements tried if foundBetter is True: q.put((placementsSinceLastCheck, self.bestTiling), block=True) foundBetter = False else: q.put((placementsSinceLastCheck, None), block=True) placementsSinceLastCheck = 0 # Check for timeout if self.searchTimeout > 0 and ((time.time() - self.startTime) > self.searchTimeout): return
def _run(self, Jobs, tiles, firstAddPoint, printStats): """This recursive function does the following with an existing tiling baseTiling: * For each 4-tuple (Xdim,Ydim,job,rjob) in Jobs, the non-rotated 'job' is selected * For the non-rotated job, the list of valid add-points is found * For each valid add-point, the job is placed at this point in a new, cloned tiling. * The function then calls its recursively with the remaining list of jobs. * The rotated job is then selected and the list of valid add-points is found. Again, for each valid add-point the job is placed there in a new, cloned tiling. * Once again, the function calls itself recursively with the remaining list of jobs. * The best tiling encountered from all recursive calls is returned. If baseTiling is None it means this combination of jobs is not tileable. The side-effect of this function is to set self.bestTiling and self.bestScore to the best tiling encountered so far. self.bestTiling could be None if no valid tilings have been found so far. """ if not tiles: return (None, float("inf")) if not Jobs: # Update the best tiling and score. If the new tiling matches # the best score so far, compare on number of corners, trying to # minimize them. score = tiles.area() if score < self.bestScore or (score == self.bestScore and tiles.corners() < self.bestTiling.corners()): self.bestTiling = tiles self.bestScore = score if firstAddPoint: self.permutations += 1 return minInletSize = tiling.minDimension(Jobs) tiles.removeInlets(minInletSize) for job_ix in range(len(Jobs)): # Pop off the next job and construct remaining_jobs, a sub-list # of Jobs with the job we've just popped off excluded. Xdim, Ydim, job, rjob = Jobs[job_ix] remaining_jobs = Jobs[:job_ix] + Jobs[job_ix + 1:] # Construct add-points for the non-rotated and rotated job. # As an optimization, do not construct add-points for the rotated # job if the job is a square (duh). addpoints1 = tiles.validAddPoints(Xdim + self.xspacing, Ydim + self.yspacing) # unrotated job if Xdim != Ydim: addpoints2 = tiles.validAddPoints(Ydim + self.xspacing, Xdim + self.yspacing) # rotated job else: addpoints2 = [] # Recursively construct tilings for the non-rotated job and # update the best-tiling-so-far as we do so. if addpoints1: for ix in addpoints1: # Clone the tiling we're starting with and add the job at this # add-point. T = tiles.clone() T.addJob(ix, Xdim + self.xspacing, Ydim + self.yspacing, job) # Recursive call with the remaining jobs and this new tiling. The # point behind the last parameter is simply so that self.permutations is # only updated once for each permutation, not once per add-point. # A permutation is some ordering of jobs (N! choices) and some # ordering of non-rotated and rotated within that ordering (2**N # possibilities per ordering). self._run(remaining_jobs, T, firstAddPoint and ix == addpoints1[0], printStats) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. self.permutations += 2 ** len(remaining_jobs) if addpoints2: for ix in addpoints2: # Clone the tiling we're starting with and add the job at this # add-point. Remember that the job is rotated so swap X and Y # dimensions. T = tiles.clone() T.addJob(ix, Ydim + self.xspacing, Xdim + self.yspacing, rjob) # Recursive call with the remaining jobs and this new tiling. self._run(remaining_jobs, T, firstAddPoint and ix == addpoints2[0], printStats) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. self.permutations += 2 ** len(remaining_jobs) # If we've been at this for one period, print some status information if printStats and time.time() > self.lastCheckTime + self.syncPeriod: self.lastCheckTime = time.time() print(self) # Check for timeout if (self.searchTimeout > 0) and ((time.time() - self.startTime) > self.searchTimeout): return
def run(self, q): """Perform a random search through all possible jobs given the provided panel size. Only self.placements & lastCheckTime are modified within this method. """ r = random.Random() N = len(self.jobs) # M is the number of jobs that will be placed randomly. # N-M is the number of jobs that will be searched exhaustively. M = N - self.RandomSearchExhaustiveJobs M = max(M, 0) # Track if a new bestTiling has been found # Also track how many placements it's been since then foundBetter = False placementsSinceLastCheck = 0 # Must escape with Ctrl-C while 1: currentTiling = self.baseTiling.clone() joborder = r.sample(range(N), N) minInletSize = tiling.minDimension(self.jobs) for ix in joborder[:M]: Xdim, Ydim, job, rjob = self.jobs[ix] currentTiling.removeInlets(minInletSize) if r.choice([0, 1]): addpoints = currentTiling.validAddPoints( Xdim + self.xspacing, Ydim + self.yspacing) if not addpoints: break pt = r.choice(addpoints) currentTiling.addJob(pt, Xdim + self.xspacing, Ydim + self.yspacing, job) else: addpoints = currentTiling.validAddPoints( Ydim + self.xspacing, Xdim + self.yspacing) if not addpoints: break pt = r.choice(addpoints) currentTiling.addJob(pt, Ydim + self.xspacing, Xdim + self.yspacing, rjob) else: # Do exhaustive search on remaining jobs if N - M: remainingJobs = [] for ix in joborder[M:]: remainingJobs.append(self.jobs[ix]) finalSearch = ExhaustiveSearch(remainingJobs, self.x, self.y, self.xspacing, self.yspacing, 0, currentTiling) finalSearch.run(False) if finalSearch.bestScore < self.bestScore: self.bestScore = finalSearch.bestScore self.bestTiling = finalSearch.bestTiling foundBetter = True self.placements += 1 placementsSinceLastCheck += 1 # If we've been at this for one period and found a better # tiling since last checkTime, output the new one if time.time() > self.lastCheckTime + self.syncPeriod: self.lastCheckTime = time.time() # Only output a tiling if it's better. We still report # attempled placements though # We also reset the placements tried if foundBetter is True: q.put((placementsSinceLastCheck, self.bestTiling), block=True) foundBetter = False else: q.put((placementsSinceLastCheck, None), block=True) placementsSinceLastCheck = 0 # Check for timeout if self.searchTimeout > 0 and ( (time.time() - self.startTime) > self.searchTimeout): return
def _run(self, Jobs, tiles, firstAddPoint, printStats): """This recursive function does the following with an existing tiling baseTiling: * For each 4-tuple (Xdim,Ydim,job,rjob) in Jobs, the non-rotated 'job' is selected * For the non-rotated job, the list of valid add-points is found * For each valid add-point, the job is placed at this point in a new, cloned tiling. * The function then calls its recursively with the remaining list of jobs. * The rotated job is then selected and the list of valid add-points is found. Again, for each valid add-point the job is placed there in a new, cloned tiling. * Once again, the function calls itself recursively with the remaining list of jobs. * The best tiling encountered from all recursive calls is returned. If baseTiling is None it means this combination of jobs is not tileable. The side-effect of this function is to set self.bestTiling and self.bestScore to the best tiling encountered so far. self.bestTiling could be None if no valid tilings have been found so far. """ if not tiles: return (None, float("inf")) if not Jobs: # Update the best tiling and score. If the new tiling matches # the best score so far, compare on number of corners, trying to # minimize them. score = tiles.area() if score < self.bestScore or ( score == self.bestScore and tiles.corners() < self.bestTiling.corners()): self.bestTiling = tiles self.bestScore = score if firstAddPoint: self.permutations += 1 return minInletSize = tiling.minDimension(Jobs) tiles.removeInlets(minInletSize) for job_ix in range(len(Jobs)): # Pop off the next job and construct remaining_jobs, a sub-list # of Jobs with the job we've just popped off excluded. Xdim, Ydim, job, rjob = Jobs[job_ix] remaining_jobs = Jobs[:job_ix] + Jobs[job_ix + 1:] # Construct add-points for the non-rotated and rotated job. # As an optimization, do not construct add-points for the rotated # job if the job is a square (duh). addpoints1 = tiles.validAddPoints(Xdim + self.xspacing, Ydim + self.yspacing) # unrotated job if Xdim != Ydim: addpoints2 = tiles.validAddPoints(Ydim + self.xspacing, Xdim + self.yspacing) # rotated job else: addpoints2 = [] # Recursively construct tilings for the non-rotated job and # update the best-tiling-so-far as we do so. if addpoints1: for ix in addpoints1: # Clone the tiling we're starting with and add the job at this # add-point. T = tiles.clone() T.addJob(ix, Xdim + self.xspacing, Ydim + self.yspacing, job) # Recursive call with the remaining jobs and this new tiling. The # point behind the last parameter is simply so that self.permutations is # only updated once for each permutation, not once per add-point. # A permutation is some ordering of jobs (N! choices) and some # ordering of non-rotated and rotated within that ordering (2**N # possibilities per ordering). self._run(remaining_jobs, T, firstAddPoint and ix == addpoints1[0], printStats) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. self.permutations += 2**len(remaining_jobs) if addpoints2: for ix in addpoints2: # Clone the tiling we're starting with and add the job at this # add-point. Remember that the job is rotated so swap X and Y # dimensions. T = tiles.clone() T.addJob(ix, Ydim + self.xspacing, Xdim + self.yspacing, rjob) # Recursive call with the remaining jobs and this new tiling. self._run(remaining_jobs, T, firstAddPoint and ix == addpoints2[0], printStats) elif firstAddPoint: # Premature prune due to not being able to put this job anywhere. We # have pruned off 2^M permutations where M is the length of the remaining # jobs. self.permutations += 2**len(remaining_jobs) # If we've been at this for one period, print some status information if printStats and time.time( ) > self.lastCheckTime + self.syncPeriod: self.lastCheckTime = time.time() print(self) # Check for timeout if (self.searchTimeout > 0) and ( (time.time() - self.startTime) > self.searchTimeout): return