From acb904a57aee99dd890e825bcae5d89eb7a9bb65 Mon Sep 17 00:00:00 2001 From: Steven Diamond Date: Thu, 15 Aug 2013 12:10:16 -0700 Subject: [PATCH] updated README --- README.md | 27 +++++++++++- add_gpl | 11 +++++ copyright.txt | 19 +++++++++ examples/flows/leaky_edges.py | 79 +++++++++++++++++++++++++++++++++++ examples/image_processing.py | 67 +++++++++++++++++++++++++++++ examples/optimal_control.py | 45 ++++++++++++++++++++ 6 files changed, 247 insertions(+), 1 deletion(-) create mode 100755 add_gpl create mode 100644 copyright.txt create mode 100644 examples/flows/leaky_edges.py create mode 100644 examples/image_processing.py create mode 100644 examples/optimal_control.py diff --git a/README.md b/README.md index 736e82c30b..b7ae14c0f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,31 @@ CVXPY ===== -CVXPY is a Python modeling language for optimization problems. +CVXPY is a Python modeling language for optimization problems. CVXPY lets you express your problem in a natural way. It automatically transforms the problem into a standard form, calls a solver, and unpacks the results. + +For example, consider the LASSO problem: + minimize ||Ax-b||~2~ + \lambda||x||~1~ + +The problem can be expressed in CVXPY like so: + +``` +from cvxpy import * + +# Problem data. +n = 10 +m = 5 +A = cvxopt.normal(n,m) +b = cvxopt.normal(m) +lambda = 1 + +# Construct the problem. +x = Variable(m) +p = Problem(Minimize(norm2(A*x - b) + lambda*norm1(x))) + +# The optimal objective is returned by p.solve(). +result = p.solve() +# The optimal value for x is stored in x.value. +print x.value +``` Currently supports numpy arrays and matrices, cvxopt matrices, numbers, and python lists as constants. Matrices and vectors must be declared as Constants, i.e. A = Constant(numpy array). diff --git a/add_gpl b/add_gpl new file mode 100755 index 0000000000..7a25e7f86c --- /dev/null +++ b/add_gpl @@ -0,0 +1,11 @@ +#!/bin/bash +# http://stackoverflow.com/questions/151677/tool-for-adding-license-headers-to-source-files +DIRECTORY=$1 +for i in $DIRECTORY/*.py # or whatever other pattern... +do + if ! grep -q Copyright $i + then + cat copyright.txt $i >$i.new && mv $i.new $i + echo $i + fi +done \ No newline at end of file diff --git a/copyright.txt b/copyright.txt new file mode 100644 index 0000000000..1f3e6c73e0 --- /dev/null +++ b/copyright.txt @@ -0,0 +1,19 @@ +""" +Copyright 2013 Steven Diamond + +This file is part of CVXPY. + +CVXPY is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +CVXPY is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with CVXPY. If not, see . +""" + diff --git a/examples/flows/leaky_edges.py b/examples/flows/leaky_edges.py new file mode 100644 index 0000000000..b07fc85c27 --- /dev/null +++ b/examples/flows/leaky_edges.py @@ -0,0 +1,79 @@ +""" +Copyright 2013 Steven Diamond + +This file is part of CVXPY. + +CVXPY is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +CVXPY is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with CVXPY. If not, see . +""" + +from cvxpy import * +import create_graph as g +from max_flow import Node, Edge +import pickle + +# Max-flow with different kinds of edges. +class Directed(Edge): + """ A directed, capacity limited edge """ + # Returns the edge's internal constraints. + def constraints(self): + return [self.in_flow <= 0] + super(Directed, self).constraints() + +class LeakyDirected(Edge): + """ A directed edge that leaks flow. """ + EFFICIENCY = .95 + # Returns the edge's internal constraints. + def constraints(self): + return [self.EFFICIENCY*self.in_flow + self.out_flow == 0, + self.in_flow <= 0, + abs(self.in_flow) <= self.capacity] + +class LeakyUndirected(Edge): + """ An undirected edge that leaks flow. """ + # Model a leaky undirected edge as two leaky directed + # edges pointing in opposite directions. + def __init__(self, capacity): + self.forward = LeakyDirected(capacity) + self.backward = LeakyDirected(capacity) + self.in_flow = self.forward.in_flow + self.backward.out_flow + self.out_flow = self.forward.out_flow + self.backward.in_flow + + def constraints(self): + return self.forward.constraints() + self.backward.constraints() + +if __name__ == "__main__": + # Read a graph from a file. + f = open(g.FILE, 'r') + data = pickle.load(f) + f.close() + + # Construct nodes. + node_count = data[g.NODE_COUNT_KEY] + nodes = [Node() for i in range(node_count)] + # Add source. + nodes[0].accumulation = Variable() + # Add sink. + nodes[-1].accumulation = Variable() + + # Construct edges. + edges = [] + for n1,n2,capacity in data[g.EDGES_KEY]: + edges.append(LeakyUndirected(capacity)) + edges[-1].connect(nodes[n1], nodes[n2]) + + # Construct the problem. + constraints = [] + map(constraints.extend, (o.constraints() for o in nodes + edges)) + p = Problem(Maximize(nodes[-1].accumulation), constraints) + result = p.solve() + print result \ No newline at end of file diff --git a/examples/image_processing.py b/examples/image_processing.py new file mode 100644 index 0000000000..7cb66cba71 --- /dev/null +++ b/examples/image_processing.py @@ -0,0 +1,67 @@ +from cvxpy import * +from itertools import izip, imap +import cvxopt +import pylab +import math + +# create simple image +n = 32 +img = cvxopt.matrix(0.0,(n,n)) +img[1:2,1:2] = 0.5 + +# add noise +img = img + 0.1*cvxopt.uniform(n,n) + +# show the image +plt = pylab.imshow(img) +plt.set_cmap('gray') +pylab.show() + +# define the gradient functions +def grad(img, direction): + m, n = img.size + for i in range(m): + for j in range(n): + if direction == 'y' and j > 0 and j < m-1: + yield img[i,j+1] - img[i,j-1] + elif direction == 'x' and i > 0 and i < n-1: + yield img[i+1,j] - img[i-1,j] + else: + yield 0.0 + +# take the gradients +img_gradx, img_grady = grad(img,'x'), grad(img,'y') + +# filter them (remove ones with small magnitude) + +def denoise(gradx, grady, thresh): + for dx, dy in izip(gradx, grady): + if math.sqrt(dx*dx + dy*dy) >= thresh: yield (dx,dy) + else: yield (0.0,0.0) + +denoise_gradx, denoise_grady = izip(*denoise(img_gradx, img_grady, 0.2)) + +# function to get boundary of image +def boundary(img): + m, n = img.size + for i in range(m): + for j in range(n): + if i == 0 or j == 0 or i == n-1 or j == n-1: + yield img[i,j] + +# now, reconstruct the image by solving a constrained least-squares problem +new_img = Variable(n,n) +gradx_obj = imap(square, (fx - gx for fx, gx in izip(grad(new_img,'x'),denoise_gradx))) +grady_obj = imap(square, (fy - gy for fy, gy in izip(grad(new_img,'y'),denoise_grady))) + +p = Problem( + Minimize(sum(gradx_obj) + sum(grady_obj)), + list(px == 0 for px in boundary(new_img))) +p.solve() + +# show the reconstructed image +plt = pylab.imshow(new_img.value) +plt.set_cmap('gray') +pylab.show() + +print new_img.value \ No newline at end of file diff --git a/examples/optimal_control.py b/examples/optimal_control.py new file mode 100644 index 0000000000..6cc2dc5412 --- /dev/null +++ b/examples/optimal_control.py @@ -0,0 +1,45 @@ +""" +Copyright 2013 Steven Diamond + +This file is part of CVXPY. + +CVXPY is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +CVXPY is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with CVXPY. If not, see . +""" + +from cvxpy import * +import cvxopt +# Problem data +T = 10 +n,p = (10,5) +A = cvxopt.normal(n,n) +B = cvxopt.normal(n,p) +x_init = cvxopt.normal(n) +x_final = cvxopt.normal(n) + +# Object oriented optimal control problem. +class Stage(object): + def __init__(self, A, B, x_prev): + self.x = Variable(n) + self.u = Variable(p) + self.cost = sum(square(self.u)) + sum(abs(self.x)) + self.constraint = (self.x == A*x_prev + B*self.u) + +stages = [Stage(A, B, x_init)] +for i in range(T): + stages.append(Stage(A, B, stages[-1].x)) + +obj = sum(s.cost for s in stages) +constraints = [stages[-1].x == x_final] +map(constraints.append, (s.constraint for s in stages)) +print Problem(Minimize(obj), constraints).solve() \ No newline at end of file