Optimal bucket¶
Principles learned¶
- Add float decision variables
- Maximize a non-linear objective
- Create a constraint on a non-linear expression
Problem¶
What is the optimal shape for a bucket?
If you were designing a bucket, what shape would you select so that it maximizes the fluid it can hold based on the material used to make the bucket?
For more details, see DataGenetics
Download the exampleProgram¶
We have a flat disk of Radius R=1. The surface of material needed to build this disk is S=π. Without using more material than this amount, we try to build a bucket that holds the largest volume.
A bucket is defined by the radius of the bottom disc r, the radius of the top
opening R, and the height h. These are the 3 variables of the model. The surface
of material used to build this bucket is the bottom disc and the sides: S =
π*r² + π(R+r)sqrt((R-r)²+h²)
. It is constrained to be lower than π.
Then, the volume V = (π*h)/3 * (R²+Rr+r²)
is maximized.
- Execution:
- localsolver optimal_bucket.lsp [lsTimeLimit=] [solFileName=]
/********** optimal_bucket.lsp **********/
use io;
/* Declares the optimization model. */
function model() {
PI = 3.14159265359;
// Numerical decisions
R <- float(0,1);
r <- float(0,1);
h <- float(0,1);
// Surface must not exceed the surface of the plain disc
surface <- PI*pow(r, 2) + PI*(R + r)*sqrt(pow(R - r, 2) + pow(h, 2));
constraint surface <= PI;
// Maximize the volume
volume <- PI*h/3*(pow(R, 2) + R*r + pow(r, 2));
maximize volume;
}
/* Parameterizes the solver. */
function param() {
if(lsTimeLimit == nil) lsTimeLimit = 2;
}
/* Writes the solution in a file with the following format:
* - surface and volume of the bucket
* - values of R, r and h */
function output() {
if (solFileName == nil) return;
local solFile = io.openWrite(solFileName);
solFile.println(surface.value," ",volume.value);
solFile.println(R.value," ",r.value," ",h.value);
}
- Execution (Windows)
- set PYTHONPATH=%LS_HOME%\bin\python27\python optimal_bucket.py
- Execution (Linux)
- export PYTHONPATH=/opt/localsolver_XXX/bin/python27/python optimal_bucket.py
########## optimal_bucket.py ##########
import localsolver
import sys
with localsolver.LocalSolver() as ls:
PI = 3.14159265359
#
# Declares the optimization model
#
m = ls.model
# Numerical decisions
R = m.float(0,1)
r = m.float(0,1)
h = m.float(0,1)
# Surface must not exceed the surface of the plain disc
surface = PI*r**2 + PI*(R+r)*m.sqrt((R - r)**2 + h**2)
m.constraint(surface <= PI)
# Maximize the volume
volume = PI*h/3*(R**2 + R*r + r**2)
m.maximize(volume)
m.close()
#
# Param
#
if len(sys.argv) >= 3: ls.param.time_limit = int(sys.argv[2])
else: ls.param.time_limit = 2
ls.solve()
#
# Writes the solution in a file with the following format:
# - surface and volume of the bucket
# - values of R, r and h
#
if len(sys.argv) >= 2:
with open(sys.argv[1], 'w') as f:
f.write("%f %f\n" % (surface.value, volume.value))
f.write("%f %f %f\n" % (R.value, r.value, h.value))
- Compilation / Execution (Windows)
- cl /EHsc optimal_bucket.cpp -I%LS_HOME%\include /link %LS_HOME%\bin\localsolver.dll.liboptimal_bucket
- Compilation / Execution (Linux)
- g++ optimal_bucket.cpp -I/opt/localsolver_XXX/include -llocalsolver -lpthread -o optimal_bucketoptimal_bucket
//********* optimal_bucket.cpp *********
#include <iostream>
#include <fstream>
#include <vector>
#include "localsolver.h"
using namespace localsolver;
using namespace std;
class OptimalBucket {
public:
// Solver.
LocalSolver localsolver;
// LS Program variables.
LSExpression R;
LSExpression r;
LSExpression h;
LSExpression surface;
LSExpression volume;
void solve(int limit) {
lsdouble PI = 3.14159265359;
// Declares the optimization model.
LSModel model = localsolver.getModel();
// Numerical decisions
R = model.floatVar(0.0, 1.0);
r = model.floatVar(0.0, 1.0);
h = model.floatVar(0.0, 1.0);
// Surface must not exceed the surface of the plain disc
surface = PI*model.pow(r, 2) + PI*(R + r)*model.sqrt(model.pow(R - r, 2) + model.pow(h, 2));
model.constraint(model.leq(surface, PI));
// Maximize the volume
volume = PI*h/3*(model.pow(R, 2) + R*r + model.pow(r, 2));
model.maximize(volume);
model.close();
// Parameterizes the solver.
localsolver.getParam().setTimeLimit(limit);
localsolver.solve();
}
// Writes the solution in a file with the following format:
// - surface and volume of the bucket
// - values of R, r and h
void writeSolution(const string& fileName) {
ofstream outfile;
outfile.exceptions(ofstream::failbit | ofstream::badbit);
outfile.open(fileName.c_str());
outfile << surface.getDoubleValue() << " " << volume.getDoubleValue() << endl;
outfile << R.getDoubleValue() << " " << r.getDoubleValue() << " " << h.getDoubleValue() << endl;
}
};
int main(int argc, char** argv) {
const char* solFile = argc > 1 ? argv[1] : NULL;
const char* strTimeLimit = argc > 2 ? argv[2] : "2";
try {
OptimalBucket model;
model.solve(atoi(strTimeLimit));
if(solFile != NULL) model.writeSolution(solFile);
return 0;
} catch (const exception& e){
cerr << "Error occurred:" << e.what() << endl;
return 1;
}
}
- Compilation/Execution (Windows)
- copy %LS_HOME%\bin\*net.dll .csc OptimalBucket.cs /reference:localsolvernet.dllOptimalBucket
/********** optimal_bucket.cs **********/
using System;
using System.IO;
using localsolver;
public class OptimalBucket : IDisposable
{
// Solver.
LocalSolver localsolver;
// LS Program variables.
LSExpression R;
LSExpression r;
LSExpression h;
LSExpression surface;
LSExpression volume;
public OptimalBucket()
{
localsolver = new LocalSolver();
}
public void Dispose()
{
if (localsolver != null)
localsolver.Dispose();
}
public void Solve(int limit)
{
// Declares the optimization model.
LSModel model = localsolver.GetModel();
// Numerical decisions
R = model.Float(0, 1);
r = model.Float(0, 1);
h = model.Float(0, 1);
// Surface must not exceed the surface of the plain disc
surface = Math.PI * model.Pow(r, 2) + Math.PI * (R + r) * model.Sqrt(model.Pow(R - r, 2) + model.Pow(h, 2));
model.AddConstraint(surface <= Math.PI);
// Maximize the volume
volume = Math.PI * h / 3 * (model.Pow(R, 2) + R * r + model.Pow(r, 2));
model.Maximize(volume);
model.Close();
// Parameterizes the solver.
localsolver.GetParam().SetTimeLimit(limit);
localsolver.Solve();
}
// Writes the solution in a file with the following format:
// - surface and volume of the bucket
// - values of R, r and h
public void WriteSolution(string fileName)
{
using (StreamWriter output = new StreamWriter(fileName))
{
output.WriteLine(surface.GetDoubleValue() + " " + volume.GetDoubleValue());
output.WriteLine(R.GetDoubleValue() + " " + r.GetDoubleValue() + " " + h.GetDoubleValue());
}
}
public static void Main(string[] args)
{
string outputFile = args.Length > 0 ? args[0] : null;
string strTimeLimit = args.Length > 1 ? args[1] : "2";
using (OptimalBucket model = new OptimalBucket())
{
model.Solve(int.Parse(strTimeLimit));
if (outputFile != null)
{
model.WriteSolution(outputFile);
}
}
}
}
- Compilation / Execution (Windows)
- javac OptimalBucket.java -cp %LS_HOME%\bin\localsolver.jarjava -cp %LS_HOME%\bin\localsolver.jar;. OptimalBucket
- Compilation/Execution (Linux)
- javac OptimalBucket.java -cp /opt/localsolver_XXX/bin/localsolver.jarjava -cp /opt/localsolver_XXX/bin/localsolver.jar:. OptimalBucket
/********** OptimalBucket.java **********/
import java.io.*;
import localsolver.*;
public class OptimalBucket {
private static final double PI = 3.14159265359;
// Solver.
private LocalSolver localsolver;
// LS Program variables.
private LSExpression R;
private LSExpression r;
private LSExpression h;
private LSExpression surface;
private LSExpression volume;
private OptimalBucket(LocalSolver localsolver) {
this.localsolver = localsolver;
}
private void solve(int limit) {
// Declares the optimization model.
LSModel model = localsolver.getModel();
LSExpression piConst = model.createConstant(PI);
// Numerical decisions
R = model.floatVar(0, 1);
r = model.floatVar(0, 1);
h = model.floatVar(0, 1);
// Surface related expressions
// s1 = PI*r^2
LSExpression s1 = model.prod(piConst, r, r);
// s2 = (R - r)^2
LSExpression s2 = model.pow(model.sub(R, r), 2);
// s3 = h^2
LSExpression s3 = model.pow(h, 2);
// s4 = sqrt((R-r)^2 + h^2)
LSExpression s4 = model.sqrt(model.sum(s2, s3));
// s5 = R+r */
LSExpression s5 = model.sum(R, r);
// s6 = PI*(R + r)*sqrt((R - r)^2 + h^2)
LSExpression s6 = model.prod(piConst, s5, s4);
// surface = PI*r^2 + PI*(R+r)*sqrt((R - r)^2 + h^2)
surface = model.sum(s1, s6);
// Surface must not exceed the surface of the plain disc
model.addConstraint(model.leq(surface, PI));
// Volume related expressions
// v1 = R^2
LSExpression v1 = model.pow(R, 2);
// v2 = R*r
LSExpression v2 = model.prod(R, r);
// v3 = r^2
LSExpression v3 = model.pow(r, 2);
// volume = PI*h/3*(R^2 + R*r + r^2)
volume = model.prod(piConst, model.div(h, 3), model.sum(v1, v2, v3));
// Maximize the volume
model.maximize(volume);
model.close();
// Parameterizes the solver.
localsolver.getParam().setTimeLimit(limit);
localsolver.solve();
}
// Writes the solution in a file with the following format:
// - surface and volume of the bucket
// - values of R, r and h
private void writeSolution(String fileName) throws IOException {
try(PrintWriter output = new PrintWriter(fileName)) {
output.println(surface.getDoubleValue() + " " + volume.getDoubleValue());
output.println(R.getDoubleValue() + " " + r.getDoubleValue() + " " + h.getDoubleValue());
}
}
public static void main(String[] args) {
String outputFile = args.length > 0 ? args[0] : null;
String strTimeLimit = args.length > 1 ? args[1] : "2";
try (LocalSolver localsolver = new LocalSolver()) {
OptimalBucket model = new OptimalBucket(localsolver);
model.solve(Integer.parseInt(strTimeLimit));
if (outputFile != null) {
model.writeSolution(outputFile);
}
} catch(Exception ex) {
System.err.println(ex);
ex.printStackTrace();
System.exit(1);
}
}
}