{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-0",
   "metadata": {},
   "source": [
    "# Hosaki函数\n",
    "\n",
    "**类别：** 仿真优化\n",
    "\n",
    "使用 OptAgent 的 Python 接口描述变量、约束与目标。\n",
    "\n",
    "问题与原始示例来源：[Hexaly Code Templates](https://www.hexaly.com/templates/hosaki-function)。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-1",
   "metadata": {},
   "source": [
    "## 问题描述\n",
    "\n",
    "**Hosaki函数**由下式定义：\n",
    "\n",
    "$$f(x_1, x_2) = \\left(1 - 8x_1 + 7x_1^2 - \\frac{7}{3}x_1^3 + \\frac{1}{4}x_1^4\\right)x_2^2 e^{-x_2}$$\n",
    "\n",
    "这是一个盒约束问题。变量 x1 和 x2 的定义域分别为 [0, 5] 和 [0, 6]。问题的目标是找到该函数的最小值。更多细节，请参阅 [hosaki_function.html](http://jakobbossek.github.io/smoof/reference/makeHosakiFunction.html)。\n",
    "\n",
    "### 学习要点\n",
    "\n",
    "- 使用 OptAgent 的 `create_double_external_function` 表达外部函数\n",
    "- 使用浮点决策变量表示连续定义域\n",
    "- 使用时间上限控制求解预算\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-2",
   "metadata": {},
   "source": [
    "## 建模思路\n",
    "\n",
    "Hosaki函数问题的 OptAgent 模型使用两个 浮点决策变量：x1 和 x2。这些变量的定义域分别为 [0, 5] 和 [0, 6]。\n",
    "\n",
    "该问题没有任何约束条件，只有一个需要最小化的目标函数。目标函数由 external function 定义。OptAgent 回调通过上下文读取 x1 和 x2 的候选值，并返回该函数在对应点的值；模型随后直接最小化这个 external call 表达式。\n",
    "\n",
    "本示例使用 `solve(model, time_limit_s=...)` 限制求解时间。需要控制外部函数的新评价次数时，可使用求解接口的 `external_evaluation_limit` 参数。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-3",
   "metadata": {},
   "source": [
    "## Python 实现\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-4",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "from pathlib import Path\n",
    "\n",
    "from optagent import OptModel, solve\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "#\n",
    "# External function\n",
    "#\n",
    "def hosaki_function(argument_values):\n",
    "    x1 = argument_values[0]\n",
    "    x2 = argument_values[1]\n",
    "    return (1 - 8 * x1 + 7 * pow(x1, 2) - 7 * pow(x1, 3) / 3 + pow(x1, 4) / 4) * pow(x2, 2) * math.exp(-x2)\n",
    "\n",
    "\n",
    "def main(output_file=None, time_limit=1):\n",
    "    model = OptModel()\n",
    "\n",
    "    # Numerical decisions\n",
    "    x1 = model.float(0, 5)\n",
    "    x2 = model.float(0, 6)\n",
    "\n",
    "    # Preserve the original black-box model: evaluate Hosaki through an\n",
    "    # external callback rather than rewriting it as a native expression.\n",
    "    external_hosaki = model.create_double_external_function(hosaki_function)\n",
    "    func_call = external_hosaki(x1, x2)\n",
    "    model.minimize(func_call)\n",
    "\n",
    "    # Limit this example by wall-clock time; the objective stays an external call.\n",
    "    solution = solve(model, time_limit_s=float(time_limit))\n",
    "    if not solution.feasible:\n",
    "        raise RuntimeError(f\"No feasible solution found: {solution.feasible}\")\n",
    "\n",
    "    values = {'objective': func_call.value, 'x1': x1.value, 'x2': x2.value}\n",
    "    result_text = f\"obj={values['objective']:.6f}\\nx1={values['x1']:.6f}\\nx2={values['x2']:.6f}\"\n",
    "    print(f\"Status = {solution.feasible}\\n{result_text}\")\n",
    "\n",
    "    if output_file is not None:\n",
    "        Path(output_file).write_text(result_text + \"\\n\", encoding=\"utf-8\")\n",
    "    return solution\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-5",
   "metadata": {},
   "source": [
    "## 本地运行\n",
    "\n",
    "Hosaki 函数不需要外部实例文件，直接调用 `main` 即可。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-6",
   "metadata": {},
   "outputs": [],
   "source": [
    "solution = main(time_limit=1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
