{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Analytical problem\n",
    "Defining a problem with an explicit mathematical representation is straightforward.\n",
    "\n",
    "As an example, consider the following multiobjective optimization problem:\n",
    "\n",
    "\\begin{equation}\n",
    "\\begin{aligned}\n",
    "& \\underset{\\mathbf x}{\\text{min}}\n",
    "& & x_1^2 - x_2; x_2^2 - 3x_1 \\\\\n",
    "& \\text{s.t.} & &  x_1 + x_2 \\leq 10 \\\\\n",
    "& & &  \\mathbf{x} \\; \\in S, \\\\\n",
    "\\end{aligned}\n",
    "\\end{equation}\n",
    "\n",
    "where the feasible region is\n",
    "\n",
    "\\begin{equation}\n",
    "x_i \\in \\left[-5, 5\\right] \\; \\forall i \\;\\in \\left[1,2\\right].\n",
    "\\end{equation}\n",
    "\n",
    "Begin by importing the necessary classes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from desdeo_problem import Variable, ScalarObjective, ScalarConstraint, ScalarMOProblem"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define the variables:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Args: name, starting value, lower bound, upper bound\n",
    "x1 = Variable(\"x_1\", 0, -0.5, 0.5)\n",
    "x2 = Variable(\"x_2\", 0, -0.5, 0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define the objectives, notice the argument of the callable objective function, it is assumed to be array-like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Args: name, callable\n",
    "obj1 = ScalarObjective(\"f_1\", lambda x: x[:,0]**2 - x[:,1])\n",
    "obj2 = ScalarObjective(\"f_2\", lambda x: x[:,1]**2 - 3*x[:,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define the constraints. Constraint may depend on objective function as well (second argument to the lambda, notice the underscore). In that case, the objectives should not be defined inline, like above, but as their own function definitions. The constraint should be defined so, that when evaluated, it should return a positive value, if the constraint is adhered to, and a negative, if the constraint is breached."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Args: name, n of variables, n of objectives, callable\n",
    "cons1 = ScalarConstraint(\"c_1\", 2, 2, lambda x, _: 10 - (x[:,0] + x[:,1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, put it all together and create the problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Args: list of objevtives, variables and constraints\n",
    "problem = ScalarMOProblem([obj1, obj2]\n",
    "                         ,[x1, x2]\n",
    "                         ,[cons1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, the problem is fully specified and can be evaluated and played around with."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N of objectives: 2\n",
      "N of variables: 2\n",
      "N of constraints: 1\n",
      "Single feasible decision variables: [[ 0. 10.]] with constraint values [[4.]]\n",
      "Single non-feasible decision variables: [[30. 18.]] with constraint values [[-2.]]\n",
      "Multiple decision variables: [[33. -9.]\n",
      " [13. -3.]\n",
      " [45. -5.]] with constraint values [[ 1.]\n",
      " [ 3.]\n",
      " [-1.]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "print(\"N of objectives:\", problem.n_of_objectives)\n",
    "print(\"N of variables:\", problem.n_of_variables)\n",
    "print(\"N of constraints:\", problem.n_of_constraints)\n",
    "\n",
    "res1 = problem.evaluate(np.array([2, 4]))\n",
    "res2 = problem.evaluate(np.array([6, 6]))\n",
    "res3 = problem.evaluate(np.array([[6, 3], [4,3], [7,4]]))\n",
    "\n",
    "print(\"Single feasible decision variables:\", res1.objectives, \"with constraint values\", res1.constraints)\n",
    "print(\"Single non-feasible decision variables:\", res2.objectives, \"with constraint values\", res2.constraints)\n",
    "print(\"Multiple decision variables:\", res3.objectives, \"with constraint values\", res3.constraints)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "desdeo-problem",
   "language": "python",
   "name": "desdeo-problem"
  },
  "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.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
