Пример #1
0
# s. t. I_3 + A0*x0 + A1*x1 >= 0

c = array([[1], [1]])
A0 = array([[1,  0,  0],
             [0, -1,  0],
             [0,  0, -1]])
A1 = array([[0, 1, 0],
             [1, 0, 1],
             [0, 1, 0]])
# starting point 
startPoint = array([[0], [0]])

# create the solver object
problem = SDPSolver(c, [[eye(3), A0, A1]])

# enable graphs
problem.setDrawPlot(True)

# enable informative output
problem.setPrintOutput(True)

# enable bounding into ball with radius 1
#problem.bound(1)

# solve!
x = problem.solve(startPoint, problem.dampedNewton)
print(x)

# print eigenvalues
#print(problem.eigenvalues())
Пример #2
0
class POPSolver:
  """
  Class providing POP (Polynomial Optimization Problem) Solver.

  Solves problem in this form:
    min f(x)
    s.t. g(x) >= 0

  by Pavel Trutman, [email protected]
  """


  def __init__(self, f, g, d):
    """
    Initialization of the POP problem.

    Args:
      f (dictionary: tuple => int): representation of the objective function f(x)
      g (dictionary: tuple => int): representation of the constraining function g(x)
      d (int): degree of the relaxation
    """

    # get number of variables
    key = list(f.keys())[0]
    self.n = len(key)
    self.d = d

    # disable output
    logging.basicConfig(stream = sys.stdout, format = '%(message)s')
    self.logStdout = logging.getLogger()

    # generate all variables up to degree 2*d
    allVar = self.generateVariablesUpDegree(2*self.d)

    # collect all variables used
    varUsed = allVar

    # generate moment matrix and localizing matrix
    self.MM = self.momentMatrix(self.d, varUsed)
    self.LM = self.localizingMatrix(self.d - 1, varUsed, g)

    # generate objective function for SDP
    self.c = zeros((len(varUsed) - 1, 1))
    for variable in range(1, len(varUsed)):
      self.c[variable - 1, 0] = f.get(varUsed[variable], 0)

    # initialize SDP Solver
    self.SDP = SDPSolver(self.c, [self.MM, self.LM])


  def solve(self, startPoint):
    """
    Solves a POP problem.

    Args:
      startPoint (Matrix): some feasible point of the SDP problem

    Returns:
      Matrix: solution of the problem
    """

    # solve the SDP porblem
    y = self.SDP.solve(startPoint, self.SDP.dampedNewton)

    # extract solutions of the POP problem
    x = y[0:self.n, :]
    return x


  def setPrintOutput(self, printOutput):
    """
    Enables or disables printing of the computation state.

    Args:
      printOuput (bool): True - enables the output, False - disables the output

    Returns:
      None
    """

    self.SDP.setPrintOutput(printOutput)
    if printOutput:
      self.logStdout.setLevel(logging.INFO)
    else:
      self.logStdout.setLevel(logging.WARNING)


  def momentMatrix(self, d, varUsed):
    """
    Constructs moment matrix.

    Args:
      d (int): degree of the relaxation
      varUsed (list of tuples): all variables that are used

    Returns:
      list: list of moment matrices
    """

    varUpD = self.generateVariablesUpDegree(d)
    varUsedNum = len(varUsed)
    dimM = len(varUpD)

    MM = [zeros((dimM, dimM)) for i in range(0, varUsedNum)]

    for i in range(0, dimM):
      for j in range(i, dimM):
        # sum up the degrees
        varCur = tuple(sum(t) for t in zip(varUpD[i], varUpD[j]))
        # find this variable amongs used vars
        index = [k for k in range(0, varUsedNum) if varUsed[k] == varCur]
        if len(index) > 0:
          pos = index[0]
          MM[pos][i, j] = 1
          MM[pos][j, i] = 1
    return MM


  def localizingMatrix(self, d, varUsed, g):
    """
    Constructs localizing matrix.

    Args:
      d (int): degree of the relaxation
      varUsed (list of tuples): all variables that are used
      g (dictionary: tuple => int): representation of the constraining function g(x)

    Returns:
      list: list of localizing matrices
    """

    varUpD = self.generateVariablesUpDegree(d)
    varUsedNum = len(varUsed)
    dimM = len(varUpD)
    LM = [zeros((dimM, dimM)) for i in range(0, varUsedNum)]

    for mon, coef in g.items():
      for i in range(0, dimM):
        for j in range(i, dimM):
          # sum up the degrees
          varCur = tuple(sum(t) for t in zip(varUpD[i], varUpD[j], mon))
          # find this variable amongs used vars
          index = [k for k in range(0, varUsedNum) if varUsed[k] == varCur]
          if len(index) > 0:
            pos = index[0]
            LM[pos][i, j] += coef
            if i != j:
              LM[pos][j, i] += coef
    return LM


  def generateVariablesDegree(self, d, n):
    """
    Generates whole set of variables of given degree.

    Args:
      d (int): degree of the variables
      n (int): number of unknowns

    Returns:
      list: list of all variables
    """

    # generate zero degree variables
    if d == 0:
      return [(0,)*n]

    # generrate one degree variables
    elif d == 1:
      variables = []
      for i in range(0, n):
        t = [0]*n
        t[i] = 1
        variables.append(tuple(t))
      return variables

    # there is only one unkown with the degree d
    elif n == 1:
      return [(d,)]

    # generate variables in general case
    else:
      variables = []
      for i in range(0, d + 1):
        innerVariables = self.generateVariablesDegree(d - i, n - 1)
        variables.extend([v + (i,) for v in innerVariables])
      return variables
  

  def generateVariablesUpDegree(self, d):
    """
    Generates whole set of variables up to given degree.

    Args:
      d (int): maximal degree of the variables

    Returns:
      list: list of variables
    """

    variables = []
    for i in range(0, d + 1):
      variables.extend(self.generateVariablesDegree(i, self.n))
    return variables


  def getFeasiblePoint(self, R):
    """Finds feasible point for SDP problem arisen from the POP problem.

    Args:
      R (int): a radius of a ball from which x points are choosen

    Returns:
      Matrix: feasible point for the SDP problem
    """

    N = comb(self.n + self.d, self.n)
    N = ceil(N*1.5 + 1)

    # generate all variable
    usedVars = self.generateVariablesUpDegree(2*self.d)[1:]

    y = zeros((len(usedVars), 1))
    i = 0

    # choose many points x to moment matrix have full rank
    while i < N:

      # select x from the ball with given radius
      x = uniform(-R, R, (self.n, 1))
      if norm(x) < R:
        
        # generate points y from it
        for alpha in range(0, len(usedVars)):
          yTemp = 1
          for j in range(0, self.n):
            yTemp *= x[j, 0]**usedVars[alpha][j]
          y[alpha, 0] += yTemp
        i += 1
    y = y / N

    return y