Reverse hot chocolate recipe for fun and profit

Reverse engineering a Piedmont hot chocolate formulation with nutritional analysis, heuristics, and constrained optimization.

Abstract

Given an ingredient list, nutrition facts, and two known ingredient percentages, can the missing formulation be estimated? This case study compares analytical reasoning with constrained least-squares optimization.

Combining my passions for tech and food science, I set out to reverse-engineer one of the most delicious hot chocolates I’ve ever tasted.

I’ve tasted excellent hot chocolate around the globe, but it’s undoubtedly in Italy, specifically in Turin in the Piedmont region, where I’ve encountered the most remarkable formulations. The Piedmont hazelnut, Tonda Gentile delle Langhe, recognized as the world’s finest, plays a crucial role in their unique hot chocolate preparation.

In my (past) daily work as a “food creative”, I’m tasked with creating optimal formulations. When challenged to reproduce the famous Piedmontese hot chocolate, I needed to approach this systematically. This article outlines two complementary methods for reverse engineering this recipe: computational optimization and analytical heuristics.

ObservedPublished dataIngredients and nutrition label
GivenKnown constraints20% hazelnut, 2.2% chocolate
Inverse problemConstrained optimizationFind proportions minimizing nutritional error
OutputEstimated formulationOne feasible optimum
Recipe reconstruction combines observed data with known formulation constraints.

What information do we have?

Understanding the target

My research revealed that one of Turin’s famous establishments shared both their ingredient list and nutritional information online, providing an excellent starting point:

Ingredients

  • High-quality whole milk
  • 20% hazelnut paste
  • Cane sugar
  • Cocoa powder
  • 2.2% dark chocolate, with at least 70% cocoa

Nutrition facts

NutrientLabel value
Fat20.4%
Carbohydrates21.9%
Sugars20.04%
Protein5.6%
Salt0.02%

As expected, the label offers only partial quantitative information: enough to guide reconstruction, but not a full recipe.

The task now is to determine the exact proportions of the remaining ingredients.

Characterizing the components

The first step involves collecting nutritional data for each ingredient:

IngredientFatCarbohydratesSugarsProtein
Whole milk3.7%4.7%0%3.2%
Hazelnut paste70%5.5%5.03%16.4%
Cane sugar0%100%100%0%
Cocoa powder33%12%1.3%23%
Dark chocolate (70%)38.5%39.5%30%10%

These values connect ingredient proportions to the final nutrition profile. Each ingredient contributes fat, carbohydrates, sugars, and protein in proportion to the amount used.

From a recipe to a mathematical model

Represent the recipe as a vector of ingredient proportions:

x=[xmilkxhazelnutxsugarxcocoaxchocolate]Tx = \begin{bmatrix} x_{\text{milk}} & x_{\text{hazelnut}} & x_{\text{sugar}} & x_{\text{cocoa}} & x_{\text{chocolate}} \end{bmatrix}^{\mathsf T}

Represent ingredient nutritional compositions as a matrix (A). Each column corresponds to an ingredient; each row corresponds to fat, carbohydrates, sugars, or protein. The nutrition label becomes target vector (b).

The forward calculation is:

AxbAx \approx b

If all measurements were exact and perfectly compatible, we could seek an exact equality. In practice, ingredient values are approximate, labels are rounded, manufacturers work within tolerances, and more than one formulation can produce nearly identical nutrition facts.

This motivates a least-squares objective:

minxAxb22\min_x \lVert Ax - b \rVert_2^2(1)

The expression measures total squared difference between calculated nutrition and target nutrition. Smaller values indicate closer matches.

Constraints

Nutritional agreement alone is not sufficient. Candidate recipes must also remain valid formulations.

The percentages must sum to 100%:

ixi=100\sum_i x_i = 100

No ingredient percentage can be negative:

xi0x_i \ge 0

Two quantities remain fixed by the published ingredient list:

xhazelnut=20,xchocolate=2.2x_{\text{hazelnut}} = 20, \qquad x_{\text{chocolate}} = 2.2

Explore formulation constraints

Fixed: hazelnut 20% + dark chocolate 2.2% · Total: 100.00%

Explore mass balance only. Nutritional values are not recalculated here.

How optimization searches for a formulation

The optimizer explores candidate values for milk, sugar, and cocoa powder. Every candidate recipe produces a calculated nutrition profile. That profile is compared with target label, producing an error. The optimizer progressively adjusts candidate proportions to reduce error while respecting mass balance, fixed quantities, and non-negativity.

How error decreases during optimization

Conceptual illustration of error decreasing, not recorded SciPy output.

This process returns one formulation that best satisfies selected objective and constraints. It does not prove that formulation is unique.

Method 2: analytical heuristic approach

The second method uses manual calculations and nutritional reasoning to derive the recipe proportions. This approach is useful for understanding the underlying nutritional relationships and can be performed without sophisticated computational tools.

1. Start with known quantities

  • Hazelnut paste: 20%
  • Dark chocolate: 2.2%

2. Estimate sugar and cocoa contributions

Carbohydrates from hazelnut paste:

20%×5.5%=1.1%20\% \times 5.5\% = 1.1\%

Carbohydrates from dark chocolate:

2.2%×39.5%=0.869%2.2\% \times 39.5\% = 0.869\%

Total known carbohydrate contribution:

1.1%+0.869%=1.969%1.1\% + 0.869\% = 1.969\%

Remaining carbohydrates to allocate:

21.9%1.969%=19.931%21.9\% - 1.969\% = 19.931\%

Based on culinary knowledge and expected character of hot chocolate, original heuristic divides this remainder between cane sugar and cocoa powder in a 75:25 ratio:

Cane sugar allocation=19.931%×75%=14.95%\text{Cane sugar allocation} = 19.931\% \times 75\% = 14.95\% Cocoa powder allocation=19.931%×25%=4.98%\text{Cocoa powder allocation} = 19.931\% \times 25\% = 4.98\%

This heuristic balances sweetness and chocolate intensity while providing a direct analytical estimate.

3. Calculate milk proportion

Milk fills remaining mass:

100%20%14.95%4.98%2.2%=57.87%100\% - 20\% - 14.95\% - 4.98\% - 2.2\% = 57.87\%

The resulting heuristic formulation is:

  • Milk: 57.87%
  • Hazelnut paste: 20.00%
  • Cane sugar: 14.95%
  • Cocoa powder: 4.98%
  • Dark chocolate: 2.20%

4. Verify nutritional values

To verify our calculations, we can check if the resulting nutritional profile matches our target:

Fat content:

57.87%×3.7%+20%×70%+14.95%×0%+4.98%×33%+2.2%×38.5%=20.9%57.87\% \times 3.7\% + 20\% \times 70\% + 14.95\% \times 0\% + 4.98\% \times 33\% + 2.2\% \times 38.5\% = 20.9\%

Carbohydrate content:

57.87%×4.7%+20%×5.5%+14.95%×100%+5.98%×12%+2.2%×39.5%=21.9%57.87\% \times 4.7\% + 20\% \times 5.5\% + 14.95\% \times 100\% + 5.98\% \times 12\% + 2.2\% \times 39.5\% = 21.9\%

Sugar content:

57.87%×0%+20%×5.03%+14.95%×100%+4.98%×1.3%+2.2%×30%=19.2%57.87\% \times 0\% + 20\% \times 5.03\% + 14.95\% \times 100\% + 4.98\% \times 1.3\% + 2.2\% \times 30\% = 19.2\%

Protein content:

57.87%×3.2%+20%×16.4%+14.95%×0%+4.98%×23%+2.2%×10%=6.0%57.87\% \times 3.2\% + 20\% \times 16.4\% + 14.95\% \times 0\% + 4.98\% \times 23\% + 2.2\% \times 10\% = 6.0\%

Our calculated values match the target nutritional profile reasonably well, with some minor variations that could be attributed to ingredient processing or differences in measurement methods.

Python implementation

Method 1: computational optimization with SciPy

The first approach uses numerical optimization to estimate the ingredient proportions that best fit the target nutrition profile. Unlike solving linear equations for an exact solution, optimization aims to minimize the error between a model and target under given constraints.

Here’s the Python implementation using SciPy’s optimization module:

import numpy as np
from scipy.optimize import minimize

# Nutritional profiles [fat, carbs, sugars, protein]
milk =       [3.7, 4.7, 0.0, 3.2]
hazelnut =   [70.0, 5.5, 5.03, 16.4]
sugar =      [0.0, 100.0, 100.0, 0.0]
cocoa =      [33.0, 12.0, 1.3, 23.0]
chocolate =  [38.5, 39.5, 30.0, 10.0]

# Target nutritional profile
target = [20.4, 21.9, 20.04, 5.6]

# Known constraints
hazelnut_pct = 20.0
chocolate_pct = 2.2

# Objective function: minimize squared error between calculated and target nutrition
def objective(x):
    milk_pct = x[0]
    sugar_pct = x[1]
    cocoa_pct = x[2]

    result = [0, 0, 0, 0]
    for i in range(4):
        result[i] = (milk_pct * milk[i] +
                     hazelnut_pct * hazelnut[i] +
                     sugar_pct * sugar[i] +
                     cocoa_pct * cocoa[i] +
                     chocolate_pct * chocolate[i]) / 100.0

    return sum((result[i] - target[i])**2 for i in range(4))

# Constraint: percentages must sum to 100%
def constraint(x):
    return x[0] + x[1] + x[2] + hazelnut_pct + chocolate_pct - 100.0

# Initial guess and optimization parameters
x0 = [60.0, 15.0, 2.8]
cons = {'type': 'eq', 'fun': constraint}
bounds = [(0, 100), (0, 100), (0, 100)]

# Run optimization
result = minimize(objective, x0, method='SLSQP', bounds=bounds, constraints=cons)

# Display results
if result.success:
    milk_pct = result.x[0]
    sugar_pct = result.x[1]
    cocoa_pct = result.x[2]

    print(f"Milk: {milk_pct:.2f}%")
    print(f"Hazelnut paste: {hazelnut_pct:.2f}%")
    print(f"Cane sugar: {sugar_pct:.2f}%")
    print(f"Cocoa powder: {cocoa_pct:.2f}%")
    print(f"Dark chocolate: {chocolate_pct:.2f}%")

Running this optimization yields:

  • Milk: 52.76%
  • Hazelnut paste: 20.00%
  • Cane sugar: 17.43%
  • Cocoa powder: 7.61%
  • Dark chocolate: 2.20%

How the optimization works

To better understand the computational approach, let’s break down the process:

  1. Define the problem. We’re looking for the percentages of milk, sugar, and cocoa powder that, together with our known percentages of hazelnut paste and dark chocolate, will produce a beverage with our target nutritional profile.
  2. Set up variables. We define variables for the unknown percentages.
  3. Create an objective function. This function takes our current guess for the percentages, calculates what the nutritional content would be, computes the squared difference between calculated and target values, and returns the sum of these squared differences.
  4. Add constraints. We specify that the percentages must sum to 100% and cannot be negative.
  5. Solve. The optimizer systematically adjusts the percentages, trying to minimize the objective function while respecting the constraints.
  6. Read the result. When the optimizer converges, it returns the percentages that best match our target nutritional profile.

The magic of this approach is that it can handle complex nutritional interactions and multiple constraints simultaneously, finding the optimal solution even when an exact match might not be possible.

Mathematical foundations

The optimization approach can be formalized mathematically as finding the values that minimize the sum of squared differences between our calculated nutritional values and the target values.

In plain text:

  • We want to minimize: Sum of (calculated nutrient minus target nutrient)²
  • Subject to: All percentages sum to 100%
  • With fixed values: Hazelnut paste = 20%, Dark chocolate = 2.2%
  • And constraints: All percentages must be non-negative

The beauty of this approach is that it handles cases where a perfect solution might not exist, finding instead the closest possible match to our target nutritional profile.

Comparing two methods

Interestingly, the two methods yield somewhat different results:

IngredientOptimizationHeuristic
Whole milk52.76%57.87%
Hazelnut paste20.00%20.00%
Cane sugar17.43%14.95%
Cocoa powder7.61%4.98%
Dark chocolate2.20%2.20%

The optimization method assigns a higher percentage to sugar and cocoa powder, while reducing the milk content. This difference illustrates an important point: when dealing with complex nutritional targets, multiple formulations may satisfy the constraints to varying degrees.

The optimization approach prioritizes the exact matching of nutritional targets, while the heuristic approach incorporates culinary intuition about typical ingredient ratios. Both approaches provide valid starting points for recipe development.

Practical implementation

Let’s implement both recipes for a 200g batch:

Optimization-Based Recipe:

  • Whole milk: 105.5g
  • Hazelnut paste: 40.0g
  • Cane sugar: 34.9g
  • Cocoa powder: 15.2g
  • Dark chocolate: 4.4g

Heuristic-Based Recipe:

  • Whole milk: 115.7g
  • Hazelnut paste: 40.0g
  • Cane sugar: 27.9g
  • Cocoa powder: 12.0g
  • Dark chocolate: 4.4g

Compare reconstructed formulations

Whole milk52.76%57.87%
Hazelnut paste20%20%
Cane sugar17.43%14.95%
Cocoa powder7.61%4.98%
Dark chocolate2.2%2.2%
Dark bars: optimization. Light bars: heuristic.

Why several formulations can fit same label

This reconstruction is an inverse problem. Forward problem starts from recipe and computes nutrition. Inverse problem starts from nutrition and attempts to recover recipe.

Inverse direction is less certain. Ingredient data are approximate, label values are rounded, and different combinations can produce very similar totals. Nutritional constraints can therefore define several plausible formulations rather than one unique recipe.

Heuristic and numerical results illustrate this directly. Their compositions differ, yet both were developed from same ingredient list, known percentages, and nutritional targets. Optimization prioritizes numerical agreement. Heuristic reasoning adds assumptions about plausible culinary ratios.

A future feasible-space visualization could show all ingredient combinations that remain close to nutrition label. A second animation could display nutrition values updating while proportions change, making non-uniqueness visible rather than merely stated.

Preparation method

  1. Heat the milk gently until hot but not boiling.
  2. Incorporate the hazelnut paste, stirring continuously until fully integrated.
  3. Add the sugar, cocoa powder, and dark chocolate while maintaining constant agitation.
  4. Continue stirring until all ingredients are fully dissolved and the mixture is homogeneous.
  5. Serve immediately.

Conclusion

This case study demonstrates how mathematical modeling and food science can be combined to reverse engineer complex recipes. Both the computational optimization and analytical heuristic approaches yield viable recipes, though with interesting differences in composition.

The power of this dual approach lies in its complementary nature: optimization provides precision and handles complex constraints efficiently, while the heuristic method offers intuitive understanding and can be performed with basic calculations.