private void calcProduction() {
        Arrays.fill(productionHolder, 0);
        for (Pattern pattern : plan.getPatterns()) {
            for (int i = 0; i < problem.size(); i++) {
                productionHolder[i] += pattern.getProduction(i);
            }
        }

        cachedUnderproductionAmount = 0;
        cachedOverproductionAmount = 0;
        cachedAverageUnderproductionRatio = 0;
        cachedMaximumUnderproductionRatio = 0;
        cachedAverageOverproductionRatio = 0;
        cachedMaximumOverproductionRatio = 0;
        for (int i = 0; i < problem.size(); i++) {
            int produced = productionHolder[i];
            int ordered = problem.getOrder(i).getQuantity();
            if (ordered > produced) {
                // underproduction
                cachedUnderproductionAmount += ordered - produced;

                double underproductionRatio = (ordered - produced) / (double) ordered;
                cachedAverageUnderproductionRatio += underproductionRatio;

                if (underproductionRatio > cachedMaximumUnderproductionRatio) {
                    cachedMaximumUnderproductionRatio = underproductionRatio;
                }
            } else {
                // overproduction
                cachedOverproductionAmount += produced - ordered;

                double overproductionRatio = (produced - ordered) / (double) ordered;
                cachedAverageOverproductionRatio += overproductionRatio;
                if (overproductionRatio > cachedMaximumOverproductionRatio) {
                    cachedMaximumOverproductionRatio = overproductionRatio;
                }
            }
        }

        cachedAverageUnderproductionRatio /= problem.size();
        cachedAverageOverproductionRatio /= problem.size();
    }