##
#  Copyright : Copyright (c) MOSEK ApS, Denmark. All rights reserved.
#
#  File :      acc1.py
#
#  Purpose :   Tutorial example for affine conic constraints.
#              Models the problem:
#
#              maximize c^T x
#              subject to  sum(x) = 1
#                          gamma >= |Gx+h|_2
##
import sys, mosek

# Define a stream printer to grab output from MOSEK
def streamprinter(text):
    sys.stdout.write(text)
    sys.stdout.flush()

# Define problem data
n, k = 3, 2
# Only a symbolic constant
inf = 0.0

# Create a task
with mosek.Task() as task:
    # Attach a printer to the task
    task.set_Stream(mosek.streamtype.log, streamprinter)

    # Create n free variables
    task.appendvars(n)
    task.putvarboundsliceconst(0, n, mosek.boundkey.fr, -inf, inf)

    # Set up the objective
    c = [2, 3, -1]
    task.putobjsense(mosek.objsense.maximize)
    task.putclist(range(n), c)

    # One linear constraint - sum(x) = 1
    task.appendcons(1)
    task.putarow(0, range(n), [1]*n)
    task.putconbound(0, mosek.boundkey.fx, 1.0, 1.0)

    # Append empty AFE rows for affine expression storage
    task.appendafes(k + 1)

    # G matrix in sparse form
    Gsubi = [0, 0, 1, 1]
    Gsubj = [0, 1, 0, 2]
    Gval  = [1.5, 0.1, 0.3, 2.1]
    # Other data
    h     = [0, 0.1]
    gamma = 0.03

    # Construct F matrix in sparse form
    Fsubi = [i + 1 for i in Gsubi]   # G will be placed from row number 1 in F
    Fsubj = Gsubj
    Fval  = Gval

    # Fill in F storage
    task.putafefentrylist(Fsubi, Fsubj, Fval)

    # Fill in g storage
    task.putafeg(0, gamma)
    task.putafegslice(1, k+1, h)

    # Define a conic quadratic domain
    quadDom = task.appendquadraticconedomain(k + 1)

    # Create the ACC
    task.appendacc(quadDom,    # Domain index
                   range(k+1), # Indices of AFE rows [0,...,k]
                   None)       # Ignored

    task.writedata("acc1.ptf")
    # Solve and retrieve solution
    task.optimize()
    xx = task.getxx(mosek.soltype.itr)
    if task.getsolsta(mosek.soltype.itr) == mosek.solsta.optimal:
        print("Solution: {xx}".format(xx=list(xx)))

    # Demonstrate retrieving activity of ACC
    activity = task.evaluateacc(mosek.soltype.itr, 
                                0)     # ACC index          
    print("Activity of ACC:: {activity}".format(activity=list(activity)))

    # Demonstrate retrieving the dual of ACC
    doty = task.getaccdoty(mosek.soltype.itr, 
                           0)          # ACC index
    print("Dual of ACC:: {doty}".format(doty=list(doty)))

