Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python wrapper increased optional parameters #56

Merged
merged 15 commits into from
May 22, 2014
Merged

Conversation

ThomasLipp
Copy link
Contributor

Added options for tolerance variables and max iterations to the python wrapper for ecos offering the same functionality as MATLAB. I followed the SCS template where possible, so everything is handled almost exactly the same, except that I left verbose as its own argument to preserve backwards compatibility. I also followed the SCS model of providing limited information about the arguments in the readme.

I opted to statically allocate the settings array. this creates slightly more overhead (several floats) in the scenario where there are no opt arguments, but avoids needing to worry about memory allocation. If we're worried about the couple floats, we can switch to dynamic allocation.

@@ -142,7 +201,7 @@ static PyObject *csolve(PyObject* self, PyObject *args, PyObject *kwargs)
PyArrayObject *Ai = NULL;
PyArrayObject *Ap = NULL;
PyArrayObject *b = NULL;
PyObject *dims, *verbose = NULL;
PyObject *dims, *verbose, *opts = NULL;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we've made a silly mistake here: should this read

PyObject *dims = NULL;
PyObject *verbose = NULL;
PyObject *opts = NULL;

Better safe than sorry. :)

@echu
Copy link
Collaborator

echu commented May 19, 2014

Except for my comment, it looks good to me. @adomahidi, any thoughts?

@adomahidi
Copy link
Member

I guess having the verbose still as an argument is for backward compatibility? Could we handle this internally and rather have only an "opts" argument?

@echu
Copy link
Collaborator

echu commented May 19, 2014

Yeah, we can; I left the choice to Thomas. If you have an opinion, though,
now is the time to make it known! I don't have a preference, and I think
Thomas would rather not break backwards compatibility. If you want to break
backwards compatibility, though, go for it. I think it might break QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have only an
"opts" argument?


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43567158
.

@adomahidi
Copy link
Member

But maybe we don't have to break backwards compatibility - of that argument is not a dictionary then it's the old behavior, otherwise it's an opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu notifications@github.com wrote:

Yeah, we can; I left the choice to Thomas. If you have an opinion, though,
now is the time to make it known! I don't have a preference, and I think
Thomas would rather not break backwards compatibility. If you want to break
backwards compatibility, though, go for it. I think it might break QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have only an
"opts" argument?


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43567158
.


Reply to this email directly or view it on GitHub.

@echu
Copy link
Collaborator

echu commented May 19, 2014

Well, the argument would have to be named "verbose" which is really strange
for an "opts" argument. We can't do that without breaking backwards
compatibility. Thomas and I had a discussion about this: the current
function prototype is

def ecos(c,G,h,dims,A,b,verbose=False)

This means the last argument is "named". So you can call
ecos(c,G,h,dims,A,b,True) or ecos(c,G,h,dims,A,b,verbose=True) and both
would work.

What you're proposing is something like

ecos(c,G,h,dims,A,b,True)

or

ecos(c,G,h,dims,A,b,{'verbose': True})

but the following would also work

ecos(c,G,h,dims,A,b, verbose={'verbose': True})

and

ecos(c,G,h,dims,A,b, opts={'verbose': True})

would not. There's no good way to modify the prototype so that it works
without surprises. If we're going to maintain backwards compatibility, I
think Thomas' method is better. If it's too sloppy, then let's just break
backwards compatibility. We probably will have to at some point anyway.

On Mon, May 19, 2014 at 4:00 PM, Alexander Domahidi <
notifications@github.com> wrote:

But maybe we don't have to break backwards compatibility - of that
argument is not a dictionary then it's the old behavior, otherwise it's an
opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu notifications@github.com wrote:

Yeah, we can; I left the choice to Thomas. If you have an opinion,
though,
now is the time to make it known! I don't have a preference, and I think
Thomas would rather not break backwards compatibility. If you want to
break
backwards compatibility, though, go for it. I think it might break QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have only an
"opts" argument?


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43567158>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43568850
.

@adomahidi
Copy link
Member

I understand, thanks for the explanation. The my opinion is to break backwards compatibility, since it's cleaner, and the changes required in CVXPY and QCML are minimal. What do you think?

On May 19, 2014, at 4:06 PM, Eric Chu notifications@github.com wrote:

Well, the argument would have to be named "verbose" which is really strange
for an "opts" argument. We can't do that without breaking backwards
compatibility. Thomas and I had a discussion about this: the current
function prototype is

def ecos(c,G,h,dims,A,b,verbose=False)

This means the last argument is "named". So you can call
ecos(c,G,h,dims,A,b,True) or ecos(c,G,h,dims,A,b,verbose=True) and both
would work.

What you're proposing is something like

ecos(c,G,h,dims,A,b,True)

or

ecos(c,G,h,dims,A,b,{'verbose': True})

but the following would also work

ecos(c,G,h,dims,A,b, verbose={'verbose': True})

and

ecos(c,G,h,dims,A,b, opts={'verbose': True})

would not. There's no good way to modify the prototype so that it works
without surprises. If we're going to maintain backwards compatibility, I
think Thomas' method is better. If it's too sloppy, then let's just break
backwards compatibility. We probably will have to at some point anyway.

On Mon, May 19, 2014 at 4:00 PM, Alexander Domahidi <
notifications@github.com> wrote:

But maybe we don't have to break backwards compatibility - of that
argument is not a dictionary then it's the old behavior, otherwise it's an
opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu notifications@github.com wrote:

Yeah, we can; I left the choice to Thomas. If you have an opinion,
though,
now is the time to make it known! I don't have a preference, and I think
Thomas would rather not break backwards compatibility. If you want to
break
backwards compatibility, though, go for it. I think it might break QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have only an
"opts" argument?


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43567158>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43568850
.


Reply to this email directly or view it on GitHub.

@echu
Copy link
Collaborator

echu commented May 19, 2014

up to thomas. :)

On Mon, May 19, 2014 at 4:10 PM, Alexander Domahidi <
notifications@github.com> wrote:

I understand, thanks for the explanation. The my opinion is to break
backwards compatibility, since it's cleaner, and the changes required in
CVXPY and QCML are minimal. What do you think?

On May 19, 2014, at 4:06 PM, Eric Chu notifications@github.com wrote:

Well, the argument would have to be named "verbose" which is really
strange
for an "opts" argument. We can't do that without breaking backwards
compatibility. Thomas and I had a discussion about this: the current
function prototype is

def ecos(c,G,h,dims,A,b,verbose=False)

This means the last argument is "named". So you can call
ecos(c,G,h,dims,A,b,True) or ecos(c,G,h,dims,A,b,verbose=True) and
both
would work.

What you're proposing is something like

ecos(c,G,h,dims,A,b,True)

or

ecos(c,G,h,dims,A,b,{'verbose': True})

but the following would also work

ecos(c,G,h,dims,A,b, verbose={'verbose': True})

and

ecos(c,G,h,dims,A,b, opts={'verbose': True})

would not. There's no good way to modify the prototype so that it works
without surprises. If we're going to maintain backwards compatibility, I
think Thomas' method is better. If it's too sloppy, then let's just
break
backwards compatibility. We probably will have to at some point anyway.

On Mon, May 19, 2014 at 4:00 PM, Alexander Domahidi <
notifications@github.com> wrote:

But maybe we don't have to break backwards compatibility - of that
argument is not a dictionary then it's the old behavior, otherwise
it's an
opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu notifications@github.com
wrote:

Yeah, we can; I left the choice to Thomas. If you have an opinion,
though,
now is the time to make it known! I don't have a preference, and I
think
Thomas would rather not break backwards compatibility. If you want
to
break
backwards compatibility, though, go for it. I think it might break
QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have
only an
"opts" argument?


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43567158>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43568850>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43569604
.

@ThomasLipp
Copy link
Contributor Author

I don't have strong feelings on the matter, and we can easily roll verbose
into the optional arguments. Although, keeping verbose separate is
consistent with the current cvxpy implementation, where verbose is a
privileged argument that gets its own keyword, that decision seems somewhat
arbitrary to me. I won't have time until tomorrow to make the changes and
make the cvxpy interface consistent. Haven't looked at QCML at all,

Thomas

On Mon, May 19, 2014 at 4:12 PM, Eric Chu notifications@github.com wrote:

up to thomas. :)

On Mon, May 19, 2014 at 4:10 PM, Alexander Domahidi <
notifications@github.com> wrote:

I understand, thanks for the explanation. The my opinion is to break
backwards compatibility, since it's cleaner, and the changes required in
CVXPY and QCML are minimal. What do you think?

On May 19, 2014, at 4:06 PM, Eric Chu notifications@github.com wrote:

Well, the argument would have to be named "verbose" which is really
strange
for an "opts" argument. We can't do that without breaking backwards
compatibility. Thomas and I had a discussion about this: the current
function prototype is

def ecos(c,G,h,dims,A,b,verbose=False)

This means the last argument is "named". So you can call
ecos(c,G,h,dims,A,b,True) or ecos(c,G,h,dims,A,b,verbose=True) and
both
would work.

What you're proposing is something like

ecos(c,G,h,dims,A,b,True)

or

ecos(c,G,h,dims,A,b,{'verbose': True})

but the following would also work

ecos(c,G,h,dims,A,b, verbose={'verbose': True})

and

ecos(c,G,h,dims,A,b, opts={'verbose': True})

would not. There's no good way to modify the prototype so that it
works
without surprises. If we're going to maintain backwards compatibility,
I
think Thomas' method is better. If it's too sloppy, then let's just
break
backwards compatibility. We probably will have to at some point
anyway.

On Mon, May 19, 2014 at 4:00 PM, Alexander Domahidi <
notifications@github.com> wrote:

But maybe we don't have to break backwards compatibility - of that
argument is not a dictionary then it's the old behavior, otherwise
it's an
opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu notifications@github.com
wrote:

Yeah, we can; I left the choice to Thomas. If you have an opinion,
though,
now is the time to make it known! I don't have a preference, and I
think
Thomas would rather not break backwards compatibility. If you want
to
break
backwards compatibility, though, go for it. I think it might break
QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.com> wrote:

I guess having the verbose still as an argument is for backward
compatibility? Could we handle this internally and rather have
only an
"opts" argument?


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43567158>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43568850>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43569604>
.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43569711
.

@echu
Copy link
Collaborator

echu commented May 19, 2014

Dont worry about QCML. We can make the update and if something breaks, it's
easy for me to fix. It's a small code base.

I think CVXPY privileges verbose because it had to be compatible with ECOS
and SCS. If we fix things here, I think steven diamond can make the
notation consistent.

On Monday, May 19, 2014, ThomasLipp notifications@github.com wrote:

I don't have strong feelings on the matter, and we can easily roll verbose
into the optional arguments. Although, keeping verbose separate is
consistent with the current cvxpy implementation, where verbose is a
privileged argument that gets its own keyword, that decision seems
somewhat
arbitrary to me. I won't have time until tomorrow to make the changes and
make the cvxpy interface consistent. Haven't looked at QCML at all,

Thomas

On Mon, May 19, 2014 at 4:12 PM, Eric Chu <notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>
wrote:

up to thomas. :)

On Mon, May 19, 2014 at 4:10 PM, Alexander Domahidi <
notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>
wrote:

I understand, thanks for the explanation. The my opinion is to break
backwards compatibility, since it's cleaner, and the changes required
in
CVXPY and QCML are minimal. What do you think?

On May 19, 2014, at 4:06 PM, Eric Chu <notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>
wrote:

Well, the argument would have to be named "verbose" which is really
strange
for an "opts" argument. We can't do that without breaking backwards
compatibility. Thomas and I had a discussion about this: the current
function prototype is

def ecos(c,G,h,dims,A,b,verbose=False)

This means the last argument is "named". So you can call
ecos(c,G,h,dims,A,b,True) or ecos(c,G,h,dims,A,b,verbose=True)
and
both
would work.

What you're proposing is something like

ecos(c,G,h,dims,A,b,True)

or

ecos(c,G,h,dims,A,b,{'verbose': True})

but the following would also work

ecos(c,G,h,dims,A,b, verbose={'verbose': True})

and

ecos(c,G,h,dims,A,b, opts={'verbose': True})

would not. There's no good way to modify the prototype so that it
works
without surprises. If we're going to maintain backwards
compatibility,
I
think Thomas' method is better. If it's too sloppy, then let's just
break
backwards compatibility. We probably will have to at some point
anyway.

On Mon, May 19, 2014 at 4:00 PM, Alexander Domahidi <
notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>
wrote:

But maybe we don't have to break backwards compatibility - of that
argument is not a dictionary then it's the old behavior, otherwise
it's an
opt dictionary. Would that work conceptually?

On May 19, 2014, at 3:58 PM, Eric Chu <notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>

wrote:

Yeah, we can; I left the choice to Thomas. If you have an
opinion,
though,
now is the time to make it known! I don't have a preference, and
I
think
Thomas would rather not break backwards compatibility. If you
want
to
break
backwards compatibility, though, go for it. I think it might
break
QCML,
but it's easy for me to fix.

On Mon, May 19, 2014 at 3:37 PM, Alexander Domahidi <
notifications@github.comjavascript:_e(%7B%7D,'cvml','notifications@github.com');>
wrote:

I guess having the verbose still as an argument is for
backward
compatibility? Could we handle this internally and rather have
only an
"opts" argument?


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43567158>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43568850>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43569604>
.


Reply to this email directly or view it on GitHub<
https://github.com/ifa-ethz/ecos/pull/56#issuecomment-43569711>
.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43571893
.

@ThomasLipp
Copy link
Contributor Author

VERBOSE is now an argument to opts and has been removed as an argument breaking backwards compatibility. Added a bool parser.

For some reason SCS is printing error messages in python to stdout. I switched the printing of error messages to stderr in ECOS, but if there's a good reason to have them print to stdout, we can switch that back.

As currently implemented in cvxpy (will submit a pull request for that shortly), the VERBOSE option added as an optional argument takes precedence over the verbose entered as a keyword. I don't think there's really a way to do a workaround for this, since I'm not aware of a way to distinguish between a verbose=False argument and the default argument in python, so I think we just declare that a feature. If the verbose keyword takes precedents then "VERBOSE":True will have no effect since verbose will default to false and take precedence.

@echu
Copy link
Collaborator

echu commented May 21, 2014

Looks good to me. We should be printing to stderr, so that's a good fix. I think SCS prints to stdout, because I was doing it here. I think we're finally used enough for error reporting to matter. @adomahidi, thoughts?

I'm not sure I understand your comment about the verbose option in CVXPY. Shouldn't the verbose keyword in CVXPY just be put into the opts structure now?

@ThomasLipp
Copy link
Contributor Author

So you still have the option to call cvxpy with p.solve(cp.ECOS,verbose=True) or p.solve(cp.ECOS,solver_specific_opts={'VERBOSE':True}). If you call p.solve(cp.ECOS,verbose=True,solver_specific_opts={'VERBOSE':False}), verbose will be set to false.

This is the same behavior that SCS has.

Steven wanted to keep verbose as a keywords as he viewed it more as an argument to cvxpy than as an argument to the solver. If we want to convince Stephen to eliminate the verbose argument that would of course eliminate this problem, but it may be more important to preserve cvxpy backwards compatibility.

@echu
Copy link
Collaborator

echu commented May 21, 2014

Sure, but nothing's stopping him from making it "work out" under the hood.
Looks good to me. Once Alex OKs this, we can merge in the PR. I have
several other patches I need to put in, but then I think 1.0.4 should be
ready.

On Wednesday, May 21, 2014, ThomasLipp notifications@github.com wrote:

So you still have the option to call cvxpy with
p.solve(cp.ECOS,verbose=True) or
p.solve(cp.ECOS,specific_solver_opts={'VERBOSE':True}). If you call
p.solve(cp.ECOS,verbose=true,specific_solver_opts={'VERBOSE':False}),
verbose will be set to false.

Steven wanted to keep verbose as a keywords as he viewed it more as an
argument to cvxpy than as an argument to the solver.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43812765
.

@SteveDiamond
Copy link
Collaborator

I think adding *_kwargs to the ecos.solve method would be more pythonic than having an opts dictionary. At a minimum, I'd like to use *_kwargs to replace solver_specific_opts and verbose. It would be easier for me if the ecos interface worked the same way. It's less awkward to write

prob.solve(verbose=True, max_iters=100)

than

opts = {"VERBOSE": True, "MAX_ITERS":100}
prob.solve(solver_specific_opts=opts)

@echu
Copy link
Collaborator

echu commented May 21, 2014

Hmmm. Thomas, how much work do u think it would be to modify your PR. I
think you can get away with

def ecos(..., **opts)

But make the keywords lowercase instead of uppercase now.

There are ways around this from the cvxpy side, also. You can always just
use opts=kwargs (assuming your keys are a superset of solver opts). But I
(now) prefer Steven's idea. (Sorry!)

If it's a bit of work, I can fix this after we accept the PR.

On Wednesday, May 21, 2014, Steven Diamond notifications@github.com wrote:

I think adding *_kwargs to the ecos.solve method would be more pythonic
than having an opts dictionary. At a minimum, I'd like to use *_kwargs to
replace solver_specific_opts and verbose. It would be easier for me if the
ecos interface worked the same way. It's less awkward to write

prob.solve(verbose=True, max_iters=100)

than

opts = {"VERBOSE": True, "MAX_ITERS":100}
prob.solve(solver_specific_opts=opts)


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43815540
.

@ThomasLipp
Copy link
Contributor Author

Probably won't be very hard, but I won't have any time to look at this until Friday at the earliest.

@echu
Copy link
Collaborator

echu commented May 21, 2014

Sure. If the PR isn't closed by then, then I haven't started working on it.
If it's closed by then, I have. :)

On Wednesday, May 21, 2014, ThomasLipp notifications@github.com wrote:

Probably won't be very hard, but I won't have any time to look at this
until Friday at the earliest.


Reply to this email directly or view it on GitHubhttps://github.com//pull/56#issuecomment-43818293
.

@ThomasLipp
Copy link
Contributor Author

So I'm still relatively new to python and kwargs, but this appears to work for me, but I'm uncertain on how to document it, and someone should check to make sure I haven't done anything foolish.

@echu echu mentioned this pull request May 22, 2014
@adomahidi
Copy link
Member

I must admit I's also prefer Steven's suggestion - it's quite a nice way of setting only those parameters that you actually want to set. No need to deal with the whole dictionary.

On May 21, 2014, at 7:20 PM, ThomasLipp notifications@github.com wrote:

So I'm still relatively new to python and kwargs, but this appears to work for me, but I'm uncertain on how to document it, and someone should check to make sure I haven't done anything foolish.


Reply to this email directly or view it on GitHub.

@echu
Copy link
Collaborator

echu commented May 22, 2014

I'm merging this PR so I can start working on some bug fixes for the 1.0.4 release candidate.

echu added a commit that referenced this pull request May 22, 2014
Python wrapper increased optional parameters
@echu echu merged commit 1f21dd1 into embotech:master May 22, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants