Exemplo n.º 1
0
    def localInputAndChecks(self, xmlNode):
        """
      Local method for additional reading.
      @ In, xmlNode, xml.etree.ElementTree.Element, Xml element node
      @ Out, None
    """
        GradientBasedOptimizer.localInputAndChecks(self, xmlNode)
        self.paramDict['alpha'] = float(self.paramDict.get('alpha', 0.602))
        self.paramDict['gamma'] = float(self.paramDict.get('gamma', 0.101))
        self.paramDict['A'] = float(
            self.paramDict.get('A', self.limit['mdlEval'] / 10.))
        self.paramDict['a'] = self.paramDict.get('a', None)
        self.paramDict['c'] = float(self.paramDict.get('c', 0.005))
        #FIXME the optimization parameters should probably all operate ONLY on normalized data!
        #  -> perhaps the whole optimizer should only work on optimized data.

        #FIXME normalizing doesn't seem to have the desired effect, currently; it makes the step size very small (for large scales)
        #if "a" was defaulted, use the average scale of the input space.
        #This is the suggested value from the paper, missing a 1/gradient term since we don't know it yet.
        if self.paramDict['a'] is None:
            self.paramDict['a'] = mathUtils.hyperdiagonal(
                np.ones(len(
                    self.getOptVars())))  # the features are always normalized
            self.raiseAMessage('Defaulting "a" gradient parameter to',
                               self.paramDict['a'])
        else:
            self.paramDict['a'] = float(self.paramDict['a'])

        self.constraintHandlingPara['innerBisectionThreshold'] = float(
            self.paramDict.get('innerBisectionThreshold', 1e-2))
        self.constraintHandlingPara['innerLoopLimit'] = float(
            self.paramDict.get('innerLoopLimit', 1000))

        self.gradDict['pertNeeded'] = self.gradDict['numIterForAve'] * 2

        stochDist = self.paramDict.get('stochasticDistribution', 'Hypersphere')
        if stochDist == 'Bernoulli':
            self.stochasticDistribution = Distributions.returnInstance(
                'Bernoulli', self)
            self.stochasticDistribution.p = 0.5
            self.stochasticDistribution.initializeDistribution()
            # Initialize bernoulli distribution for random perturbation. Add artificial noise to avoid that specular loss functions get false positive convergence
            # FIXME there has to be a better way to get two random numbers
            self.stochasticEngine = lambda: [
                (0.5 + randomUtils.random() * (1. + randomUtils.random(
                ) / 1000. * randomUtils.randomIntegers(-1, 1, self)))
                if self.stochasticDistribution.rvs() == 1 else -1. *
                (0.5 + randomUtils.random() * (1. + randomUtils.random(
                ) / 1000. * randomUtils.randomIntegers(-1, 1, self)))
                for _ in range(len(self.getOptVars()))
            ]
        elif stochDist == 'Hypersphere':
            self.stochasticEngine = lambda: randomUtils.randPointsOnHypersphere(
                len(self.getOptVars()))
        else:
            self.raiseAnError(
                IOError, self.paramDict['stochasticEngine'] +
                'is currently not supported for SPSA')
Exemplo n.º 2
0
    def chooseEvaluationPoints(self, opt, stepSize, constraints=None):
        """
      Determines new point(s) needed to evaluate gradient
      @ In, opt, dict, current opt point (normalized)
      @ In, stepSize, float, distance from opt point to sample neighbors
      @ In, constraints, dict, optional, boundary and functional constraints to respect when
                                         choosing new sampling points
      @ Out, evalPoints, list(dict), list of points that need sampling
      @ Out, evalInfo, list(dict), identifying information about points
    """
        dh = self._proximity * stepSize
        evalPoints = []
        evalInfo = []

        directions = np.atleast_1d(randomUtils.random(self.N) < 0.5) * 2 - 1
        for o, optVar in enumerate(self._optVars):
            # pick a new grad eval point
            optValue = opt[optVar]
            new = copy.deepcopy(opt)
            delta = dh * directions[o]  # note this is NORMALIZED space delta
            new[optVar] = optValue + delta
            # constraint handling
            if constraints is not None:
                # all constraints speak DENORM space, not NORM space
                denormed = constraints['denormalize'](new)
                altPoint = self._handleConstraints(
                    denormed, constraints['denormalize'](opt), optVar,
                    constraints)
                # need NORM point, delta
                new = constraints['normalize'](altPoint)
                delta = new[optVar] - opt[optVar]
            # store as samplable point
            evalPoints.append(new)
            evalInfo.append({'type': 'grad', 'optVar': optVar, 'delta': delta})
        return evalPoints, evalInfo
Exemplo n.º 3
0
def uniformCrossover(parents,**kwargs):
  """
    Method designed to perform crossover by swapping genes one by one
    @ In, parents, xr.DataArray, parents involved in the mating process.
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          parents, 2D array, parents in the current mating process.
          Shape is nParents x len(chromosome) i.e, number of Genes/Vars
    @ Out, children, xr.DataArray, children resulting from the crossover. Shape is nParents x len(chromosome) i.e, number of Genes/Vars
  """
  nParents,nGenes = np.shape(parents)
  children = xr.DataArray(np.zeros((int(2*comb(nParents,2)),np.shape(parents)[1])),
                              dims=['chromosome','Gene'],
                              coords={'chromosome': np.arange(int(2*comb(nParents,2))),
                                      'Gene':parents.coords['Gene'].values})

  if (kwargs['crossoverProb'] == None) or ('crossoverProb' not in kwargs.keys()):
    crossoverProb = randomUtils.random(dim=1, samples=1)
  else:
    crossoverProb = kwargs['crossoverProb']

  index = 0
  parentsPairs = list(combinations(parents,2))
  for parentPair in parentsPairs:
    parent1 = parentPair[0].values
    parent2 = parentPair[1].values
    children1,children2 = uniformCrossoverMethod(parent1,parent2,crossoverProb)
    children[index]   = copy.deepcopy(children1)
    children[index+1] = copy.deepcopy(children2)
    index = index + 1
  return children
Exemplo n.º 4
0
def onePointCrossover(parents,**kwargs):
  """
    Method designed to perform crossover by swapping chromosome portions before/after specified or sampled location
    @ In, parents, xr.DataArray, parents involved in the mating process.
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          crossoverProb, float, crossoverProb determines when child takes genes from a specific parent, default is random
          points, integer, point at which the cross over happens, default is random
          variables, list, variables names.
    @ Out, children, np.array, children resulting from the crossover. Shape is nParents x len(chromosome) i.e, number of Genes/Vars
  """
  nParents,nGenes = np.shape(parents)
  # Number of children = 2* (nParents choose 2)
  children = xr.DataArray(np.zeros((int(2*comb(nParents,2)),nGenes)),
                              dims=['chromosome','Gene'],
                              coords={'chromosome': np.arange(int(2*comb(nParents,2))),
                                      'Gene':kwargs['variables']})


  # defaults
  if (kwargs['crossoverProb'] == None) or ('crossoverProb' not in kwargs.keys()):
    crossoverProb = randomUtils.random(dim=1, samples=1)
  else:
    crossoverProb = kwargs['crossoverProb']

  # create children
  parentsPairs = list(combinations(parents,2))

  for ind,parent in enumerate(parentsPairs):
    parent = np.array(parent).reshape(2,-1) # two parents at a time

    if randomUtils.random(dim=1,samples=1) <= crossoverProb:
      if (kwargs['points'] == None) or ('points' not in kwargs.keys()):
        point = list([randomUtils.randomIntegers(1,nGenes-1,None)])
      elif (any(i>=nGenes-1 for i in kwargs['points'])):
        raise ValueError('Crossover point cannot be larger than number of Genes (variables)')
      else:
        point = kwargs['points']
      for i in range(nGenes):
        if len(point)>1:
          raise ValueError('In one Point Crossover a single crossover location should be provided!')
        children[2*ind:2*ind+2,i] = copy.deepcopy(parent[np.arange(0,2)*(i<point[0])+np.arange(-1,-3,-1)*(i>=point[0]),i])
    else:
      # Each child is just a copy of the parents
      children[2*ind:2*ind+2,:] = copy.deepcopy(parent)

  return children
Exemplo n.º 5
0
  def localInputAndChecks(self, xmlNode, paramInput):
    """
      Local method for additional reading.
      @ In, xmlNode, xml.etree.ElementTree.Element, Xml element node
      @ In, paramInput, InputData.ParameterInput, the parsed parameters
      @ Out, None
    """
    GradientBasedOptimizer.localInputAndChecks(self, xmlNode, paramInput)
    self.currentDirection   = None
    numValues = self._numberOfSamples()
    # set the initial step size
    ## use the hyperdiagonal of a unit hypercube with a side length equal to the user's provided initialStepSize * 1.0
    stepPercent = float(self.paramDict.get('initialStepSize', 0.05))
    self.paramDict['initialStepSize'] = mathUtils.hyperdiagonal(np.ones(numValues)*stepPercent)
    self.raiseADebug('Based on initial step size factor of "{:1.5e}", initial step size is "{:1.5e}"'
                         .format(stepPercent, self.paramDict['initialStepSize']))
    # set the perturbation distance
    ## if not given, default to 10% of the step size
    self.paramDict['pertDist'] = float(self.paramDict.get('perturbationDistance',0.01))
    self.raiseADebug('Perturbation distance is "{:1.5e}" percent of the step size'
                         .format(self.paramDict['pertDist']))

    self.constraintHandlingPara['innerBisectionThreshold'] = float(self.paramDict.get('innerBisectionThreshold', 1e-2))
    if not 0 < self.constraintHandlingPara['innerBisectionThreshold'] < 1:
      self.raiseAnError(IOError,'innerBisectionThreshold must be between 0 and 1; got',self.constraintHandlingPara['innerBisectionThreshold'])
    self.constraintHandlingPara['innerLoopLimit'] = float(self.paramDict.get('innerLoopLimit', 1000))

    self.gradDict['pertNeeded'] = self.gradDict['numIterForAve'] * (self.paramDict['pertSingleGrad']+1)

    # determine the number of indpendent variables (scalar and vectors included)
    stochDist = self.paramDict.get('stochasticDistribution', 'Hypersphere')
    if stochDist == 'Bernoulli':
      self.stochasticDistribution = Distributions.returnInstance('Bernoulli',self)
      self.stochasticDistribution.p = 0.5
      self.stochasticDistribution.initializeDistribution()
      # Initialize bernoulli distribution for random perturbation. Add artificial noise to avoid that specular loss functions get false positive convergence
      # FIXME there has to be a better way to get two random numbers
      self.stochasticEngine = lambda: [(0.5+randomUtils.random()*(1.+randomUtils.random()/1000.*randomUtils.randomIntegers(-1, 1, self))) if self.stochasticDistribution.rvs() == 1 else
                                   -1.*(0.5+randomUtils.random()*(1.+randomUtils.random()/1000.*randomUtils.randomIntegers(-1, 1, self))) for _ in range(numValues)]
    elif stochDist == 'Hypersphere':
      # TODO assure you can't get a "0" along any dimension! Need to be > 1e-15. Right now it's just highly unlikely.
      self.stochasticEngine = lambda: randomUtils.randPointsOnHypersphere(numValues) if numValues > 1 else [randomUtils.randPointsOnHypersphere(numValues)]
    else:
      self.raiseAnError(IOError, self.paramDict['stochasticEngine']+'is currently not supported for SPSA')
Exemplo n.º 6
0
 def _checkAcceptability(self, traj, opt, optVal, info):
     """
   Check if new opt point is acceptably better than the old one
   @ In, traj, int, identifier
   @ In, opt, dict, new opt point
   @ In, optVal, float, new optimization value
   @ In, info, dict, meta information about the opt point
   @ Out, acceptable, str, acceptability condition for point
   @ Out, old, dict, old opt point
   @ Out, rejectReason, str, reject reason of opt point, or return None if accepted
 """
     # Check acceptability
     # NOTE: if self._optPointHistory[traj]: -> faster to use "try" for all but the first time
     try:
         old, _ = self._optPointHistory[traj][-1]
         oldVal = old[self._objectiveVar]
         # check if same point
         self.raiseADebug(
             ' ... change: {d: 1.3e} new objective: {n: 1.6e} old objective: {o: 1.6e}'
             .format(d=opt[self._objectiveVar] - oldVal,
                     o=oldVal,
                     n=opt[self._objectiveVar]))
         # if this is an opt point rerun, accept it without checking.
         if self._acceptRerun[traj]:
             acceptable = 'rerun'
             self._acceptRerun[traj] = False
         elif all(opt[var] == old[var] for var in self.toBeSampled):
             # this is the classic "same point" trap; we accept the same point, and check convergence later
             acceptable = 'accepted'
         else:
             if self._acceptabilityCriterion(
                     oldVal, opt[self._objectiveVar]) > randomUtils.random(
                         dim=1, samples=1):  # TODO replace it back
                 acceptable = 'accepted'
             else:
                 acceptable = 'rejected'
     except IndexError:
         # if first sample, simply assume it's better!
         acceptable = 'first'
         old = None
     self._acceptHistory[traj].append(acceptable)
     self.raiseADebug(' ... {a}!'.format(a=acceptable))
     return acceptable, old, 'None'
Exemplo n.º 7
0
def inversionMutator(offSprings, **kwargs):
    """
    This method is designed mirror a sequence of genes in each chromosome with probability = mutationProb.
    The sequence of genes to be mirrored is completely random.
    E.g. given chromosome C = [0,1,2,3,4,5,6,7,8,9] and sampled locL=2 locU=6;
         New chromosome  C' = [0,1,6,5,4,3,2,7,8,9]
    @ In, offSprings, xr.DataArray, children resulting from the crossover process
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          mutationProb, float, probability that governs the mutation process, i.e., if prob < random number, then the mutation will occur
    @ Out, offSprings, xr.DataArray, children resulting from the crossover process
  """
    for child in offSprings:
        # the mutation is performed for each child independently
        if randomUtils.random(dim=1, samples=1) < kwargs['mutationProb']:
            # sample gene locations: i.e., determine loc1 and loc2
            locRangeList = list(range(0, child.values.shape[0]))
            index1 = randomUtils.randomIntegers(0,
                                                len(locRangeList),
                                                caller=None,
                                                engine=None)
            loc1 = locRangeList[index1]
            locRangeList.pop(loc1)
            index2 = randomUtils.randomIntegers(0,
                                                len(locRangeList),
                                                caller=None,
                                                engine=None)
            loc2 = locRangeList[index2]
            if loc1 > loc2:
                locL = loc2
                locU = loc1
            elif loc1 < loc2:
                locL = loc1
                locU = loc2
            ##############
            # select sequence to be mirrored and mirror it
            seq = child.values[locL:locU + 1]
            mirrSeq = seq[::-1]
            ##############
            # insert mirrored sequence into child
            child.values[locL:locU + 1] = mirrSeq

    return offSprings
Exemplo n.º 8
0
def rouletteWheel(population,**kwargs):
  """
    Roulette Selection mechanism for parent selection
    @ In, population, xr.DataArray, populations containing all chromosomes (individuals) candidate to be parents, i.e. population.values.shape = populationSize x nGenes.
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          fitness, xr.DataArray, fitness of each chromosome (individual) in the population, i.e., np.shape(fitness) = 1 x populationSize
          variables, list, variable names.
          nParents, int, number of required parents.
    @ Out, selectedParents, xr.DataArray, selected parents, i.e. np.shape(selectedParents) = nParents x nGenes.
  """
  # Arguments
  pop = copy.deepcopy(population)
  fitness = copy.deepcopy(kwargs['fitness'])
  nParents= kwargs['nParents']
  # if nparents = population size then do nothing (whole population are parents)
  if nParents == pop.shape[0]:
    return population
  elif nParents > pop.shape[0]:
    raise IOError('Number of parents is greater than population size')
  # begin the roulette selection algorithm
  selectedParent = xr.DataArray(
        np.zeros((nParents,np.shape(pop)[1])),
        dims=['chromosome','Gene'],
        coords={'chromosome':np.arange(nParents),
                'Gene': kwargs['variables']})
  # imagine a wheel that is partitioned according to the selection probabilities

  for i in range(nParents):
    # set a random pointer
    roulettePointer = randomUtils.random(dim=1, samples=1)
    # initialize Probability
    counter = 0
    selectionProb = fitness.data/np.sum(fitness.data) # Share of the pie (rouletteWheel)
    sumProb = selectionProb[counter]

    while sumProb < roulettePointer :
      counter += 1
      sumProb += selectionProb[counter]
    selectedParent[i,:] = pop.values[counter,:]
    pop = np.delete(pop, counter, axis=0)
    fitness = np.delete(fitness,counter,axis=0)
  return selectedParent
Exemplo n.º 9
0
def scrambleMutator(offSprings, **kwargs):
    """
    This method performs the scramble mutator. For each child, a subset of genes is chosen
    and their values are shuffled randomly.
    @ In, offSprings, xr.DataArray, offsprings after crossover
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          chromosome, numpy.array, the chromosome that will mutate to the new child
          locs, list, the locations of the genes to be randomly scrambled
          mutationProb, float, probability that governs the mutation process, i.e., if prob < random number, then the mutation will occur
          variables, list, variables names.
    @ Out, child, np.array, the mutated chromosome, i.e., the child.
  """
    locs = kwargs['locs']
    if locs == None:
        nLocs = randomUtils.randomIntegers(0, offSprings.sizes['Gene'] - 1,
                                           None)
        locs = []
        for i in range(nLocs):
            l = randomUtils.randomIntegers(0, offSprings.sizes['Gene'] - 1,
                                           None)
            locs.append(l)
        locs = list(set(locs))
    nMutable = len(locs)
    # initializing children
    children = xr.DataArray(np.zeros((np.shape(offSprings))),
                            dims=['chromosome', 'Gene'],
                            coords={
                                'chromosome':
                                np.arange(np.shape(offSprings)[0]),
                                'Gene': kwargs['variables']
                            })
    for i in range(np.shape(offSprings)[0]):
        children[i] = copy.deepcopy(offSprings[i])
        new = list(itemgetter(*locs)(offSprings[i].values))
        for ind, element in enumerate(locs):
            if randomUtils.random(dim=1, samples=1) < kwargs['mutationProb']:
                children[i,
                         locs[0]:locs[-1] + 1] = randomUtils.randomPermutation(
                             list(offSprings.data[i, locs[0]:locs[-1] + 1]),
                             None)
    return children
Exemplo n.º 10
0
def uniformCrossoverMethod(parent1,parent2,crossoverProb):
  """
    Method designed to perform a uniform crossover on 2 arrays
    @ In, parent1: first array
    @ In, parent2: second array
    @ In, crossoverProb: crossover probability for each gene
    @ Out, children1: first generated array
    @ Out, children2: second generated array
  """
  children1 = np.zeros(parent1.size)
  children2 = np.zeros(parent2.size)

  for pos in range(parent1.size):
    if randomUtils.random(dim=1,samples=1)<crossoverProb:
      children1[pos] = parent1[pos]
      children2[pos] = parent2[pos]
    else:
      children1[pos] = parent2[pos]
      children2[pos] = parent1[pos]

  return children1,children2
Exemplo n.º 11
0
def swapMutator(offSprings, **kwargs):
    """
    This method performs the swap mutator. For each child, two genes are sampled and switched
    E.g.:
    child=[a,b,c,d,e] --> b and d are selected --> child = [a,d,c,b,e]
    @ In, offSprings, xr.DataArray, children resulting from the crossover process
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          locs, list, the 2 locations of the genes to be swapped
          mutationProb, float, probability that governs the mutation process, i.e., if prob < random number, then the mutation will occur
          variables, list, variables names.
    @ Out, children, xr.DataArray, the mutated chromosome, i.e., the child.
  """
    if kwargs['locs'] == None:
        locs = list(
            set(
                randomUtils.randomChoice(list(
                    np.arange(offSprings.data.shape[1])),
                                         size=2,
                                         replace=False)))
        loc1 = locs[0]
        loc2 = locs[1]
    else:
        loc1 = kwargs['locs'][0]
        loc2 = kwargs['locs'][1]
    # initializing children
    children = xr.DataArray(np.zeros((np.shape(offSprings))),
                            dims=['chromosome', 'Gene'],
                            coords={
                                'chromosome':
                                np.arange(np.shape(offSprings)[0]),
                                'Gene': kwargs['variables']
                            })
    for i in range(np.shape(offSprings)[0]):
        children[i] = copy.deepcopy(offSprings[i])
        ## TODO What happens if loc1 or 2 is out of range?! should we raise an error?
        if randomUtils.random(dim=1, samples=1) <= kwargs['mutationProb']:
            children[i, loc1] = offSprings[i, loc2]
            children[i, loc2] = offSprings[i, loc1]
    return children
Exemplo n.º 12
0
    def chooseEvaluationPoints(self, opt, stepSize):
        """
      Determines new point(s) needed to evaluate gradient
      @ In, opt, dict, current opt point (normalized)
      @ In, stepSize, float, distance from opt point to sample neighbors
      @ Out, evalPoints, list(dict), list of points that need sampling
      @ Out, evalInfo, list(dict), identifying information about points
    """
        dh = self._proximity * stepSize
        evalPoints = []
        evalInfo = []

        directions = np.asarray(randomUtils.random(self.N) < 0.5) * 2 - 1
        for o, optVar in enumerate(self._optVars):
            optValue = opt[optVar]
            new = copy.deepcopy(opt)
            delta = dh * directions[o]
            new[optVar] = optValue + delta
            evalPoints.append(new)
            evalInfo.append({'type': 'grad', 'optVar': optVar, 'delta': delta})

        return evalPoints, evalInfo
Exemplo n.º 13
0
def bitFlipMutator(offSprings, **kwargs):
    """
    This method is designed to flip a single gene in each chromosome with probability = mutationProb.
    E.g. gene at location loc is flipped from current value to newValue
    The gene to be flipped is completely random.
    The new value of the flipped gene is is completely random.
    @ In, offSprings, xr.DataArray, children resulting from the crossover process
    @ In, kwargs, dict, dictionary of parameters for this mutation method:
          mutationProb, float, probability that governs the mutation process, i.e., if prob < random number, then the mutation will occur
    @ Out, offSprings, xr.DataArray, children resulting from the crossover process
  """
    for child in offSprings:
        # the mutation is performed for each child independently
        if randomUtils.random(dim=1, samples=1) < kwargs['mutationProb']:
            # sample gene location to be flipped: i.e., determine loc
            chromosomeSize = child.values.shape[0]
            loc = randomUtils.randomIntegers(0,
                                             chromosomeSize,
                                             caller=None,
                                             engine=None)
            ##############
            # sample value: i.e., determine newValue
            if kwargs['sampleRange'] == 'local':
                rangeValues = list(set(offSprings[:, loc].values))
            else:  #kwargs['sampleRange']=='global'
                rangeValues = offSprings.values.ravel().tolist()
            rangeValues.pop(child.values[loc])
            newValuePos = randomUtils.randomIntegers(0,
                                                     len(rangeValues),
                                                     caller=None,
                                                     engine=None)
            newValue = rangeValues[newValuePos]
            ##############
            # gene at location loc is flipped from current value to newValue
            child.values[loc] = newValue

    return offSprings
Exemplo n.º 14
0
    def _nextNeighbour(self, rlz, fraction=1):
        """
      Perturbs the state to find the next random neighbour based on the cooling schedule
      @ In, rlz, dict, current realization
      @ In, fraction, float, optional, the current iteration divided by the iteration limit i.e., $\frac{iter}{Limit}$
      @ Out, nextNeighbour, dict, the next random state

      for exponential cooling:
      .. math::

          fraction = \\frac{iter}{Limit}

          amp = 1-fraction

          delta = \\frac{-amp}{2} + amp * r

      where :math: `r \sim \mathcal{U}(0,1)`

      for boltzmann cooling:
      .. math::

          amp = min(\\sqrt(T), \\frac{1}{3*alpha}

          delta = r * alpha * amp

      where :math: `r \\sim \\mathcal{N}(0,1)`

      for cauchy cooling:
      .. math::

          amp = r

          delta = alpha * T * tan(amp)

      where :math: `r \\sim \\mathcal{U}(-\\pi,\\pi)`

      for veryfast cooling:
      .. math::

          amp = r

          delta = \\sign(amp-0.5)*T*((1.0+\\frac{1.0}{T})^{\\abs{2*amp-1}-1.0}

      where :math: `r \\sim \\mathcal{U}(0,1)`
    """
        nextNeighbour = {}
        D = len(self.toBeSampled.keys())
        alpha = 0.94
        if self._coolingMethod in ['exponential', 'geometric']:
            amp = ((fraction)**-1) / 20
            r = randomUtils.random(dim=D, samples=1)
            delta = (-amp / 2.) + amp * r
        elif self._coolingMethod == 'boltzmann':
            amp = min(np.sqrt(self.T), 1 / 3.0 / alpha)
            delta = randomUtils.randomNormal(dim=D, size=1) * alpha * amp
        elif self._coolingMethod == 'veryfast':
            amp = randomUtils.random(dim=D, samples=1)
            delta = np.sign(amp - 0.5) * self.T * (
                (1 + 1.0 / self.T)**abs(2 * amp - 1) - 1.0)
        elif self._coolingMethod == 'cauchy':
            amp = (np.pi -
                   (-np.pi)) * randomUtils.random(dim=D, samples=1) - np.pi
            delta = alpha * self.T * np.tan(amp)
        for i, var in enumerate(self.toBeSampled.keys()):
            nextNeighbour[var] = rlz[var] + delta[i]
            self.info['amp_' + var] = amp
            self.info['delta_' + var] = delta[i]
        self.info['fraction'] = fraction
        return nextNeighbour
Exemplo n.º 15
0
    return True

### BEGIN TESTS
# NOTE that due to seeding, this test relies HEAVILY on not changing the orders of calls to randomUtils!
# Reseed at the beginning of sections and add new tests to the end of sections.

# set the stochastic environment TODO check both someday?
# cannot pass the numpy as the stochasticEnv
randomUtils.stochasticEnv = 'crow'

eng = randomUtils.newRNG()
# randomSeed(), setting the random seed
randomUtils.randomSeed(42,engine=None)
randomUtils.randomSeed(42,engine=eng)
# check that seed is set
checkAnswer('First float from first seed for engine not provided',randomUtils.random(engine=None),0.374540118847)
checkAnswer('First float from first seed for local engine provided',randomUtils.random(engine=eng),0.374540118847)

# check resetting seed
randomUtils.randomSeed(12345,engine=None) #next float would be 0.95071430641 if seed didn't change
randomUtils.randomSeed(12345,engine=eng) #next float would be 0.95071430641 if seed didn't change
checkAnswer('First float from second seed for engine not provided',randomUtils.random(engine=None),0.929616092817)
checkAnswer('First float from second seed for local engine provided',randomUtils.random(engine=eng),0.929616092817)

### random(), sampling on [0,1]
## single sampling
randomUtils.randomSeed(42,engine=None)
randomUtils.randomSeed(42,engine=eng)

vals = np.array([randomUtils.random(engine=None) for _ in range(int(1e5))])
mean = np.average(vals)
Exemplo n.º 16
0
    def localGenerateInput(self, model, myInput):
        """
      Function to select the next most informative point for refining the limit
      surface search.
      After this method is called, the self.inputInfo should be ready to be sent
      to the model
      @ In, model, model instance, an instance of a model
      @ In, myInput, list, a list of the original needed inputs for the model (e.g. list of files, etc.)
      @ Out, None
    """
        varCount = 0
        self.inputInfo['distributionName'] = {
        }  #Used to determine which distribution to change if needed.
        self.inputInfo['distributionType'] = {
        }  #Used to determine which distribution type is used
        weight = 1.0
        for varName in self.axisName:
            # new implementation for ND LHS
            if not "<distribution>" in varName:
                if self.variables2distributionsMapping[varName][
                        'totDim'] > 1 and self.variables2distributionsMapping[
                            varName]['reducedDim'] == 1:
                    # to avoid double count of weight for ND distribution; I need to count only one variable instaed of N
                    distName = self.variables2distributionsMapping[varName][
                        'name']
                    if self.variablesTransformationDict:
                        for distVarName in self.distributions2variablesMapping[
                                distName]:
                            for subVar in utils.first(
                                    distVarName.keys()).strip().split(','):
                                self.inputInfo['distributionName'][
                                    subVar] = self.toBeSampled[varName]
                                self.inputInfo['distributionType'][
                                    subVar] = self.distDict[varName].type
                        ndCoordinate = np.zeros(
                            len(self.distributions2variablesMapping[distName]))
                        dxs = np.zeros(
                            len(self.distributions2variablesMapping[distName]))
                        centerCoordinate = np.zeros(
                            len(self.distributions2variablesMapping[distName]))
                        positionList = self.distributions2variablesIndexList[
                            distName]
                        sorted_mapping = sorted([
                            (utils.first(var.keys()).strip(),
                             utils.first(var.values())) for var in
                            self.distributions2variablesMapping[distName]
                        ])
                        for var in sorted_mapping:
                            # if the varName is a comma separated list of strings the user wants to sample the comma separated variables with the same sampled value => link the value to all comma separated variables
                            variable, position = var
                            upper = self.gridEntity.returnShiftedCoordinate(
                                self.gridEntity.returnIteratorIndexes(), {
                                    variable:
                                    self.sampledCoordinate[self.counter -
                                                           1][varCount] + 1
                                })[variable]
                            lower = self.gridEntity.returnShiftedCoordinate(
                                self.gridEntity.returnIteratorIndexes(), {
                                    variable:
                                    self.sampledCoordinate[self.counter -
                                                           1][varCount]
                                })[variable]
                            varCount += 1
                            if self.gridInfo[variable] == 'CDF':
                                coordinate = lower + (
                                    upper - lower) * randomUtils.random()
                                ndCoordinate[positionList.index(
                                    position)] = self.distDict[
                                        variable].inverseMarginalDistribution(
                                            coordinate, variable)
                                dxs[positionList.index(
                                    position
                                )] = self.distDict[
                                    variable].inverseMarginalDistribution(
                                        max(upper, lower), variable
                                    ) - self.distDict[
                                        variable].inverseMarginalDistribution(
                                            min(upper, lower), variable)
                                centerCoordinate[positionList.index(
                                    position)] = (self.distDict[variable].
                                                  inverseMarginalDistribution(
                                                      upper, variable) +
                                                  self.distDict[variable].
                                                  inverseMarginalDistribution(
                                                      lower, variable)) / 2.0
                                for subVar in variable.strip().split(','):
                                    self.values[subVar] = ndCoordinate[
                                        positionList.index(position)]
                                    self.inputInfo['upper'][
                                        subVar] = self.distDict[
                                            variable].inverseMarginalDistribution(
                                                max(upper, lower), variable)
                                    self.inputInfo['lower'][
                                        subVar] = self.distDict[
                                            variable].inverseMarginalDistribution(
                                                min(upper, lower), variable)
                            elif self.gridInfo[variable] == 'value':
                                dxs[positionList.index(position)] = max(
                                    upper, lower) - min(upper, lower)
                                centerCoordinate[positionList.index(
                                    position)] = (upper + lower) / 2.0
                                coordinateCdf = self.distDict[
                                    variable].marginalCdf(lower) + (
                                        self.distDict[variable].marginalCdf(
                                            upper) -
                                        self.distDict[variable].marginalCdf(
                                            lower)) * randomUtils.random()
                                coordinate = self.distDict[
                                    variable].inverseMarginalDistribution(
                                        coordinateCdf, variable)
                                ndCoordinate[positionList.index(
                                    position)] = coordinate
                                for subVar in variable.strip().split(','):
                                    self.values[subVar] = coordinate
                                    self.inputInfo['upper'][subVar] = max(
                                        upper, lower)
                                    self.inputInfo['lower'][subVar] = min(
                                        upper, lower)
                        gridsWeight = self.distDict[varName].cellIntegral(
                            centerCoordinate, dxs)
                        self.inputInfo['SampledVarsPb'][
                            varName] = self.distDict[varName].pdf(ndCoordinate)
                    else:
                        if self.gridInfo[varName] == 'CDF':
                            upper = self.gridEntity.returnShiftedCoordinate(
                                self.gridEntity.returnIteratorIndexes(), {
                                    varName:
                                    self.sampledCoordinate[self.counter -
                                                           1][varCount] + 1
                                })[varName]
                            lower = self.gridEntity.returnShiftedCoordinate(
                                self.gridEntity.returnIteratorIndexes(), {
                                    varName:
                                    self.sampledCoordinate[self.counter -
                                                           1][varCount]
                                })[varName]
                            varCount += 1
                            coordinate = lower + (
                                upper - lower) * randomUtils.random()
                            gridCoordinate, distName = self.distDict[
                                varName].ppf(
                                    coordinate
                                ), self.variables2distributionsMapping[
                                    varName]['name']
                            for distVarName in self.distributions2variablesMapping[
                                    distName]:
                                for subVar in utils.first(
                                        distVarName.keys()).strip().split(','):
                                    self.inputInfo['distributionName'][
                                        subVar], self.inputInfo[
                                            'distributionType'][
                                                subVar], self.values[
                                                    subVar] = self.toBeSampled[
                                                        varName], self.distDict[
                                                            varName].type, np.atleast_1d(
                                                                gridCoordinate
                                                            )[utils.first(
                                                                distVarName.
                                                                values()) - 1]
                            # coordinate stores the cdf values, we need to compute the pdf for SampledVarsPb
                            self.inputInfo['SampledVarsPb'][
                                varName] = self.distDict[varName].pdf(
                                    np.atleast_1d(gridCoordinate).tolist())
                            gridsWeight = max(upper, lower) - min(upper, lower)
                        else:
                            self.raiseAnError(
                                IOError,
                                "Since the globalGrid is defined, the Stratified Sampler is only working when the sampling is performed on a grid on a CDF. However, the user specifies the grid on "
                                + self.gridInfo[varName])
                    weight *= gridsWeight
                    self.inputInfo['ProbabilityWeight-' +
                                   distName] = gridsWeight
            if (
                    "<distribution>" in varName
            ) or self.variables2distributionsMapping[varName]['totDim'] == 1:
                # 1D variable
                # if the varName is a comma separated list of strings the user wants to sample the comma separated variables with the same sampled value => link the value to all comma separated variables
                upper = self.gridEntity.returnShiftedCoordinate(
                    self.gridEntity.returnIteratorIndexes(), {
                        varName:
                        self.sampledCoordinate[self.counter - 1][varCount] + 1
                    })[varName]
                lower = self.gridEntity.returnShiftedCoordinate(
                    self.gridEntity.returnIteratorIndexes(), {
                        varName:
                        self.sampledCoordinate[self.counter - 1][varCount]
                    })[varName]
                varCount += 1
                if self.gridInfo[varName] == 'CDF':
                    coordinate = lower + (upper - lower) * randomUtils.random()
                    ppfValue = self.distDict[varName].ppf(coordinate)
                    ppfLower = self.distDict[varName].ppf(min(upper, lower))
                    ppfUpper = self.distDict[varName].ppf(max(upper, lower))
                    gridWeight = self.distDict[varName].cdf(
                        ppfUpper) - self.distDict[varName].cdf(ppfLower)
                    self.inputInfo['SampledVarsPb'][varName] = self.distDict[
                        varName].pdf(ppfValue)
                elif self.gridInfo[varName] == 'value':
                    coordinateCdf = self.distDict[varName].cdf(
                        min(upper, lower)) + (self.distDict[varName].cdf(
                            max(upper, lower)) - self.distDict[varName].cdf(
                                min(upper, lower))) * randomUtils.random()
                    if coordinateCdf == 0.0:
                        self.raiseAWarning(
                            IOError,
                            "The grid lower bound and upper bound in value will generate ZERO cdf value!!!"
                        )
                    coordinate = self.distDict[varName].ppf(coordinateCdf)
                    gridWeight = self.distDict[varName].cdf(max(
                        upper, lower)) - self.distDict[varName].cdf(
                            min(upper, lower))
                    self.inputInfo['SampledVarsPb'][varName] = self.distDict[
                        varName].pdf(coordinate)
                # compute the weight and ProbabilityWeight-varName
                weight *= gridWeight
                self.inputInfo['ProbabilityWeight-' + varName] = gridWeight
                for subVar in varName.strip().split(','):
                    self.inputInfo['distributionName'][
                        subVar] = self.toBeSampled[varName]
                    self.inputInfo['distributionType'][subVar] = self.distDict[
                        varName].type
                    if self.gridInfo[varName] == 'CDF':
                        self.values[subVar] = ppfValue
                        self.inputInfo['upper'][subVar] = ppfUpper
                        self.inputInfo['lower'][subVar] = ppfLower
                    elif self.gridInfo[varName] == 'value':
                        self.values[subVar] = coordinate
                        self.inputInfo['upper'][subVar] = max(upper, lower)
                        self.inputInfo['lower'][subVar] = min(upper, lower)

        self.inputInfo['PointProbability'] = reduce(
            mul, self.inputInfo['SampledVarsPb'].values())
        self.inputInfo['ProbabilityWeight'] = weight
        self.inputInfo['SamplerType'] = 'Stratified'
Exemplo n.º 17
0
### BEGIN TESTS
# NOTE that due to seeding, this test relies HEAVILY on not changing the orders of calls to randomUtils!
# Reseed at the beginning of sections and add new tests to the end of sections.

# set the stochastic environment TODO check both someday?
# cannot pass the numpy as the stochasticEnv
randomUtils.stochasticEnv = 'crow'

eng = randomUtils.newRNG()
# randomSeed(), setting the random seed
randomUtils.randomSeed(42, engine=None)
randomUtils.randomSeed(42, engine=eng)
# check that seed is set
checkAnswer('First float from first seed for engine not provided',
            randomUtils.random(engine=None), 0.374540118847)
checkAnswer('First float from first seed for local engine provided',
            randomUtils.random(engine=eng), 0.374540118847)

# check resetting seed
randomUtils.randomSeed(
    12345,
    engine=None)  #next float would be 0.95071430641 if seed didn't change
randomUtils.randomSeed(
    12345,
    engine=eng)  #next float would be 0.95071430641 if seed didn't change
checkAnswer('First float from second seed for engine not provided',
            randomUtils.random(engine=None), 0.929616092817)
checkAnswer('First float from second seed for local engine provided',
            randomUtils.random(engine=eng), 0.929616092817)
Exemplo n.º 18
0
    def localGenerateInput(self, model, myInput):
        """
      Function to select the next most informative point for refining the limit
      surface search.
      After this method is called, the self.inputInfo should be ready to be sent
      to the model
      @ In, model, model instance, an instance of a model
      @ In, myInput, list, a list of the original needed inputs for the model (e.g. list of files, etc.)
      @ Out, None
    """
        # create values dictionary
        weight = 1.0
        for key in self.distDict:
            # check if the key is a comma separated list of strings
            # in this case, the user wants to sample the comma separated variables with the same sampled value => link the value to all comma separated variables

            dim = self.variables2distributionsMapping[key]['dim']
            totDim = self.variables2distributionsMapping[key]['totDim']
            dist = self.variables2distributionsMapping[key]['name']
            reducedDim = self.variables2distributionsMapping[key]['reducedDim']
            weight = 1.0
            if totDim == 1:
                for var in self.distributions2variablesMapping[dist]:
                    varID = utils.first(var.keys())
                    if self.samplingType == 'uniform':
                        distData = self.distDict[key].getCrowDistDict()
                        if ('xMin' not in distData.keys()) or (
                                'xMax' not in distData.keys()):
                            self.raiseAnError(
                                IOError,
                                "In the Monte-Carlo sampler a uniform sampling type has been chosen; however, one or more distributions have not specified either the lowerBound or the upperBound"
                            )
                        lower = distData['xMin']
                        upper = distData['xMax']
                        rvsnum = lower + (upper - lower) * randomUtils.random()
                        epsilon = (upper - lower) / self.limit
                        midPlusCDF = self.distDict[key].cdf(rvsnum + epsilon)
                        midMinusCDF = self.distDict[key].cdf(rvsnum - epsilon)
                        weight *= midPlusCDF - midMinusCDF
                    else:
                        rvsnum = self.distDict[key].rvs()
                    self.inputInfo['SampledVarsPb'][key] = self.distDict[
                        key].pdf(rvsnum)
                    for kkey in varID.strip().split(','):
                        self.values[kkey] = np.atleast_1d(rvsnum)[0]
                    self.inputInfo['ProbabilityWeight-' + varID] = 1.
            elif totDim > 1:
                if reducedDim == 1:
                    if self.samplingType is None:
                        rvsnum = self.distDict[key].rvs()
                        coordinate = np.atleast_1d(rvsnum).tolist()
                    else:
                        coordinate = np.zeros(totDim)
                        for i in range(totDim):
                            lower = self.distDict[key].returnLowerBound(i)
                            upper = self.distDict[key].returnUpperBound(i)
                            coordinate[i] = lower + (
                                upper - lower) * randomUtils.random()
                    if reducedDim > len(coordinate):
                        self.raiseAnError(
                            IOError,
                            "The dimension defined for variables drew from the multivariate normal distribution is exceeded by the dimension used in Distribution (MultivariateNormal) "
                        )
                    probabilityValue = self.distDict[key].pdf(coordinate)
                    self.inputInfo['SampledVarsPb'][key] = probabilityValue
                    for var in self.distributions2variablesMapping[dist]:
                        varID = utils.first(var.keys())
                        varDim = var[varID]
                        for kkey in varID.strip().split(','):
                            self.values[kkey] = np.atleast_1d(rvsnum)[varDim -
                                                                      1]
                    self.inputInfo['ProbabilityWeight-' + dist] = 1.
            else:
                self.raiseAnError(
                    IOError,
                    "Total dimension for given distribution should be >= 1")

        if len(self.inputInfo['SampledVarsPb'].keys()) > 0:
            self.inputInfo['PointProbability'] = reduce(
                mul, self.inputInfo['SampledVarsPb'].values())
        else:
            self.inputInfo['PointProbability'] = 1.0
        if self.samplingType == 'uniform':
            self.inputInfo['ProbabilityWeight'] = weight
        else:
            self.inputInfo[
                'ProbabilityWeight'] = 1.0  #MC weight is 1/N => weight is one
        self.inputInfo['SamplerType'] = 'MonteCarlo'
Exemplo n.º 19
0
    def initialize(self, externalSeeding=None, solutionExport=None):
        """
      This function should be called every time a clean optimizer is needed. Called before takeAstep in <Step>
      @ In, externalSeeding, int, optional, external seed
      @ In, solutionExport, DataObject, optional, a PointSet to hold the solution
      @ Out, None
    """
        for entry in self.assemblerDict.get('Preconditioner', []):
            cls, typ, name, model = entry
            if cls != 'Models' or typ != 'ExternalModel':
                self.raiseAnError(
                    IOError,
                    'Currently only "ExternalModel" models can be used as preconditioners! Got "{}.{}" for "{}".'
                    .format(cls, typ, name))
            self.preconditioners[name] = model
            model.initialize({}, [])

        for entry in self.assemblerDict.get('Sampler', []):
            cls, typ, name, sampler = entry
            forwardSampler = False
            for baseClass in sampler.__class__.__bases__:
                if "ForwardSampler" in baseClass.__name__:
                    forwardSampler = True
                    break
            if not forwardSampler:
                self.raiseAnError(
                    IOError,
                    'Only "ForwardSampler"s (e.g. MonteCarlo, Grid, etc.) can be used for initializing the trajectories in the Optimizer! Got "{}.{}" for "{}".'
                    .format(cls, typ, name))
            self.initializationSampler = sampler
            initDict = {}
            for entity in ['Distributions', 'Functions', 'DataObjects']:
                initDict[entity] = dict(
                    (entry[2], entry[3])
                    for entry in self.assemblerDict.get(entity, []))
            self.initializationSampler._localGenerateAssembler(initDict)
            for key in self.initializationSampler.getInitParams().keys():
                if key.startswith("sampled variable:"):
                    var = key.replace("sampled variable:", "").strip()
                    # check if the sampled variables are among the optimization parameters
                    if var not in self.getOptVars():
                        self.raiseAnError(
                            IOError, 'The variable "' + var +
                            '" sampled by the initialization Sampler "' +
                            self.initializationSampler.name +
                            '" is not among the optimization parameters!')
                    # check if the sampled variables have been already initialized in the optimizer (i.e. <initial>)
                    if self.optVarsInitialized[var]:
                        self.raiseAnError(
                            IOError, 'The variable "' + var +
                            '" sampled by the initialization Sampler "' +
                            self.initializationSampler.name +
                            '" has been already initialized in the Optimizer block. Remove <initial> XML node in Optimizer or the <variable> XML node in the Sampler!'
                        )
            # generate the initial coordinates by the sampler and check if they are inside the boundaries
            self.initializationSampler.initialize(externalSeeding)
            # check the number of trajectories (i.e. self.initializationSample.limit in the Sampler)
            currentNumberTrajectories = len(self.optTraj)
            if currentNumberTrajectories > 1:
                if currentNumberTrajectories != self.initializationSampler.limit:
                    self.raiseAnError(
                        IOError,
                        "The number of samples generated by the initialization Sampler are different "
                        +
                        "than the one inputted in the Optimizer (from the variables where the <initial> XML block has been inputted)"
                    )
            else:
                self.optTraj = list(range(self.initializationSampler.limit))
                for varName in self.optVarsInit['initial'].keys():
                    self.optVarsInit['initial'][varName] = dict.fromkeys(
                        self.optTraj, self.optVarsInit['initial'][varName][0])
            while self.initializationSampler.amIreadyToProvideAnInput():
                self.initializationSampler.localGenerateInput(None, None)
                self.initializationSampler.inputInfo[
                    'prefix'] = self.initializationSampler.counter
                sampledVars = self.initializationSampler.inputInfo[
                    'SampledVars']
                for varName, value in sampledVars.items():
                    self.optVarsInit['initial'][varName][
                        self.initializationSampler.counter] = np.atleast_1d(
                            value)
                self.initializationSampler.counter += 1

        # NOTE: counter['varsUpdate'] needs to be set AFTER self.optTraj length is set by the sampler (if used exclusively)
        self.counter['mdlEval'] = 0
        self.counter['varsUpdate'] = [0] * len(self.optTraj)
        self.optTrajLive = copy.deepcopy(self.optTraj)

        self.mdlEvalHist = self.assemblerDict['TargetEvaluation'][0][3]
        # check if the TargetEvaluation feature and target spaces are consistent
        ins = self.mdlEvalHist.getVars("input")
        outs = self.mdlEvalHist.getVars("output")
        for varName in self.fullOptVars:
            if varName not in ins:
                self.raiseAnError(
                    RuntimeError, "the optimization variable " + varName +
                    " is not contained in the TargetEvaluation object " +
                    self.mdlEvalHist.name)
        if self.objVar not in outs:
            self.raiseAnError(
                RuntimeError,
                "the optimization objective variable " + self.objVar +
                " is not contained in the TargetEvaluation object " +
                self.mdlEvalHist.name)
        self.objSearchingROM = SupervisedLearning.returnInstance(
            'SciKitLearn', self, **{
                'SKLtype': 'neighbors|KNeighborsRegressor',
                'Features': ','.join(list(self.fullOptVars)),
                'Target': self.objVar,
                'n_neighbors': 1,
                'weights': 'distance'
            })
        self.solutionExport = solutionExport
        if self.solutionExport is None:
            self.raiseAnError(
                IOError,
                'The results of optimization cannot be obtained without a SolutionExport defined in the Step!'
            )

        if type(solutionExport).__name__ not in ["PointSet", "DataSet"]:
            self.raiseAnError(IOError,'solutionExport type must be a PointSet or DataSet. Got '+\
                                       type(solutionExport).__name__+ '!')

        if 'Function' in self.assemblerDict.keys():
            self.constraintFunction = self.assemblerDict['Function'][0][3]
            if 'constrain' not in self.constraintFunction.availableMethods():
                self.raiseAnError(
                    IOError,
                    'the function provided to define the constraints must have an implemented method called "constrain"'
                )

        # initialize dictionary entries
        # TODO a bunch of the gradient-level trajectory initializations should be moved here.
        for traj in self.optTraj:
            self.optVars[traj] = self.getOptVars()
            self.submissionQueue[traj] = deque()

        #check initial point array consistency
        rightLen = len(self.optTraj)  #the hypothetical correct length
        for var in self.getOptVars():
            haveLen = len(self.optVarsInit['initial'][var])
            if haveLen != rightLen:
                self.raiseAnError(
                    RuntimeError,
                    'The number of trajectories for variable "{}" is incorrect!  Got {} but expected {}!  Check the <initial> block.'
                    .format(var, haveLen, rightLen))

        # check the constraint here to check if the initial values violate it
        varK = {}
        for trajInd in self.optTraj:
            for varName in self.getOptVars():
                varK[varName] = self.optVarsInit['initial'][varName][trajInd]
            satisfied, _ = self.checkConstraint(varK)
            if not satisfied:
                # get a random value between the the lower and upper bounds
                self.raiseAWarning(
                    "the initial values specified for trajectory " +
                    str(trajInd) +
                    " do not satify the contraints. Picking random ones!")
                randomGuessesCnt = 0
                while not satisfied and randomGuessesCnt < self.constraintHandlingPara[
                        'innerLoopLimit']:
                    for varName in self.getOptVars():
                        varK[varName] = self.optVarsInit['lowerBound'][
                            varName] + randomUtils.random(
                            ) * self.optVarsInit['ranges'][varName]
                        self.optVarsInit['initial'][varName][trajInd] = varK[
                            varName]
                    satisfied, _ = self.checkConstraint(varK)
                if not satisfied:
                    self.raiseAnError(
                        Exception,
                        "It was not possible to find any initial values that could satisfy the constraints for trajectory "
                        + str(trajInd))

        # extend multivalue variables (aka vector variables, or variables with "shape")
        ## TODO someday take array of initial values from a DataSet
        for var, shape in self.variableShapes.items():
            if np.prod(shape) > 1:
                for traj in self.optTraj:
                    baseVal = self.optVarsInit['initial'][var][traj]
                    newVal = np.ones(shape) * baseVal
                    self.optVarsInit['initial'][var][traj] = newVal

        if self.initSeed is not None:
            randomUtils.randomSeed(self.initSeed)

        self.localInitialize(solutionExport=solutionExport)
Exemplo n.º 20
0
        if updateResults:
            results["pass"] += 1
        return True


### BEGIN TESTS
# NOTE that due to seeding, this test relies HEAVILY on not changing the orders of calls to randomUtils!
# Reseed at the beginning of sections and add new tests to the end of sections.

# set the stochastic environment TODO check both someday?
randomUtils.stochasticEnv = 'crow'

# randomSeed(), setting the random seed
randomUtils.randomSeed(42)
# check that seed is set
checkAnswer('First float from first seed', randomUtils.random(),
            0.374540118847)
# check resetting seed
randomUtils.randomSeed(
    12345)  #next float would be 0.95071430641 if seed didn't change
checkAnswer('First float from second seed', randomUtils.random(),
            0.929616092817)

### random(), sampling on [0,1]
## single sampling
randomUtils.randomSeed(42)
vals = np.array([randomUtils.random() for _ in range(int(1e5))])
mean = np.average(vals)
stdv = np.std(vals)
checkAnswer('mean of 1e5 single samples', mean, 0.5, tol=1e-3)
checkAnswer('stdv of 1e5 single samples', stdv, np.sqrt(1. / 12.), tol=1e-3)
Exemplo n.º 21
0
  def localGenerateInput(self,model,oldInput):
    """
      Function to select the next most informative point for refining the limit
      surface search.
      After this method is called, the self.inputInfo should be ready to be sent
      to the model
      @ In, model, model instance, an instance of a model
      @ In, oldInput, list, a list of the original needed inputs for the model (e.g. list of files, etc.)
      @ Out, None
    """
    #  Alternatively, though I don't think we do this yet:
    #  compute the direction normal to the surface, compute the derivative
    #  normal to the surface of the probability, check the points where the
    #  derivative probability is the lowest

    # create values dictionary
    self.inputInfo['distributionName'] = {} #Used to determine which distribution to change if needed.
    self.inputInfo['distributionType'] = {} #Used to determine which distribution type is used
    self.raiseADebug('generating input')
    varSet=False

    # DM: This sequence gets used repetitively, so I am promoting it to its own
    #  variable
    axisNames = [key.replace('<distribution>','') for key in self.axisName]

    if self.surfPoint is not None and len(self.surfPoint) > 0:
      if self.batchStrategy == 'none':
        self.__scoreCandidates()
        maxDistance, maxGridId, maxId =  0.0, "", 0
        for key, value in sorted(self.invPointPersistence.items()):
          if key != self.exceptionGrid and self.surfPoint[key] is not None:
            localMax = np.max(self.scores[key])
            if localMax > maxDistance:
              maxDistance, maxGridId, maxId  = localMax, key,  np.argmax(self.scores[key])
        if maxDistance > 0.0:
          for varIndex, _ in enumerate([key.replace('<distribution>','') for key in self.axisName]):
            self.values[self.axisName[varIndex]] = copy.copy(float(self.surfPoint[maxGridId][maxId,varIndex]))
            self.inputInfo['SampledVarsPb'][self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
            self.inputInfo['ProbabilityWeight-'+self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
          varSet=True
        else:
          self.raiseADebug('Maximum score is 0.0')
      elif self.batchStrategy.startswith('max'):
        ########################################################################
        ## Initialize the queue with as many points as requested or as many as
        ## possible
        if len(self.toProcess) == 0:
          self.__scoreCandidates()
          edges = []

          flattenedSurfPoints = list()
          flattenedBandPoints = list()
          flattenedScores     = list()
          for key in self.bandIndices.keys():
            flattenedSurfPoints = flattenedSurfPoints + list(self.surfPoint[key])
            flattenedScores = flattenedScores + list(self.scores[key])
            flattenedBandPoints = flattenedBandPoints + self.listSurfPoint[key] + self.bandIndices[key]

          flattenedSurfPoints = np.array(flattenedSurfPoints)
          for i,iCoords in enumerate(flattenedBandPoints):
            for j in range(i+1, len(flattenedBandPoints)):
              jCoords = flattenedBandPoints[j]
              ijValidNeighbors = True
              for d in range(len(jCoords)):
                if abs(iCoords[d] - jCoords[d]) > 1:
                  ijValidNeighbors = False
                  break
              if ijValidNeighbors:
                edges.append((i,j))
                edges.append((j,i))

          names = axisNames[:] #make copy
          names.append('score')
          amsc = AMSC_Object(X=flattenedSurfPoints, Y=flattenedScores,
                             w=None, names=names, graph='none',
                             gradient='steepest', normalization='feature',
                             persistence='difference', edges=edges, debug=False)
          plevel = self.simplification*(max(flattenedScores)-min(flattenedScores))
          partitions = amsc.StableManifolds(plevel)
          mergeSequence = amsc.GetMergeSequence()
          maxIdxs = list(set(partitions.keys()))

          thresholdLevel = self.threshold*(max(flattenedScores)-min(flattenedScores))+min(flattenedScores)
          # Sort the maxima based on decreasing function value, thus the top
          # candidate is the first element.
          if self.batchStrategy.endswith('V'):
            sortedMaxima = sorted(maxIdxs, key=lambda idx: flattenedScores[idx], reverse=True)
          else:
          # Sort the maxima based on decreasing persistence value, thus the top
          # candidate is the first element.
            sortedMaxima = sorted(maxIdxs, key=lambda idx: mergeSequence[idx][1], reverse=True)
          B = min(self.maxBatchSize,len(sortedMaxima))
          for idx in sortedMaxima[0:B]:
            if flattenedScores[idx] >= thresholdLevel:
              self.toProcess.append(flattenedSurfPoints[idx,:])
          if len(self.toProcess) == 0:
            self.toProcess.append(flattenedSurfPoints[np.argmax(flattenedScores),:])
        ########################################################################
        ## Select one sample
        selectedPoint = self.toProcess.pop()
        for varIndex, varName in enumerate(axisNames):
          self.values[self.axisName[varIndex]] = float(selectedPoint[varIndex])
          self.inputInfo['SampledVarsPb'][self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
          self.inputInfo['ProbabilityWeight-'+self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
        varSet=True
      elif self.batchStrategy == 'naive':
        ########################################################################
        ## Initialize the queue with as many points as requested or as many as
        ## possible
        if len(self.toProcess) == 0:
          self.__scoreCandidates()
          sortedIndices = sorted(range(len(self.scores)), key=lambda k: self.scores[k],reverse=True)
          B = min(self.maxBatchSize,len(sortedIndices))
          for idx in sortedIndices[0:B]:
            self.toProcess.append(self.surfPoint[idx,:])
          if len(self.toProcess) == 0:
            self.toProcess.append(self.surfPoint[np.argmax(self.scores),:])
        ########################################################################
        ## Select one sample
        selectedPoint = self.toProcess.pop()
        for varIndex, varName in enumerate(axisNames):
          self.values[self.axisName[varIndex]] = float(selectedPoint[varIndex])
          self.inputInfo['SampledVarsPb'][self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
          self.inputInfo['ProbabilityWeight-'+self.axisName[varIndex]] = self.distDict[self.axisName[varIndex]].pdf(self.values[self.axisName[varIndex]])
        varSet=True

    if not varSet:
      #here we are still generating the batch
      for key in sorted(self.distDict.keys()):
        if self.toleranceWeight=='cdf':
          self.values[key]                       = self.distDict[key].ppf(float(randomUtils.random()))
        else:
          self.values[key]                       = self.distDict[key].lowerBound+(self.distDict[key].upperBound-self.distDict[key].lowerBound)*float(randomUtils.random())
        self.inputInfo['distributionName'][key]  = self.toBeSampled[key]
        self.inputInfo['distributionType'][key]  = self.distDict[key].type
        self.inputInfo['SampledVarsPb'   ][key]  = self.distDict[key].pdf(self.values[key])
        self.inputInfo['ProbabilityWeight-'+key] = self.distDict[key].pdf(self.values[key])
        self.addMetaKeys(['ProbabilityWeight-'+key])
    self.inputInfo['PointProbability'    ]      = reduce(mul, self.inputInfo['SampledVarsPb'].values())
    # the probability weight here is not used, the post processor is going to recreate the grid associated and use a ROM for the probability evaluation
    self.inputInfo['ProbabilityWeight']         = self.inputInfo['PointProbability']
    self.hangingPoints                          = np.vstack((self.hangingPoints,copy.copy(np.array([self.values[axis] for axis in self.axisName]))))
    self.raiseADebug('At counter '+str(self.counter)+' the generated sampled variables are: '+str(self.values))
    self.inputInfo['SamplerType'] = 'LimitSurfaceSearch'
    self.inputInfo['subGridTol' ] = self.subGridTol
Exemplo n.º 22
0
  else:
    if updateResults:
      results["pass"] += 1
    return True

### BEGIN TESTS
# NOTE that due to seeding, this test relies HEAVILY on not changing the orders of calls to randomUtils!
# Reseed at the beginning of sections and add new tests to the end of sections.

# set the stochastic environment TODO check both someday?
randomUtils.stochasticEnv = 'crow'

# randomSeed(), setting the random seed
randomUtils.randomSeed(42)
# check that seed is set
checkAnswer('First float from first seed',randomUtils.random(),0.374540118847)
# check resetting seed
randomUtils.randomSeed(12345) #next float would be 0.95071430641 if seed didn't change
checkAnswer('First float from second seed',randomUtils.random(),0.929616092817)

### random(), sampling on [0,1]
## single sampling
randomUtils.randomSeed(42)
vals = np.array([randomUtils.random() for _ in range(int(1e5))])
mean = np.average(vals)
stdv = np.std(vals)
checkAnswer('mean of 1e5 single samples',mean,0.5, tol=1e-3)
checkAnswer('stdv of 1e5 single samples',stdv,np.sqrt(1./12.), tol=1e-3)
## 1d batch sampling
randomUtils.randomSeed(42)
vals = randomUtils.random(1e5)