7.1 Synchronous Problem Submission

For the purpose of the tutorial we assume that the problem to be solved is read from a file, and the solutions will be saved to a file, i.e. we don’t go into the logic which sets up the problem and interprets the solution. See file formats for specifications of file formats.

We demonstrate synchronous optimization, see Sec. 5.1 (Synchronous Optimization). If using authentication, the access token will always be passed in the X-Mosek-Access-Token header. Assuming that an HTTP/HTTPS connection to the OptServer was established, we first submit a problem using submit. We can provide a name for easier identification of the problem in the Web GUI. The file format is passed in the Content-Type header.

Listing 7.1 Submit a problem.
            # POST problem data
            con.request('POST', '/api/submit?jobname=' + jobname, 
                                probdata, 
                                headers = dict(headers, **{"Content-Type": "application/x-mosek-{}".format(intype)}))
            resp = con.getresponse()
            check_status(resp)
            # Recover a token identifying the job
            token = resp.read().decode('ascii')      

The response contains a token used to identify the job in future requests. If no errors have occurred, we use solve to request running the solver for the given job token. When requesting the solution we set the Accept header to indicate expected solution format.

Listing 7.2 Starting the solver synchronously.
            # Use token to identify job
            con.request('GET', '/api/solve?token=' + token, 
                               headers = dict(headers, **{"Accept": outtype})) 
            resp = con.getresponse()

The request will return when optimization terminates. If there were no errors, the status codes are available in the headers and the solution in the body of the response.

Listing 7.3 Retrieving results.
            ## Retrieve status codes
            res = resp.getheader('X-Mosek-Res-Code',None) 
            trm = resp.getheader('X-Mosek-Trm-Code',None) 
            print('\tMOSEK response: %s' % res)
            print('\t      trm resp: %s' % trm)

            ## Retrieve the solution
            if resp.status == http.client.OK:
                print('Solution (as plain text):\n')
                print(resp.read().decode('ascii', errors = 'ignore'))

It is also possible to retrieve the log from the solver (log):

Listing 7.4 Retrieving optimization log.
            con.request('GET','/api/log?token=' + token, headers = headers)
            resp = con.getresponse()

The full example is shown below.

Listing 7.5 How to submit a job and solve the problem synchronously. Click here to download.
import http.client
import sys
try:
    import ssl
except:
    pass

# A debug method which prints out the HTTP(S) response 
# and exits in case of error
def check_status(resp):
    print('\tHTTPResponse: %s / %s' % (resp.status,resp.reason))
    for k,v in  resp.getheaders():
        print('\t%s: %s' % (k,v))
            
    if resp.status not in [http.client.OK, http.client.NO_CONTENT]:
        raise Exception('An error in connection')

# A helper method which opens a connection
def openConnection(host, port, useHttps):
    if useHttps:
        return http.client.HTTPSConnection(host, port, context=ssl._create_unverified_context())
    else:
        return http.client.HTTPConnection(host, port)

# Main code
if __name__ == '__main__':
    try:
        # OptServer address
        host, port = sys.argv[1], int(sys.argv[2])
        # Protocol (HTTP/HTTPS)
        useHttps = (sys.argv[3] == "HTTPS")
        # Name of file with input data
        probfile = sys.argv[4]        
        # Input and output file type
        intype, outtype = sys.argv[5], sys.argv[6]
        # Jobname (for demonstration)
        jobname = sys.argv[7] 
        # Authentication token
        headers = {}
        if len(sys.argv) == 9:
            headers = {"X-Mosek-Access-Token": sys.argv[8]}
    except:
        print("Usage  : python3 test_sync.py host            port  protocol  probfile intype outtype    jobname     [accestoken]")
        print("Example: python3 test_sync.py solve.mosek.com 38000 HTTPS     lo1.mps  mps    text/plain SimpleTask  ...")
        sys.exit(1)

    # Establish HTTP connection
    con = openConnection(host, port, useHttps)
    try:
        # Read input file
        with open(probfile,'rb') as probdata:
            ## Submit job
            print('POST /api/submit')
            # POST problem data
            con.request('POST', '/api/submit?jobname=' + jobname, 
                                probdata, 
                                headers = dict(headers, **{"Content-Type": "application/x-mosek-{}".format(intype)}))
            resp = con.getresponse()
            check_status(resp)
            # Recover a token identifying the job
            token = resp.read().decode('ascii')      
            
            ## Solve and wait for solution
            print('GET /api/solve')
            # Use token to identify job
            con.request('GET', '/api/solve?token=' + token, 
                               headers = dict(headers, **{"Accept": outtype})) 
            resp = con.getresponse()
            check_status(resp)

            ## Retrieve status codes
            res = resp.getheader('X-Mosek-Res-Code',None) 
            trm = resp.getheader('X-Mosek-Trm-Code',None) 
            print('\tMOSEK response: %s' % res)
            print('\t      trm resp: %s' % trm)

            ## Retrieve the solution
            if resp.status == http.client.OK:
                print('Solution (as plain text):\n')
                print(resp.read().decode('ascii', errors = 'ignore'))

            ## Obtain the solver log output
            print('GET /api/log')
            con.request('GET','/api/log?token=' + token, headers = headers)
            resp = con.getresponse()
            check_status(resp)
            if resp.status == http.client.OK:
                print('Solver log:\n')                
                print(resp.read().decode('utf-8', errors = 'ignore'))
    finally:
        con.close()

It is also possible to simplify the logic by using the submit+solve API to submit the problem and receive the solution in one request. The remaining protocol is similar to the above so we restrict to listing the full example without further explanations.

Listing 7.6 How to submit a job and solve the problem synchronously in one request. Click here to download.
import http.client
import sys
try:
    import ssl
except:
    pass

# A debug method which prints out the HTTP(S) response 
# and exits in case of error
def check_status(resp):
    print('\tHTTPResponse: %s / %s' % (resp.status,resp.reason))
    for k,v in  resp.getheaders():
        print('\t%s: %s' % (k,v))
            
    if resp.status not in [http.client.OK, http.client.NO_CONTENT]:
        raise Exception('An error in connection')

# A helper method which opens a connection
def openConnection(host, port, useHttps):
    if useHttps:
        return http.client.HTTPSConnection(host, port, context=ssl._create_unverified_context())
    else:
        return http.client.HTTPConnection(host, port)

# Main code
if __name__ == '__main__':
    try:
        # OptServer address
        host, port = sys.argv[1], int(sys.argv[2])
        # Protocol (HTTP/HTTPS)
        useHttps = (sys.argv[3] == "HTTPS")
        # Name of file with input data
        probfile = sys.argv[4]        
        # Input and output file type
        intype, outtype = sys.argv[5], sys.argv[6]
        # Jobname (for demonstration)
        jobname = sys.argv[7] 
        # Authentication token
        headers = {}
        if len(sys.argv) == 9:
            headers = {"X-Mosek-Access-Token": sys.argv[8]}
    except:
        print("Usage  : python3 test_simple_api.py host            port  protocol  probfile intype outtype    jobname     [accestoken]")
        print("Example: python3 test_simple_api.py solve.mosek.com 38000 HTTPS     lo1.mps  mps    text/plain SimpleTask  ...")
        sys.exit(1)

    # Establish HTTP connection
    con = openConnection(host, port, useHttps)
    try:
        # Read input file
        with open(probfile,'rb') as probdata:
            ## Submit job
            print('POST /api/submit+solve')
            # POST problem data
            con.request('POST', '/api/submit+solve?jobname=' + jobname, 
                                probdata, 
                                headers = dict(headers, **{"Content-Type": "application/x-mosek-{}".format(intype),
                                                           "Accept": outtype}))
            resp = con.getresponse()
            check_status(resp)
            # Recover a token identifying the job
            token = resp.getheader('X-Mosek-Token',None) 

            ## Retrieve status codes
            res = resp.getheader('X-Mosek-Res-Code',None) 
            trm = resp.getheader('X-Mosek-Trm-Code',None) 
            print('\tMOSEK response: %s' % res)
            print('\t      trm resp: %s' % trm)

            ## Retrieve the solution
            if resp.status == http.client.OK:
                print('Solution (as plain text):\n')
                print(resp.read().decode('ascii', errors = 'ignore'))

            ## Obtain the solver log output
            print('GET /api/log')
            con.request('GET','/api/log?token=' + token, headers = headers)
            resp = con.getresponse()
            check_status(resp)
            if resp.status == http.client.OK:
                print('Solver log:\n')                
                print(resp.read().decode('utf-8', errors = 'ignore'))
    finally:
        con.close()