https://github.com/mschuldt/forth_wizard
Finds optimal code sequences for stack transformations
https://github.com/mschuldt/forth_wizard
Last synced: 8 months ago
JSON representation
Finds optimal code sequences for stack transformations
- Host: GitHub
- URL: https://github.com/mschuldt/forth_wizard
- Owner: mschuldt
- License: gpl-3.0
- Created: 2017-11-11T10:28:18.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2019-02-21T00:55:41.000Z (over 7 years ago)
- Last Synced: 2025-01-09T22:37:11.536Z (over 1 year ago)
- Language: Python
- Homepage:
- Size: 90.8 KB
- Stars: 24
- Watchers: 3
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.org
- License: LICENSE.txt
Awesome Lists containing this project
README
The Forth Wizard finds the shortest sequence of forth instructions needed for a given stack manipulation.
In addition to simple stack transforms it allows for partial specification of the final
stack state, usage of the return stack, and caching. All common forth instructions are supported.
This was translated from the orignal [[http://sovietov.com/app/forthwiz.html][forth wizard]] and heavily extended.
It is written in C and provides a Python3 module. Tested only on Ubuntu.
* Installation
Install from pypi with ~pip3 install forthwiz~,
or download and run ~sudo ./make.sh~ to build and install. Requires package python3-dev to build.
* Usage
Instantiate a ~forthwiz.Wizard~ object and use the ~setup~ method to specify
the machine state. This can include the initial and ending state of data stack,
initial state of return stack, and options for caching, supported ops, and return stack usage.
The stack states are specified with lists, the items in those lists may be any hashable type.
#+BEGIN_SRC python
$ python3
>>> import forthwiz
>>> wiz = forthwiz.Wizard()
>>> wiz.setup( in_stack=['a', 'b'], out_stack=['b', 'a', 'a'] )
>>> solution = wiz.solve()
>>> solution.code
['swap', 'dup']
#+END_SRC
* Multiple solutions
~Wizard.solve~ may be called multiple times to generate alternative solutions:
#+BEGIN_SRC python
>>> wiz.setup( in_stack=['a', 'b'], out_stack=['b', 'a', 'a'] )
>>> solution = wiz.solve(); solution.code
['swap', 'dup']
>>> solution = wiz.solve(); solution.code
['over', 'rot']
>>> solution = wiz.solve(); solution.code
['swap', '2dup', 'nip']
#+END_SRC
* Partial stack usage
The =out_vars= parameter can be used to specify symbols that must remain
in the final machine state. When ~out_vars~ is set
the =out_stack= parameter only specifies the top values
that are expected on the stack. Symbols in =out_vars= that are not in =out_stack=
may be included in the bottom portion of the data stack in any order. This may yield
shorter solutions when only the top ordering matters.
The final data stack value is saved as the =Solution.stack= attribute.
#+BEGIN_SRC python
>>> wiz.setup( in_stack=[1, 2, 3, 4, 5], out_stack=[1],
out_vars=[1, 2, 3, 5] )
>>> solution = wiz.solve()
>>> solution.code
['nip', '2swap', 'swap']
>>> solution.stack
[3, 5, 2, 1]
#+END_SRC
* Using the return stack
The =use_rstack= parameter tells the solver that it is ok to leave values on the
return stack. When it is set values that appear in =out_vars= that are not present
in =out_stack= may be left on the return stack in addition to the bottom of
the data stack. This is disabled by default. The final state of the return stack
is saved as the ~Solution.rstack~ attribute.
#+BEGIN_SRC python
>>> wiz.setup( in_stack=[1, 2, 3, 4, 5], out_stack=[1],
out_vars=[1, 2, 3, 5], use_rstack=True )
>>> solution = wiz.solve()
>>> solution.code
['>r', 'drop', 'rot']
>>> solution.stack
[2, 3, 1]
>>> solution.rstack
[5]
#+END_SRC
=in_rstack= can be used to specify the starting state of the return stack.
* Finding all solutions
Use the ~Wizard.solutions~ to find all the solutions of the minimal length.
#+BEGIN_SRC python
>>> wiz.setup( in_stack=[1, 2], out_stack=[2, 1, 1] )
>>> solution = wiz.solutions()
>>> [s.code for s in solution]
[['swap', 'dup'], ['over', 'rot']]
#+END_SRC
Subsequent calls to ~Wizard.solutions~ gives the collection of the next
longest solution length.
~Wizard.solve_many~ can be used to find all solutions under a given length.
* Forth ops
The forth ops the solver will use to find the solution can be set with the =ops=
parameter. Specify the op ~N pick~ with ~Npick~, currently supported for N=[2,5].
For example, duplicating top of stack without =dup=:
#+BEGIN_SRC python
>>> wiz.setup( in_stack=['A', 'B'], out_stack=['A', 'B', 'B'],
ops=['swap', 'r>', 'over', '>r', 'r@'] )
>>> solution = wiz.solve(); solution.code
>>> ['>r', 'r@', 'r>']
#+END_SRC
Predefined collections of ops supported by common forth interpreters can be set
using the =target= parameter. Currently supported targets are gforth and amforth.
#+BEGIN_SRC python
>>> wiz.setup( in_stack=['a', 'b','c','d'], out_stack=['a', 'b','c','d','a','b'],
target='gforth' )
>>> solution = wiz.solve(); solution.code
['2over']
>>> wiz.setup( in_stack=['a', 'b','c','d'], out_stack=['a', 'b','c','d','a','b'],
target='amforth' )
>>> solution = wiz.solve(); solution.code
['2>r', '2dup', '2r>', '2swap']
#+END_SRC
* Caching
By default calls to ~solve~ will cache the solution.
To disable caching set the optional ~setup~ parameter ~use_cache~ to False.
A different cache file is used for each solver version and collection of
ops used to find the solution, for example =wizard_cache_1_2_7ffff.txt=.
* Disabling the pick instruction
Use of the =pick= instruction may be disabled with the =use_pick= option:
#+BEGIN_SRC python
>>> wiz.setup( in_stack=[0, 1, 2], out_stack=[0, 2, 0, 1] )
>>> solution = wiz.solve(); solution
['2', 'pick', 'rot']
>>> wiz.setup( in_stack=[0, 1, 2], out_stack=[0, 2, 0, 1],
use_pick=False )
>>> solution = wiz.solve(); solution
['swap', '>r', 'over', 'r>']
#+END_SRC
* forthwiz.solve_stacks
~forthwiz.solve_stacks~ is a convenience function supporting only basic usage. It takes
two lists describing the input and output states of the data stack and a subset
of the options available to =Wizard.setup=
#+BEGIN_SRC python
>>> import forthwiz
>>> forthwiz.solve_stacks( ['a', 'b'], ['b', 'a', 'a'] )
['swap', 'dup']
#+END_SRC