{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# OPTaaS Constraints\n", "\n", "### Note: To run this notebook, you need an API Key. You can get one here.\n", "\n", "Constraints allow you to specify relationships between the parameters you want to optimize, or just constrain the values that a parameter can take. \n", "\n", "For example, you may want an optional parameter to always be enabled if another parameter is set to `True`, or you may want an IntParameter to be between 0 and 10, but never 3." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numeric constraints\n", "You can use all the familiar numeric and comparison operators.\n", "\n", "Constraints are automatically converted to string expressions in a format that can be parsed by OPTaaS." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "#id_x < #id_y" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindfoundry.optaas.client.parameter import IntParameter\n", "from mindfoundry.optaas.client.constraint import Constraint\n", "\n", "x = IntParameter(\"x\", id=\"id_x\", minimum=0, maximum=20)\n", "y = IntParameter(\"y\", id=\"id_y\", minimum=0, maximum=20)\n", "\n", "Constraint(x 5 ) && ( #id_y >= 7 ) )" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint((x<3) | (x>5) & (y>=7))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optional parameters\n", "Use `is_present` and `is_absent` to create constraints based on whether a parameter is present in a configuration." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from mindfoundry.optaas.client.parameter import FloatParameter\n", "\n", "z = FloatParameter(\"z\", id=\"id_z\", minimum=0, maximum=1, optional=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that you can create conditional constraints that only apply when a condition is true (in this case, if `z` is present)." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "if #id_z is_present then #id_z >= ( #id_x / #id_y )" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=z.is_present(), then=z >= x/y)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "if ( #id_x == 0 ) && ( #id_y == 0 ) then #id_z is_absent" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=(x==0) & (y==0), then=z.is_absent())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Choices\n", "You can use `is_present` and `is_absent` with parameters that are part of a choice." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "from mindfoundry.optaas.client.parameter import ChoiceParameter\n", "\n", "choice = ChoiceParameter(\"xy\", [x, y], id=\"id_choice\", default=y)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "if #id_x is_present then #id_z < 0.5" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=x.is_present(), then=z<0.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use `==` and `!=` with choices:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "if #id_choice == #id_x then #id_z < 0.5" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=choice==x, then=z<0.5)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "if #id_z == 1 then #id_choice != #id_x" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=z==1, then=choice!=x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Categoricals\n", "You can use `==`, `!=`, `is_present` and `is_absent` with categoricals as well." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "if #id_abc == 'a' then #id_x == 0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindfoundry.optaas.client.parameter import CategoricalParameter\n", "\n", "abc = CategoricalParameter('abc', ['a', 'b', 'c'], id='id_abc')\n", "\n", "Constraint(when=abc == \"a\", then=x == 0)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "if #id_x > 1 then #id_abc != 'c'" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Constraint(when=x > 1, then=abc != \"c\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use them when creating a Task" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from mindfoundry.optaas.client.client import OPTaaSClient\n", "\n", "client = OPTaaSClient('https://optaas.mindfoundry.ai', '')\n", "\n", "task = client.create_task(\n", " title='My Task With Constraints', \n", " parameters=[abc, choice, z],\n", " constraints=[\n", " Constraint(when=(x==0) & (y==0), then=z.is_absent()),\n", " Constraint(when=choice==x, then=z < 0.5),\n", " Constraint(when=x==1, then=abc != \"c\")\n", " ]\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All generated configurations will obey the constraints:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'type': 'default', 'values': {'abc': 'a', 'xy': {'y': 10}, 'z': 0.5}},\n", " {'type': 'exploration', 'values': {'abc': 'a', 'xy': {'y': 10}}},\n", " {'type': 'exploration', 'values': {'abc': 'a', 'xy': {'y': 16}}},\n", " {'type': 'exploration', 'values': {'abc': 'a', 'xy': {'y': 20}}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'c', 'xy': {'x': 0}, 'z': 0.41254703404025717}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'a', 'xy': {'y': 11}, 'z': 0.8632684114311011}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'a', 'xy': {'x': 13}, 'z': 0.2981315596478492}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'a', 'xy': {'y': 6}, 'z': 0.09724688592587882}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'a', 'xy': {'y': 6}, 'z': 0.8982091428469245}},\n", " { 'type': 'exploration',\n", " 'values': {'abc': 'b', 'xy': {'x': 2}, 'z': 0.3196519301900007}}]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "task.generate_configurations(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a configuration violates a constraint, it will not be accepted:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "ename": "OPTaaSError", "evalue": "400 Configuration violates constraint: if #id_choice == #id_x then #id_z < 0.5", "output_type": "error", "traceback": [ "\u001b[1;31mOPTaaSError\u001b[0m: 400 Configuration violates constraint: if #id_choice == #id_x then #id_z < 0.5" ] } ], "source": [ "task.add_user_defined_configuration({'xy': {'x': 1}, 'z': 0.5, 'abc': 'c'})" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }