feat(optimizer): masked MSE, strategy seeds, adversarial IFRA guard; add accords/materials/importer
fd5ba83 | from __future__ import annotations | |
| """ | |
| PINO fragrance accords and standard material library. | |
| Why this module exists: | |
| - Many real-world formulas contain proprietary bases (e.g., "Green Tea Base") or | |
| complex naturals (e.g., "Orris butter") that are not single CAS records. | |
| - For physics and neural critique, we decompose these into representative | |
| ingredient proxies that capture the dominant volatility and odour character. | |
| - Accords are a first-class concept so the UI and composer can start from a | |
| known base (e.g., "citrus top accord", "green tea base") instead of raw | |
| single materials. | |
| """ | |
| from dataclasses import dataclass, field | |
| from typing import Any | |
| class Accord: | |
| """A named aromatic accord represented as a weighted proxy formula.""" | |
| name: str | |
| description: str | |
| ingredients: list[dict[str, Any]] = field(default_factory=list) | |
| """ | |
| Each ingredient is {"cas": str, "name": str, "weight_fraction": float}. | |
| The fractions inside an accord sum to 1.0; they are scaled by the accord's | |
| overall weight when the accord is expanded into a full formula. | |
| """ | |
| def expand(self, overall_weight_fraction: float) -> list[dict[str, Any]]: | |
| """Return the accord's proxy formula scaled to a target weight fraction.""" | |
| return [ | |
| { | |
| "cas": item["cas"], | |
| "name": item["name"], | |
| "weight_fraction": item["weight_fraction"] * overall_weight_fraction, | |
| } | |
| for item in self.ingredients | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # Standard accords used by the UI, composer, and formula importer. | |
| # These are intentionally approximate; they encode the *olfactory character* and | |
| # *volatility class* rather than an exact GC-MS reconstruction. | |
| # --------------------------------------------------------------------------- | |
| GREEN_TEA_BASE = Accord( | |
| name="Green Tea Base", | |
| description="Fresh, leafy, slightly phenolic green tea reconstruction", | |
| ingredients=[ | |
| {"cas": "928-96-1", "name": "cis-3-Hexenol", "weight_fraction": 0.15}, | |
| {"cas": "928-97-2", "name": "cis-3-Hexenyl acetate", "weight_fraction": 0.10}, | |
| {"cas": "140-67-0", "name": "Estragole", "weight_fraction": 0.05}, | |
| {"cas": "674-86-6", "name": "Linalool oxide", "weight_fraction": 0.10}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.15}, | |
| {"cas": "110-44-1", "name": "Sorbic acid", "weight_fraction": 0.02}, | |
| {"cas": "121-33-5", "name": "Vanillin", "weight_fraction": 0.05}, | |
| {"cas": "119-64-2", "name": "Tetrahydroquinoline", "weight_fraction": 0.03}, | |
| {"cas": "4602-84-0", "name": "Farnesol", "weight_fraction": 0.05}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.10}, | |
| {"cas": "106-25-2", "name": "Nerol", "weight_fraction": 0.08}, | |
| {"cas": "5989-27-5", "name": "d-Limonene", "weight_fraction": 0.07}, | |
| {"cas": "89-43-0", "name": "Anthranilic acid", "weight_fraction": 0.05}, | |
| ], | |
| ) | |
| BLACK_TEA_BASE = Accord( | |
| name="Tea Black Base", | |
| description="Dark, smoky, phenolic black tea reconstruction", | |
| ingredients=[ | |
| {"cas": "105-95-3", "name": "Ethylene brassylate", "weight_fraction": 0.10}, | |
| {"cas": "91-64-5", "name": "Coumarin", "weight_fraction": 0.08}, | |
| {"cas": "121-33-5", "name": "Vanillin", "weight_fraction": 0.08}, | |
| {"cas": "121-34-6", "name": "Ethyl vanillin", "weight_fraction": 0.05}, | |
| {"cas": "119-36-8", "name": "Methyl salicylate", "weight_fraction": 0.07}, | |
| {"cas": "118-58-1", "name": "Benzyl salicylate", "weight_fraction": 0.10}, | |
| {"cas": "140-67-0", "name": "Estragole", "weight_fraction": 0.05}, | |
| {"cas": "89-86-1", "name": "Beta-thujone", "weight_fraction": 0.03}, | |
| {"cas": "90-05-1", "name": "Guaiacol", "weight_fraction": 0.24}, | |
| {"cas": "106-26-3", "name": "Neral", "weight_fraction": 0.05}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.08}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.07}, | |
| ], | |
| ) | |
| MATE_ABSOLUTE = Accord( | |
| name="Mate absolute", | |
| description="Dry, herbal, tea-like yerba mate reconstruction", | |
| ingredients=[ | |
| {"cas": "928-96-1", "name": "cis-3-Hexenol", "weight_fraction": 0.10}, | |
| {"cas": "928-97-2", "name": "cis-3-Hexenyl acetate", "weight_fraction": 0.08}, | |
| {"cas": "140-67-0", "name": "Estragole", "weight_fraction": 0.08}, | |
| {"cas": "99-85-4", "name": "Terpinen-4-ol", "weight_fraction": 0.08}, | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.12}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.08}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.08}, | |
| {"cas": "91-64-5", "name": "Coumarin", "weight_fraction": 0.05}, | |
| {"cas": "121-33-5", "name": "Vanillin", "weight_fraction": 0.05}, | |
| {"cas": "4602-84-0", "name": "Farnesol", "weight_fraction": 0.08}, | |
| {"cas": "7212-44-4", "name": "Nerolidol", "weight_fraction": 0.10}, | |
| {"cas": "5989-27-5", "name": "d-Limonene", "weight_fraction": 0.10}, | |
| ], | |
| ) | |
| ORRIS_BUTTER = Accord( | |
| name="Orris butter / orris CO2", | |
| description="Powdery, violet-iris orris root reconstruction", | |
| ingredients=[ | |
| {"cas": "127-42-4", "name": "Methyl ionone gamma", "weight_fraction": 0.18}, | |
| {"cas": "14901-07-6", "name": "Ionone beta", "weight_fraction": 0.12}, | |
| {"cas": "17283-81-7", "name": "Dihydro ionone beta", "weight_fraction": 0.10}, | |
| {"cas": "110-17-8", "name": "Fumaric acid", "weight_fraction": 0.02}, | |
| {"cas": "105-95-3", "name": "Ethylene brassylate", "weight_fraction": 0.15}, | |
| {"cas": "91-64-5", "name": "Coumarin", "weight_fraction": 0.08}, | |
| {"cas": "121-33-5", "name": "Vanillin", "weight_fraction": 0.05}, | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.10}, | |
| {"cas": "104-54-1", "name": "Cinnamyl alcohol", "weight_fraction": 0.05}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.05}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.05}, | |
| {"cas": "4602-84-0", "name": "Farnesol", "weight_fraction": 0.05}, | |
| ], | |
| ) | |
| CEDARWOOD_VIRGINIA = Accord( | |
| name="Cedarwood Virginia/Texas", | |
| description="Dry, woody cedarwood oil reconstruction", | |
| ingredients=[ | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.35}, | |
| {"cas": "469-01-2", "name": "Cedrene", "weight_fraction": 0.30}, | |
| {"cas": "5986-38-9", "name": "Cedryl acetate", "weight_fraction": 0.15}, | |
| {"cas": "8000-27-9", "name": "Cedarwood oil (Virginia)", "weight_fraction": 0.20}, | |
| ], | |
| ) | |
| VETIVER_HAITI = Accord( | |
| name="Vetiver Haiti", | |
| description="Earthy, smoky, woody vetiver oil reconstruction", | |
| ingredients=[ | |
| {"cas": "117-98-6", "name": "Vetiveryl acetate", "weight_fraction": 0.30}, | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.15}, | |
| {"cas": "89-78-1", "name": "Menthol", "weight_fraction": 0.03}, | |
| {"cas": "4602-84-0", "name": "Farnesol", "weight_fraction": 0.10}, | |
| {"cas": "7212-44-4", "name": "Nerolidol", "weight_fraction": 0.12}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.05}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.05}, | |
| {"cas": "5989-27-5", "name": "d-Limonene", "weight_fraction": 0.05}, | |
| {"cas": "8000-27-9", "name": "Cedarwood oil", "weight_fraction": 0.10}, | |
| {"cas": "105-95-3", "name": "Ethylene brassylate", "weight_fraction": 0.05}, | |
| ], | |
| ) | |
| AMBER_MUSK_BASE = Accord( | |
| name="Amber-Musk Base", | |
| description="Warm, clean, slightly sweet amber-musk reconstruction", | |
| ingredients=[ | |
| {"cas": "105-95-3", "name": "Ethylene brassylate", "weight_fraction": 0.20}, | |
| {"cas": "111-79-5", "name": "Habanolide", "weight_fraction": 0.15}, | |
| {"cas": "142-62-3", "name": "Ambrettolide", "weight_fraction": 0.10}, | |
| {"cas": "6790-58-9", "name": "Ambroxan", "weight_fraction": 0.15}, | |
| {"cas": "91-64-5", "name": "Coumarin", "weight_fraction": 0.08}, | |
| {"cas": "121-33-5", "name": "Vanillin", "weight_fraction": 0.07}, | |
| {"cas": "1222-05-5", "name": "Galaxolide", "weight_fraction": 0.10}, | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.10}, | |
| {"cas": "4602-84-0", "name": "Farnesol", "weight_fraction": 0.05}, | |
| ], | |
| ) | |
| CITRUS_TOP_ACCORD = Accord( | |
| name="Citrus Top Accord", | |
| description="Bright, sparkling citrus opening", | |
| ingredients=[ | |
| {"cas": "5989-27-5", "name": "d-Limonene", "weight_fraction": 0.35}, | |
| {"cas": "68647-72-3", "name": "Linalyl acetate", "weight_fraction": 0.15}, | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.10}, | |
| {"cas": "94-48-4", "name": "Bergamot oil", "weight_fraction": 0.20}, | |
| {"cas": "8008-56-8", "name": "Lemon oil", "weight_fraction": 0.15}, | |
| {"cas": "119-64-2", "name": "Tetrahydroquinoline", "weight_fraction": 0.05}, | |
| ], | |
| ) | |
| FLORAL_HEART_ACCORD = Accord( | |
| name="Floral Heart Accord", | |
| description="Clean, elegant floral bouquet", | |
| ingredients=[ | |
| {"cas": "78-70-6", "name": "Linalool", "weight_fraction": 0.20}, | |
| {"cas": "106-24-5", "name": "Geraniol", "weight_fraction": 0.15}, | |
| {"cas": "106-25-2", "name": "Nerol", "weight_fraction": 0.10}, | |
| {"cas": "8007-44-1", "name": "Jasmine absolute (proxy: benzyl acetate)", "weight_fraction": 0.15}, | |
| {"cas": "140-11-4", "name": "Benzyl acetate", "weight_fraction": 0.15}, | |
| {"cas": "104-54-1", "name": "Cinnamyl alcohol", "weight_fraction": 0.05}, | |
| {"cas": "101-86-0", "name": "alpha-Hexylcinnamaldehyde", "weight_fraction": 0.10}, | |
| {"cas": "122-97-4", "name": "Phenethyl alcohol", "weight_fraction": 0.10}, | |
| ], | |
| ) | |
| WOODY_BASE_ACCORD = Accord( | |
| name="Woody Base Accord", | |
| description="Dry, warm woody dry-down", | |
| ingredients=[ | |
| {"cas": "77-53-2", "name": "Cedrol", "weight_fraction": 0.20}, | |
| {"cas": "469-01-2", "name": "Cedrene", "weight_fraction": 0.15}, | |
| {"cas": "54452-50-3", "name": "Iso E Super", "weight_fraction": 0.25}, | |
| {"cas": "68039-33-4", "name": "Timbersilk", "weight_fraction": 0.15}, | |
| {"cas": "8000-27-9", "name": "Cedarwood oil", "weight_fraction": 0.15}, | |
| {"cas": "105-95-3", "name": "Ethylene brassylate", "weight_fraction": 0.10}, | |
| ], | |
| ) | |
| ACCORDS: dict[str, Accord] = { | |
| "green_tea": GREEN_TEA_BASE, | |
| "black_tea": BLACK_TEA_BASE, | |
| "mate": MATE_ABSOLUTE, | |
| "orris": ORRIS_BUTTER, | |
| "cedarwood": CEDARWOOD_VIRGINIA, | |
| "vetiver": VETIVER_HAITI, | |
| "amber_musk": AMBER_MUSK_BASE, | |
| "citrus_top": CITRUS_TOP_ACCORD, | |
| "floral_heart": FLORAL_HEART_ACCORD, | |
| "woody_base": WOODY_BASE_ACCORD, | |
| } | |
| def expand_accord_by_name(name: str, overall_weight_fraction: float) -> list[dict[str, Any]]: | |
| """Expand a named accord to a weight-fraction list.""" | |
| key = name.lower().replace(" ", "_").replace("/", "_") | |
| if key not in ACCORDS: | |
| raise KeyError(f"Unknown accord '{name}'. Available: {list(ACCORDS.keys())}") | |
| return ACCORDS[key].expand(overall_weight_fraction) | |