{ "info": { "author": "Micha\u0142 Jaworski", "author_email": "swistakm@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3" ], "description": "|Build Status| |Coverage Status|\n\nfrules - simple functional fuzzy rules\n======================================\n\nFrules stands for **fuzzy/funtional rules**. It allows to work easily\nwith fuzzy rules and variables.\n\nInstallation:\n\n::\n\n pip install frules\n\nLinguistic variables and expressions\n------------------------------------\n\nExpression is a core concept in frules. ``Expression`` class represents\nsubrange of `linguistic\nvariable `__\nin fuzzy logic.\n\nVariables in classical math take numerical values. in fuzzy logic, the\n*linguistic variables* are non-numeric and are described with\nexpressions. Expressions map continuous variable like nemerical\ntemperature to its linguistic counterpart. For example temperature can\nbe described as cold, warm or hot. There is no strict boundary between\ncold and warm - this is why this expressions are fuzzy.\n\nTo create new expression we use function that takes numerical value of\ncontiunous variable and returns *truth value*. Truth value ranges\nbetween 0 and 1 - it's a degree of membership of continous value to that\nlinguistic variable.\n\n.. code:: python\n\n from frules.expressions import Expression\n #We know that anything over 50 degrees is hot and below 40 is't hot\n hot = Expression(lambda x: min(1, max((x - 40) / 10., 0)))\n\nThis ugly lambda is representation of some fuzzy set. If we take a look\nhow it behaves, we'll see that it in fact returns 1 for anything over\n50, 0 for anything below 40 and some linear values between 40 and 50:\n\n.. code:: python\n\n >>> map(lambda x: {x: min(1, max((x - 40) / 10., 0))}, xrange(35, 55, 2))\n [{35: 0}, {37: 0}, {39: 0}, {41: 0.1}, {43: 0.3}, {45: 0.5}, {47: 0.7}, {49: 0.9}, {51: 1}, {53: 1}\n\nUsing a lot of lambdas in practice makes your code a mess. Fuzzy\nexpressions described this way are additionally hard to write because of\nsome value assertions they must satisfy.\n\nThis is why we ancapsulate don't use raw functions and encapsulate them\nwith expressions. Moreover frules provides a bunch of helpers that eases\ndefinition of new expressions. Example of full set of expressions for\ntemperature variable could look this way:\n\n.. code:: python\n\n from frules.expressions import Expression as E\n from frules.expressions import ltrapezoid, trapezoid, rtrapezoid\n\n cold = E(ltrapezoid(10, 20), \"cold\") # anything below 10, more is fuzzy\n warm = E(trapezoid(10, 20, 30, 35), \"warm\") # anything between 20 and 30\n hot = E(rtrapezoid(30, 35), \"hot\") # anything over 35, less is fuzzy\n\nExpressions can be reused/mixed using logical operators:\n\n.. code:: python\n\n cold_or_hot = cold || warm\n not_hot = !hot\n\nOptional names will be helpful when we start to work with fuzzy rules.\n\nFuzzy rules\n-----------\n\nAlthough expressions define linguistic variables, they aren't strictly\nbound to any variable. They are rather the adjectives we use to describe\nsomething and their meaning depends strictly on context. Both *person*\nand *data* could be *big* but this particular adjective has slighlty\ndifferent meaning in each case.\n\n``Rule`` objects bounds continous variable with expressions. Rules also\ncan also be evaluated to see how true they are for given continous\ninput.\n\n::\n\n >>> from frules.rules import Rule\n >>> is_hot = Rule(temperature=hot)\n >>> is_hot.eval(temperature=5)\n 0.8\n\nRules can be mixed using logical operators (``&`` and ``|``) to create\nmore sophisticated rules that allow fuzzy reasoning:\n\n.. code:: python\n\n from frules.expressions import Expression as E\n from frules.rules import Rule as R\n from frules.expressions import ltrapezoid, trapezoid, rtrapezoid\n\n # car age expressions\n old = E(ltrapezoid(2001, 2008), \"old\")\n new = E(rtrapezoid(2013, 2014), \"new\")\n not_so_old = - (old & new)\n\n # power expressions\n strong = E(rtrapezoid(50, 100), \"strong\")\n weak = E(ltrapezoid(50, 100), \"weak\")\n\n # price expression\n expensive = E(rtrapezoid(25000, 30000), \"expensive\")\n cheap = - expensive\n\n # yes expression\n yes = E(lambda yes: float(yes), \"yes\") # converts bool to float\n\n\n # rules\n is_attractive = R(production_year=not_so_old) & R(horsepower=strong)\n should_buy = is_attractive & R(price=cheap)\n\nHaving such set of rules we can do some reasoning:\n\n::\n\n >>> should_buy\n (((age = !(old & new) & horsepower = strong) & !None = None) & cost = !expensive)\n >>> should_buy.eval(horsepower=70, production_year=2012, price=15000)\n 0.4\n >>>\n >>> candidates = {\n ... \"car1\": {\"horsepower\": 70, \"production_year\": 2012, \"price\": 15000},\n ... \"car2\": {\"horsepower\": 150, \"production_year\": 2010, \"price\": 30000},\n ... \"car3\": {\"horsepower\": 90, \"production_year\": 2014, \"price\": 10000},\n ... \"car4\": {\"horsepower\": 85, \"production_year\": 2009, \"price\": 35000},\n ... }\n >>> max(candidates.iteritems(), key=lambda (key, inputs): is_hot.eval(**inputs))\n ('car3', {'horsepower': 90, 'price': 10000, 'production_year': 2014})\n\n.. |Build Status| image:: https://travis-ci.org/swistakm/frules.svg?branch=master\n :target: https://travis-ci.org/swistakm/frules\n.. |Coverage Status| image:: https://coveralls.io/repos/swistakm/frules/badge.svg?branch=master\n :target: https://coveralls.io/r/swistakm/frules?branch=master", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/swistakm/frules", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "frules", "package_url": "https://pypi.org/project/frules/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/frules/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/swistakm/frules" }, "release_url": "https://pypi.org/project/frules/0.1.2/", "requires_dist": null, "requires_python": null, "summary": "simple functional fuzzy rules implementation", "version": "0.1.2" }, "last_serial": 1599114, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "7a40fdb5961898a34811cbb0bba6eda7", "sha256": "ac1d0a892c291999c86aa3ecf91fc3201d88356e3ebb65ba718656a0d096f3f9" }, "downloads": -1, "filename": "frules-0.0.1.tar.gz", "has_sig": false, "md5_digest": "7a40fdb5961898a34811cbb0bba6eda7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6230, "upload_time": "2014-02-27T15:11:18", "url": "https://files.pythonhosted.org/packages/48/de/154daed73fa1f86ebbfe24ae20f0f06e40c14769d487123e500be24e2cbd/frules-0.0.1.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "45a1184a0637cdb19864fb62a9c4fb70", "sha256": "76caaa93e34614a64de552b1bc35467a2e4d0e715e4e1a3cbc3f58fc2e570ccb" }, "downloads": -1, "filename": "frules-0.1.0.tar.gz", "has_sig": false, "md5_digest": "45a1184a0637cdb19864fb62a9c4fb70", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8080, "upload_time": "2014-02-28T14:53:29", "url": "https://files.pythonhosted.org/packages/a3/9e/d156bd645970778897079f060b1aa26c86c49e1c9fac6ccff8fe65786b80/frules-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "ea73133c60a9874e955085b46316b5ff", "sha256": "68879770bd9d412f07b30eadc7e3a7fd69c82f25b5b2c956127ec406045d4606" }, "downloads": -1, "filename": "frules-0.1.1.tar.gz", "has_sig": false, "md5_digest": "ea73133c60a9874e955085b46316b5ff", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8532, "upload_time": "2014-05-16T15:04:18", "url": "https://files.pythonhosted.org/packages/89/a1/31bb80c5a140f6368f50b3d34c7c1f3a4423a7c0b5e78504ac71c6704257/frules-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "540441f77adc2b9fb451f932090451d1", "sha256": "74a8b27ed3f3dba25583c0678831cbd28147b02874c899397f0678cfbbce6761" }, "downloads": -1, "filename": "frules-0.1.2.tar.gz", "has_sig": false, "md5_digest": "540441f77adc2b9fb451f932090451d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9403, "upload_time": "2015-06-19T14:30:25", "url": "https://files.pythonhosted.org/packages/12/ee/f8ab2adfcd67744311fe43c775d21489a1a3ca31ece509135e29099f4ae7/frules-0.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "540441f77adc2b9fb451f932090451d1", "sha256": "74a8b27ed3f3dba25583c0678831cbd28147b02874c899397f0678cfbbce6761" }, "downloads": -1, "filename": "frules-0.1.2.tar.gz", "has_sig": false, "md5_digest": "540441f77adc2b9fb451f932090451d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9403, "upload_time": "2015-06-19T14:30:25", "url": "https://files.pythonhosted.org/packages/12/ee/f8ab2adfcd67744311fe43c775d21489a1a3ca31ece509135e29099f4ae7/frules-0.1.2.tar.gz" } ] }