TrishGillett/pysdpt3glue

View on GitHub
sdpt3glue/solve_locally.py

Summary

Maintainability
A
0 mins
Test Coverage
#
# sdpt3glue/solve_locally.py
#
# Copyright (c) 2016 Trish Gillett-Kawamoto
#
# This software is released under the MIT License.
#
# http://opensource.org/licenses/mit-license.php
#
'''
Methods that run code on a copy of Matlab or Octave installed on the user's
machine.
'''

import os
import os.path

import shutil
import subprocess
import tempfile


class SubprocessCallError(Exception):
    '''
    This error is raised when an error occurs during a subprocess call.
    '''
    pass


def matlab_solve(matfile_target, discard_matfile=True, **_):
    '''
    The .mat is loaded into matlab and the problem is solved with SDPT3.

    Args:
        matfile_target: the path to the .mat file containing the Sedumi format problem data.
        discard_matfile: if True, deletes the .mat file after the solve finishes.

    Returns:
        A dictionary with solve result information.

    Raises:
        SubprocessCallError when some error happens while executing matlab.
    '''
    # Generating the .mat file
    run_command = "matlab -r \"SDPT3solve('{0}')\" -nodisplay -nojvm".format(
        matfile_target)
    msg = _run_command_get_output(run_command)

    # Cleanup
    if discard_matfile:
        print "now deleting {0}".format(matfile_target)
        os.remove(matfile_target)

    return msg


def octave_solve(matfile_target, discard_matfile=True, cmd="octave", **_):
    '''
    The .mat is loaded into octave and the problem is solved with SDPT3.

    Args:
        matfile_target: the path to the .mat file containing the Sedumi format problem data.
        discard_matfile: if True, deletes the .mat file after the solve finishes.
        cmd: command name for octave, which will be used for alternative command.

    Returns:
        A dictionary with solve result information.

    Raises:
        SubprocessCallError when some error happens while executing octave.
    '''
    # Generating the .mat file
    with tempfile.NamedTemporaryFile(
        suffix=".m", dir=os.path.dirname(matfile_target)) as runner:

        with open(os.path.join(os.path.dirname(__file__), "SDPT3solve.m")) as lib:
            shutil.copyfileobj(lib, runner)

        runner.write("SDPT3solve('{0}');\n".format(
            os.path.relpath(matfile_target)))
        runner.flush()

        run_command = "{cmd} {script}".format(
            cmd=cmd, script=os.path.relpath(runner.name))
        msg = _run_command_get_output(run_command)

    # Cleanup
    if discard_matfile:
        print "now deleting {0}".format(matfile_target)
        os.remove(matfile_target)

    return msg


def _run_command_get_output(run_command):
    '''
    Runs the command run_command, saves the output to output_target, and
    returns the output log.
    '''
    # Performing the Matlab solve
    try:
        proc = subprocess.Popen(
            run_command, shell=True, stdout=subprocess.PIPE)
        return proc.communicate()[0]

    except:
        err_msg = ("Something went wrong with the command. The command "
                   "run was:\n{0}\nPlease check that the command looks good "
                   "and that the the folder containing SDPT3solve.m is in the "
                   "Matlab or Octave path variable.").format(run_command)
        raise SubprocessCallError(err_msg)