Optimisation de recettes via le solveur linaire

La fonction @glop.optimize() permet de calculer la recette en maximisant ou minimisant une certaine caractéristique sous certaines contraintes.

@glop.optimize({target: {var: nut['Protéines'], task: "max"}, constraints: {
               {var: "recipeQtyUsed", min: 1, max: 1},
               {var: compo['Cerise, dénoyautée, crue'], min: 0.3, max: "inf"},
               {var: compo['Beurre à 82% MG, doux'], min: 0.05, max: 0.2},
               {var: compo['Pâte brisée, crue'], min: 0.1, max: 0.3},
               {var: compo['Farine de blé tendre ou froment T45 (pour pâtisserie)'], min: 0.125, max: 0.2},
               {var: compo['Sucre blanc'], min: 0.05, max: 0.2}
               }})

Dans cet exemple, on cherche à maximiser la quantité de protéines en imposant des encadrements pour chaque ingrédient ainsi qu'une quantité totale égale à 1.

L'argument est un objet avec la structure suivante :

  • target spécifie l'objectif de l'optimisation et contient les paramètres :
    • var spécifiant la charactéristique à optimiser,
    • task valant "min" ou "max" selon qu'il faille la minimiser ou la maximiser ;
  • constraints est un ensemble d'objets spécifiant des contraintes à respecter pour l'optimisation et dont chacune d'elles contient les champs :
    • var spécifiant l'objet de la contrainte,
    • min désignant la valeur minimale acceptée pour cet objet, ou "-inf" (avec les guillemets) si pas de valeur minimale,
    • max désignant la valeur maximale acceptée pour cet objet, ou "inf" (avec les guillemets) si pas de valeur maximale.

Les caractéristiques supportées sont  :

  • les compositions (compo[]) ;
  • les nutriments (nut[]) ;
  • les coûts (cost[]) ;
  • les allergènes (allergen[]) ;
  • les ingrédients (ing[]).

Les objets de contraintes sont soit des caractéristiques, soit des identifiants de contraintes spéciales. Une contrainte spéciale nécessite plusieurs caractéristiques pour la définir. Actuellement, la seule implémentée est "recipeQtyUsed" qui est la somme de toutes les quantités de composants dans la recette.

Le résultat de cette fonction est un objet contenant :

  • coefficients qui indique la quantité de chaque composant dans la formule optimisée, en excluant les composants dont la quantité calculée est zéro ;
  • value qui indique la valeur de la fonction d'objectif pour la recette optimisée ;
  • status qui vaut optimal si la recette calculée est optimale et feasible si elle vérifie toutes les contraintes sans être garantie optimale.

S'il est impossible de respecter toutes les contraintes spécifiées, alors l'appel à @glop.optimize() échoue avec l'erreur Linear program is unfeasible.

Exemple d'optimisation avec le service Glop

Prenons par exemple une recette constituée de 5 ingrédients : ing1, ing2, ing3, ing4 et ing5.

Chaque ingrédient possède des caractéristiques physico-chimiques (PC) et un coût qui lui sont propres, voici un tableau définissant la constitution des ingrédients :

IngrédientPC1PC2PC3PC4Coût unitaire
ing16530281008
ing27028301008
ing36528.5601008
ing41000001
ing56733670100

On cherche à minimiser le coût total de la recette avec les contraintes suivantes :

  • le volume totale doit être de 1000 (unité arbitraire)
  • PC1 doit être compris entre 70000 et 80000
  • PC2 est une quantité expimée en pourcentages et doit être comprise entre 20% et 30%
  • PC3 doit être compris entre 40000 et 50000
  • PC4 doit être compris entre 70000 et 80000
  • ing1 doit être compris entre 1% et 100% (du volume total)
  • ing2 doit être compris entre 1% et 100% (du volume total)
  • ing3 doit être compris entre 10 et 1000
  • ing4 doit être compris entre 10% et 25% (du volume total)
  • ing5 doit être compris entre 50% et 100% (du volume total)

Le formule qui doit être entrée est la suivante :

@glop.optimize({target: {var:   cost['Coût'], task: "min"}, constraints: {
               {var:    physico['PC1'] , min: 70000, max: 80000},
               {var:    physico['PC2'], min: 20000, max: 30000},
               {var:    physico['PC3'], min: 40000, max: 50000},
               {var:    physico['PC4'], min: 70000, max: 80000},
               {var:    compo['ing1'], min: 10, max:1000},
               {var:    compo['ing2'], min: 10, max:1000},
               {var:    compo['ing3'], min: 10, max:1000},
               {var:    compo['ing4'], min: 100, max:250},
               {var:    compo['ing5'], min: 500, max:1000},
               {var: "recipeQtyUsed", min: 1000, max: 1000}
               }})

Comme la caractéristique physico-chimique PC2 est exprimée en pourcentages dans beCPG (par exemple : taux de glucides) il faut multiplier ses contraintes par la quantité totale voulue car le système ne peut pas savoir qu'il s'agit d'un rapport sur le volume, on a donc PC2 min = 20 x 1000 = 20000 et PC2 max = 30 x 1000 = 30000

Le résultat obtenu dans la formule SPEL est le suivant :

{coefficients={ing1=157.81249999999991, ing4=250.0, ing3=532.1875, ing2=10.0, ing5=50.0}, value=10850.0, status=optimal}

Le résultat affiché est 10850.0, il s'agit du coût total minimisé.

results matching ""

    No results matching ""