{ "info": { "author": "Christian Stigen Larsen", "author_email": "csl@csl.name", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Education", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Forth", "Programming Language :: Other", "Programming Language :: Python", "Programming Language :: Python :: 2 :: Only", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Code Generators", "Topic :: Software Development :: Compilers", "Topic :: Software Development :: Interpreters", "Topic :: Software Development :: Libraries", "Topic :: Utilities" ], "description": "Crianza\n-------\n\nCrianza is a very simple program virtual machine with example genetic\nprogramming applications.\n\nIt comes both with a command line program (for running programs and starting a\nREPL) and as a Python module so you can create and run programs from Python.\nThe ``crianza.genetic`` module contains a simple genetic programming framework.\n\nThis project originated from a blog post I wrote at https://csl.name/post/vm/\n(it details how you can write your own interpreter from scratch) and is hosted\non https://github.com/cslarsen/crianza\n\nThe VM contains:\n\n- An interpreter for a Forth-like stack-based language\n- Some simple peephole optimizations\n- Simple correctness checking\n- Compilation from source language down to virtual machine language\n- Threaded code interpretation\n- Data types: Integers, floats, booleans and strings\n- An experimental, in-progress compiler to native Python bytecode\n\nThe genetic programming part uses a simple evolutionary approach with\ncrossover and weighted Tanimoto coefficients to relate fitness scores.\n\nThe project's main goal is to be tutorial and fun.\n\nInstalling\n----------\n\nInstall from PyPI::\n\n $ pip install crianza\n\nor from the repository::\n\n $ git clone https://github.com/cslarsen/crianza.git\n $ cd crianza\n $ python setup.py install\n\nExample: Using crianza from the command line\n--------------------------------------------\n\nJust type ``crianza -r`` or ``crianza --repl`` to start the interpreter. In\nthis example, we want to calculate ``(2+3)*4``::\n\n $ crianza -r\n Extra commands for the REPL:\n .code - print code\n .raw - print raw code\n .quit - exit immediately\n .reset - reset machine (IP and stacks)\n .restart - create a clean, new machine\n .clear - same as .restart\n .stack - print data stack\n\n > 2 3 + 4 * .\n Optimizer: Constant-folded 2 3 + to 5\n Optimizer: Constant-folded 5 4 * to 20\n 20\n > .code\n IP: 2\n DS: []\n RS: []\n 0000 20 .\n >\n\nNotice that the optimizer constant-folds the entire expression down to simply\n``20``. You can see this by printing out the compiled code with the command\n``.code``. This will list the current instruction pointer ``IP``, the number\nof items on the data stack ``DS`` and the return stack ``RS`` followed by the\ncode.\n\nYou can run programs in files as well. Use ``crianza -h`` to get options.\n\nExample: Running a simple program from Python\n---------------------------------------------\n\nThe simplest way to get started with the language itself is to use the\n``eval`` function:\n\n::\n\n >>> import crianza\n >>> crianza.eval(\"2 3 + 4 *\")\n 20\n\nYou can also use ``crianza.execute`` to get the machine used to execute\nthe program:\n\n::\n\n >>> crianza.execute(\"2 3 + 4 *\")\n \n\nThis is equivalent of computing ``(2 + 3) * 4`` and puts the result on\ntop of the data stack. We can get this by doing\n``crianza.execute(...).top`` or just use ``crianza.eval``. The language\nis basically a `dialect of\nForth `_.\n\nThe complete machine is returned. Here it prints the current value of\nthe instruction pointer ``ip``, the number of items on the data stack\n(``|ds|``), the number of items on the return stack (``|rs|``) and the\nvalue on top of the stack.\n\n``eval`` and ``execute`` will automatically optimize the code (turn off\nwith the option ``optimize=False``). In this case, the entire expression\nis constant-folded down to the result ``20``:\n\n::\n\n >>> m = crianza.execute(\"2 3 + 4 *\")\n >>> m.code\n [20]\n\nYou can divert program output to a memory buffer:\n\n::\n\n >>> from StringIO import StringIO\n >>> buffer = StringIO()\n >>> machine = crianza.execute('\"Hello, world!\" .', output=buffer)\n >>> buffer.getvalue()\n 'Hello, world!\\n'\n >>> machine.code_string\n '\"Hello, world!\" .'\n\nExample: Controlling parsing\n----------------------------\n\nThe more elaborate way of parsing and running code is:\n\n::\n\n from crianza import *\n\n source = \"2 3 + 4 *\" # or: (2+3) * 4\n\n code = compile(parse(source), optimize=False)\n machine = Machine(code)\n machine.run()\n\n assert(machine.top == 20)\n\nYou can also do some simple optimizations on the code by specifying:\n\n::\n\n code = compile(source, optimize=True)\n\nIn this case, the entire code will be constant-folded to simply 20. The\n``check`` function checks for simple errors.\n\nExample: Source code with subroutines\n-------------------------------------\n\nHere's code to print the Fibonacci sequence:\n\n::\n\n : println dup . ;\n : next swap over + ;\n\n # Start values\n 0 println\n 1 println\n\n # Loop forever\n @ next println return\n\nYou can run it by typing:\n\n::\n\n crianza fibonacci.source | head -20\n\nMore examples in the ``examples/`` folder.\n\nExample: Genetic programming\n----------------------------\n\nCrianza also contains very simple genetic programming facilities, just\nto demonstrate a cool usage of the VM.\n\nYou can run the example simulation, which simply attempts to find a\nprogram that squares input numbers. For speed, you should run it with\n``pypy``:\n\n::\n\n $ pypy -OO examples/genetic/square-number.py\n Starting ...\n gen 1 1-fitness 0.410299299627 avg code len 10.00 avg stack len 0.00\n gen 2 1-fitness 0.400844361878 avg code len 6.20 avg stack len 0.00\n gen 3 1-fitness 0.417903405823 avg code len 5.20 avg stack len 0.00\n gen 4 1-fitness 0.403448229584 avg code len 4.60 avg stack len 0.00\n gen 5 1-fitness 0.405436543540 avg code len 2.80 avg stack len 0.00\n gen 6 1-fitness 0.359110672048 avg code len 2.20 avg stack len 0.80\n gen 7 1-fitness 0.206176614950 avg code len 1.60 avg stack len 1.00\n gen 8 1-fitness 0.028440428102 avg code len 2.80 avg stack len 2.20\n gen 9 1-fitness 0.000000044595 avg code len 3.00 avg stack len 1.40\n gen 10 1-fitness 0.000000000833 avg code len 2.20 avg stack len 1.20\n gen 11 1-fitness 0.000000000000 avg code len 2.00 avg stack len 1.00\n\n Listing programs from best to worst, unique solutions only.\n 0 : dup *\n\n The GP found that you can make a square word like so:\n\n : square\n dup * ;\n\n Example output:\n\n 850 square ==> 722500\n 702 square ==> 492804\n 177 square ==> 31329\n 803 square ==> 644809\n 786 square ==> 617796\n\n The code seems to be correct.\n\nIt uses a weighted `Tanimoto coefficient (or Jaccard\nindex) `_\nto relate fitness scores among programs, so you can encode any goal. See\nthe example files for more information.\n\nHere is the main part of the code that instructs Crianza to find a\n``square-number`` subroutine (see the file\n``examples/genetic/square-number.py``).\n\n::\n\n def score(self):\n # Goals, what kind of program we want to evolve ...\n wanted = (\n self._input**2, # Find a way to calculate n^2\n 0, # We don't want errors\n 1, # Don't put a lot of values on the data stack\n 0, # The return stack should be zero after completion\n 0) # Code should be as small as possible, but not over\n # 5 opcodes (see below on how to encode this goal)\n\n # ... and the goals corresponding weights\n weights = (0.10, 0.80, 0.02, 0.02, 0.06)\n\n # Which values we actually got (and how they can be converted to\n # numbers) ...\n actual = (self.top if vm.isnumber(self.top) else 9999.9,\n 1000 if self._error else 0,\n len(self.stack),\n len(self.return_stack),\n len(self.code) if len(self.code)<5 else 999)\n\n # Return a value from 0.0 (perfect score) to 1.0 (infinitely bad score)\n return 1.0 - weighted_tanimoto(actual, wanted, weights)\n\nFor the above example, the fitness score encodes several goals:\n\n- The top of the stack ``top`` should equal the square of the program's\n input ``self._input**2``.\n- Runtime and compile time errors in the program are penalized\n (``1000 if self._error else 0``).\n- The length of the data stack should be exactly one (this makes it\n easier to embed the resulting code in a subroutine).\n- The return stack should be zero after program completion.\n- The code length should be no more than 5 instructions, but as small\n as possible.\n\nFor the above, it almost always seems to converge. The obvious result\nfor calculating the square of a number is ``dup *``, and this is what I\nusually get, although I've also gotten fun variants that are almost\ncorrect, such as ``dup abs *``.\n\nI've not played around much with the GP, but I think it currently does\ncrossover quite badly and unintelligently. It also seems to have\nproblems converging on somewhat more advanced programs. But, it's a\nstart, and it's definitely a lot of fun!\n\nNative Python bytecode compiler\n-------------------------------\n\nCrianza also contains ``crianza.native``, an experimental, work-in-progress\ncompiler to native `CPython bytecode\n`_. At\nthe moment, it only correctly implements simple instructions and doesn't do any\noptimizations.\n\nFurthermore, it uses the `byteplay module\n`_, which works for Python 2.x only.\nIn time, I plan to support all instructions and the Python 3.x series.\n\nTo test it, you can do::\n\n >>> import crianza.native\n >>> mul2 = crianza.native.xcompile(\"2 *\", args=1)\n >>> mul2(101)\n 202\n >>> import dis\n >>> dis.dis(mul2)\n 1 0 LOAD_FAST 0 (arg0)\n 3 LOAD_CONST 1 (2)\n 6 BINARY_MULTIPLY\n 7 RETURN_VALUE\n\nThe ``crianza.native.xcompile`` function takes in source code and ``args``, the\nnumber of arguments the resulting Python function will take. In the above\nexample, we create a function that multiplies its *single* argument by two, so\nwe set ``args=1``. This is *exactly* the same as doing::\n\n >>> py_mul2 = lambda n: n*2\n >>> dis.dis(py_mul2)\n 1 0 LOAD_FAST 0 (n)\n 3 LOAD_CONST 1 (2)\n 6 BINARY_MULTIPLY\n 7 RETURN_VALUE\n\nIn fact, the Python bytecode for the two functions are exactly the same, sans\nthe local argument name.\n\nBecause the CPython bytecode also operates on Python types, it naturally\nsupports things like multiplying sequences::\n\n >>> mul2(\"hello\")\n 'hellohello'\n\nand equivalently::\n\n >>> py_mul2(\"hello\")\n 'hellohello'\n\nAgain, note that this compiler is currently *very* buggy. In particular, it\ndoesn't correctly implement branching (jumps, if-statements, etc.) and many\nother things.\n\nLicense and author\n------------------\n\nCopyright (C) 2015 Christian Stigen Larsen\n\nDistributed under the BSD 3-Clause License. See the LICENSE.txt file for\nthe full text.", "description_content_type": null, "docs_url": null, "download_url": "https://github.com/cslarsen/crianza/tarball/0.1.8", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cslarsen/crianza", "keywords": "vm,virtual machine,genetic programming,interpreter,forth,programming,code,bytecode,assembler,native,stack,machine,tanimoto,evolutionary programming,evolving,evolve,evolution,evolutionary,artificial intelligence,organism", "license": "http://opensource.org/licenses/BSD-3-Clause", "maintainer": null, "maintainer_email": null, "name": "crianza", "package_url": "https://pypi.org/project/crianza/", "platform": "unix,linux,osx,cygwin,win32", "project_url": "https://pypi.org/project/crianza/", "project_urls": { "Download": "https://github.com/cslarsen/crianza/tarball/0.1.8", "Homepage": "https://github.com/cslarsen/crianza" }, "release_url": "https://pypi.org/project/crianza/0.1.8/", "requires_dist": null, "requires_python": null, "summary": "Simple Forth-like VM and genetic programming framework.", "version": "0.1.8" }, "last_serial": 1494727, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "0d269cee89a1202f899a1d0870627b1a", "sha256": "7c57280456fd15f9d87b4b72f21f15b2019e27041609058f35ce8532cfe4d92d" }, "downloads": -1, "filename": "crianza-0.1.tar.gz", "has_sig": false, "md5_digest": "0d269cee89a1202f899a1d0870627b1a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18028, "upload_time": "2015-03-04T10:39:03", "url": "https://files.pythonhosted.org/packages/ef/b0/c5abc8fa987a50a7ecea21a66707e6831359a77a1b34cf934c3f49693d96/crianza-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "b7e66b39f2f09b46c5313108d14dc3c4", "sha256": "d328dbf94bb0c3e43df5f8a1b37292e89cb4f7785adad8ad92cf3ee9d1271dce" }, "downloads": -1, "filename": "crianza-0.1.1.tar.gz", "has_sig": false, "md5_digest": "b7e66b39f2f09b46c5313108d14dc3c4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18295, "upload_time": "2015-03-04T11:53:34", "url": "https://files.pythonhosted.org/packages/b0/83/522327d11dc49addd0245ac7b39ca2ff7d25f8fadda00ad8e9ad953b4c3c/crianza-0.1.1.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "c4dbdfb3d3e72577d903ac9975eefedf", "sha256": "4430644e4ab37c333315edac97c6307f296c794c359077d69541157901dd9135" }, "downloads": -1, "filename": "crianza-0.1.3.tar.gz", "has_sig": false, "md5_digest": "c4dbdfb3d3e72577d903ac9975eefedf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17540, "upload_time": "2015-03-04T16:55:09", "url": "https://files.pythonhosted.org/packages/3e/57/f1afd91549a6378d1094debaaf7417a9f53c365d51d4fb02e679a03d8bf3/crianza-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "71c93ae0d5a344f7990b190575ff489d", "sha256": "542f85fd1a6b8fcd8eae8515c5e28b422d2c578372b7f7885a5f28dad34a51c9" }, "downloads": -1, "filename": "crianza-0.1.4.tar.gz", "has_sig": false, "md5_digest": "71c93ae0d5a344f7990b190575ff489d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18200, "upload_time": "2015-03-04T17:11:57", "url": "https://files.pythonhosted.org/packages/39/09/7f4b03c6e46a2746b1047500b0392dab59cf682fe6c707d4226c9e91300d/crianza-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "29b9f365bf310c17885a125c950b8475", "sha256": "28d4195e770a7798494116a27e6864b643e5d579b76e153ebd94feb50d49c4ef" }, "downloads": -1, "filename": "crianza-0.1.5.tar.gz", "has_sig": true, "md5_digest": "29b9f365bf310c17885a125c950b8475", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19435, "upload_time": "2015-03-05T19:24:50", "url": "https://files.pythonhosted.org/packages/c4/60/00cad212fab472bc8590f8f49c3e43dc0ed2a9c04a7d67deffce8521ab8c/crianza-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "62bd361f9ead8946262bbf21fbcc01cd", "sha256": "0ed32914bc2a2c2050baa1e341ab3ee09143d33bd4e8891856815504bb52f24c" }, "downloads": -1, "filename": "crianza-0.1.6.tar.gz", "has_sig": true, "md5_digest": "62bd361f9ead8946262bbf21fbcc01cd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29187, "upload_time": "2015-03-05T20:09:26", "url": "https://files.pythonhosted.org/packages/c4/81/d0193073fe16491776908bb1086f2bec77c502160b2cef52c0222610eb83/crianza-0.1.6.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "d36a110678223f17c493bec5b0149e65", "sha256": "4b2fea74f2aa241384bf54d349ee99b1694f0f3f7ef1b5309e53011df530749a" }, "downloads": -1, "filename": "crianza-0.1.7-py2-none-any.whl", "has_sig": true, "md5_digest": "d36a110678223f17c493bec5b0149e65", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 27690, "upload_time": "2015-03-07T15:58:22", "url": "https://files.pythonhosted.org/packages/6f/fe/bddb77761dbe4e0340dc867a4bc79169b1ea3bf08bb686ca8a553b03a7a4/crianza-0.1.7-py2-none-any.whl" } ], "0.1.8": [ { "comment_text": "", "digests": { "md5": "b8187322e3406dc23cefaf9ab4489dd4", "sha256": "a22870ea5027c11cbfba337de6aacc53bb1bffb815d79aa065911f181c96611d" }, "downloads": -1, "filename": "crianza-0.1.8-py2-none-any.whl", "has_sig": false, "md5_digest": "b8187322e3406dc23cefaf9ab4489dd4", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 32132, "upload_time": "2015-04-07T19:04:13", "url": "https://files.pythonhosted.org/packages/32/34/b962d07019817b08bf9292101f43be6efbe0d396c3b369450321bcee053a/crianza-0.1.8-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ec809dd9a983b2627b4d732047021255", "sha256": "c6c0584cae3e4813816f8445d7b6a8cbcdee3002854670c33ac6e7cb32edd723" }, "downloads": -1, "filename": "crianza-0.1.8.tar.gz", "has_sig": true, "md5_digest": "ec809dd9a983b2627b4d732047021255", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33624, "upload_time": "2015-04-07T19:04:17", "url": "https://files.pythonhosted.org/packages/31/b1/108f4881eaaf8ac9837a092ababfc76403265410a0ce993a471b1e02414c/crianza-0.1.8.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b8187322e3406dc23cefaf9ab4489dd4", "sha256": "a22870ea5027c11cbfba337de6aacc53bb1bffb815d79aa065911f181c96611d" }, "downloads": -1, "filename": "crianza-0.1.8-py2-none-any.whl", "has_sig": false, "md5_digest": "b8187322e3406dc23cefaf9ab4489dd4", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 32132, "upload_time": "2015-04-07T19:04:13", "url": "https://files.pythonhosted.org/packages/32/34/b962d07019817b08bf9292101f43be6efbe0d396c3b369450321bcee053a/crianza-0.1.8-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ec809dd9a983b2627b4d732047021255", "sha256": "c6c0584cae3e4813816f8445d7b6a8cbcdee3002854670c33ac6e7cb32edd723" }, "downloads": -1, "filename": "crianza-0.1.8.tar.gz", "has_sig": true, "md5_digest": "ec809dd9a983b2627b4d732047021255", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33624, "upload_time": "2015-04-07T19:04:17", "url": "https://files.pythonhosted.org/packages/31/b1/108f4881eaaf8ac9837a092ababfc76403265410a0ce993a471b1e02414c/crianza-0.1.8.tar.gz" } ] }