Search code examples
javascriptoptimizationmathematical-optimizationcalculus

The maximum volume of a box


Trying to write a simple web app to solve the following common calculus problem in JavaScript.

Suppose you wanted to make an open-topped box out of a flat piece of cardboard that is L long by W wide by cutting the same size square (h × h) out of each corner and then folding the flaps to form the box, as illustrated below:

box_vol_problem

You want to find out how big to make the cut-out squares in order to maximize the volume of the box.

Ideally I want to avoid using any calculus library to solve this.

My initial naive solution:

// V = l * w * h
function getBoxVolume(l, w, h) {
  return (l - 2*h)*(w - 2*h)*h;
}

function findMaxVol(l, w) {
  const STEP_SIZE = 0.0001;

  let ideal_h = 0;
  let max_vol = 0;

  for (h = 0; h <= Math.min(l, w) / 2; h = h + STEP_SIZE) {
    const newVol = getBoxVolume(l, w, h);
    if (max_vol <= newVol) {
      ideal_h = h;
      max_vol = newVol;
    } else {
      break;
    }
  }

  return {
    ideal_h,
    max_vol
  }
}

const WIDTH_1 = 20;
const WIDTH_2 = 30;

console.log(findMaxVol(WIDTH_1, WIDTH_2))

// {
//   ideal_h: 3.9237000000038558,
//   max_vol: 1056.3058953402121
// }

The problem with this naive solution is that it only gives an estimate because you have to provide STEP_SIZE and it heavily limits the size of the problem this can solve.


Solution

  • After realising that the derivative of the volume function is a second degree polynomial you can apply a quadratic formula to solve for x.

    Using calculus, the vertex point, being a maximum or minimum of the function, can be obtained by finding the roots of the derivative

    // V = l * w * h
    function getBoxVolume(l, w, h) {
      return (l - 2*h)*(w - 2*h)*h;
    }
    
    // ax^2 + bx + c = 0
    function solveQuad(a, b, c) {
      var x1 = (-1 * b + Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
      var x2 = (-1 * b - Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
      return { x1, x2 };
    }
    
    function findMaxVol(l, w) {    
      // V'(h) = 12h^2-4(l+w)h+l*w - second degree polynomial
      // solve to get the critical numbers
      const result = solveQuad(12, -4*(l + w), l*w)
    
      const vol1 = getBoxVolume(l, w, result.x1);
      const vol2 = getBoxVolume(l, w, result.x2);
    
      let ideal_h = 0;
      let max_vol = 0;
    
      // check for max
      if (vol1 > vol2) {
        ideal_h = result.x1;
        max_vol = vol1;
      } else {
        ideal_h = result.x2;
        max_vol = vol2;
      }
    
      return {
        ideal_h,
        max_vol
      } 
    }
    
    const WIDTH_1 = 20;
    const WIDTH_2 = 30;
    
    console.log(findMaxVol(WIDTH_1, WIDTH_2))
    
    // {
    //   ideal_h: 3.9237478148923493,
    //   max_vol: 1056.30589546119
    // }