# Optimal Bucket¶

## Principles learned¶

• 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

## Program¶

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=]
```use io;

/* Declare 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;
}

/* Parametrize the solver */
function param() {
if (lsTimeLimit == nil) lsTimeLimit = 2;
}

/* Write 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\python
python optimal_bucket.py
Execution (Linux)
export PYTHONPATH=/opt/localsolver_12_0/bin/python
python optimal_bucket.py
```import localsolver
import sys

with localsolver.LocalSolver() as ls:
PI = 3.14159265359

#
# Declare 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()

#
# Parametrize the solver
#
if len(sys.argv) >= 3:
ls.param.time_limit = int(sys.argv)
else:
ls.param.time_limit = 2

ls.solve()

#
# Write 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, '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\localsolver120.lib
optimal_bucket
Compilation / Execution (Linux)
g++ optimal_bucket.cpp -I/opt/localsolver_12_0/include -llocalsolver120 -lpthread -o optimal_bucket
optimal_bucket
```#include "localsolver.h"
#include <fstream>
#include <iostream>
#include <vector>

using namespace localsolver;
using namespace std;

class OptimalBucket {
public:
// LocalSolver
LocalSolver localsolver;

// LS Program variables
LSExpression R;
LSExpression r;
LSExpression h;

LSExpression surface;
LSExpression volume;

void solve(int limit) {
lsdouble PI = 3.14159265359;

// Declare 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();

// Parametrize the solver
localsolver.getParam().setTimeLimit(limit);

localsolver.solve();
}

/* Write 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.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 : NULL;
const char* strTimeLimit = argc > 2 ? argv : "2";

try {
OptimalBucket model;
model.solve(atoi(strTimeLimit));
if (solFile != NULL)
model.writeSolution(solFile);
return 0;
} catch (const exception& e) {
cerr << "An error occurred:" << e.what() << endl;
return 1;
}
}
```
Compilation / Execution (Windows)
copy %LS_HOME%\bin\localsolvernet.dll .
csc OptimalBucket.cs /reference:localsolvernet.dll
OptimalBucket
```using System;
using System.IO;
using localsolver;

public class OptimalBucket : IDisposable
{
// LocalSolver
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)
{
// Declare 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));

// Maximize the volume
volume = Math.PI * h / 3 * (model.Pow(R, 2) + R * r + model.Pow(r, 2));
model.Maximize(volume);

model.Close();

// Parametrize the solver
localsolver.GetParam().SetTimeLimit(limit);

localsolver.Solve();
}

// Write 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 : null;
string strTimeLimit = args.Length > 1 ? args : "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.jar
java -cp %LS_HOME%\bin\localsolver.jar;. OptimalBucket
Compilation / Execution (Linux)
javac OptimalBucket.java -cp /opt/localsolver_12_0/bin/localsolver.jar
java -cp /opt/localsolver_12_0/bin/localsolver.jar:. OptimalBucket
```import java.io.*;
import localsolver.*;

public class OptimalBucket {
private static final double PI = 3.14159265359;

// LocalSolver
private final 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) {
// Declare 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 = PI*r^2 + PI*(R+r)*sqrt((R - r)^2 + h^2)
LSExpression s1 = model.prod(piConst, r, r);
LSExpression s2 = model.pow(model.sub(R, r), 2);
LSExpression s3 = model.pow(h, 2);
LSExpression s4 = model.sqrt(model.sum(s2, s3));
LSExpression s5 = model.sum(R, r);
LSExpression s6 = model.prod(piConst, s5, s4);
surface = model.sum(s1, s6);

// Surface must not exceed the surface of the plain disc

LSExpression v1 = model.pow(R, 2);
LSExpression v2 = model.prod(R, r);
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();

// Parametrize the solver
localsolver.getParam().setTimeLimit(limit);

localsolver.solve();
}

/* Write 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 : null;
String strTimeLimit = args.length > 1 ? args : "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);
}
}
}
```