提交 129bf3cb authored 作者: Olivier Breuleux's avatar Olivier Breuleux

merge

# -*- coding: utf-8 -*-
#
# theano documentation build configuration file, created by
# sphinx-quickstart on Tue Oct 7 02:53:58 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys, os
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.txt'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = 'theano'
copyright = '2008, Olivier Breuleux, James Bergstra'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be searched
# for source files.
#exclude_dirs = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
#html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'theanodoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index', 'theano.tex', 'theano Documentation',
'Olivier Breuleux, James Bergstra', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
"""script to generate doc/oplist.txt, which compiles to :doc:`oplist`. """ """script to generate doc/oplist.txt, which compiles to :doc:`oplist`. """
__docformat__ = "restructuredtext en" __docformat__ = "restructuredtext en"
import sys import sys
import gof from theano import gof
def print_title(title_string, under_char, over_char=''): def print_title(title_string, under_char, over_char=''):
l = len(title_string) l = len(title_string)
...@@ -94,15 +94,25 @@ class EntryConstructor(Entry): ...@@ -94,15 +94,25 @@ class EntryConstructor(Entry):
Entry.__init__(self, symbol, name, module) Entry.__init__(self, symbol, name, module)
def search_entries(module_list): def search_entries(module_list, ops = None, constructors = None, seen = None):
ops = [] if ops is None: ops = []
constructors = [] if constructors is None: constructors = []
if seen is None: seen = set()
modules = []
for module in module_list: for module in module_list:
symbol_name_list = [s for s in dir(module) if not s[0] == '_'] symbol_name_list = [s for s in dir(module) if not s[0] == '_']
for symbol_name in symbol_name_list: for symbol_name in symbol_name_list:
symbol = getattr(module, symbol_name) symbol = getattr(module, symbol_name)
try:
if symbol in seen:
continue
seen.add(symbol)
except TypeError:
pass
if type(symbol) == type(module): # module
modules.append(symbol)
try: try:
ops.append(EntryOp(symbol, symbol_name, module)) ops.append(EntryOp(symbol, symbol_name, module))
except TypeError: except TypeError:
...@@ -111,6 +121,9 @@ def search_entries(module_list): ...@@ -111,6 +121,9 @@ def search_entries(module_list):
except TypeError: except TypeError:
pass pass
for symbol in modules:
search_entries([symbol], ops, constructors, seen)
return ops, constructors return ops, constructors
def print_entries(ops, constructors): def print_entries(ops, constructors):
...@@ -141,7 +154,7 @@ def print_entries(ops, constructors): ...@@ -141,7 +154,7 @@ def print_entries(ops, constructors):
if __name__ == "__main__": if __name__ == "__main__":
"""Generate the op list""" """Generate the op list"""
import scalar, sparse, tensor import theano
print_title("Op List", "~", "~") print_title("Op List", "~", "~")
print """ print """
...@@ -156,11 +169,8 @@ In the future, this list may distinguish `constructors` that are Op instances fr ...@@ -156,11 +169,8 @@ In the future, this list may distinguish `constructors` that are Op instances fr
print ".. contents:: " print ".. contents:: "
print "" print ""
ops, constructors = search_entries([scalar, sparse, tensor]) ops, constructors = search_entries([theano])
print_entries(ops, constructors) print_entries(ops, constructors)
print "" print ""
for line in open("doc/header.txt"):
print line[:-1]
import unittest, os, sys, traceback
def test_root_dir(debugmode=False):
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py' and filename[0:5] == '_test':
#print >>sys.stderr, 'Loading', modname
modname = filename[0:-3]
try:
module = __import__(modname)
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load %s.py" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugmode:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
if len(sys.argv) >= 2:
cmd = sys.argv[1]
else:
cmd = 'python'
for dir in 'gof compile scalar tensor sparse'.split():
os.system('cd %s; %s autotest.py %s' % (dir, cmd, debugparam))
test_root_dir(debugparam!="")
import unittest, os, sys, traceback
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py':
modname = filename[:-3]
if modname in ['__init__', 'autotest']: continue
#print >>sys.stderr, 'Loading', modname
try:
module = __import__(modname)
except Exception, e:
if 'relative import' not in e.message:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load module %s" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugparam:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
...@@ -194,18 +194,9 @@ Getting Help ...@@ -194,18 +194,9 @@ Getting Help
If these installation instructions don't work, search the theano-users archive for similar cases. If you don't find a solution, write to theano-users and explain the situation. If these installation instructions don't work, search the theano-users archive for similar cases. If you don't find a solution, write to theano-users and explain the situation.
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_
.. _README: README.html .. _README: README.html
.. _Download: README.html#downloading-theano .. _Download: README.html#downloading-theano
.. _Documentation: doc/index.html .. _Documentation: doc/index.html
.. _Wiki: http://pylearn.org/theano .. _Wiki: http://pylearn.org/theano
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority .. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png
:target: http://pylearn.org/auto_theano
:alt: THEANO
:align: top
:class: borderless
:width: 60
:height: 18
...@@ -7,12 +7,7 @@ ...@@ -7,12 +7,7 @@
# The list of objects to document. Objects can be named using # The list of objects to document. Objects can be named using
# dotted names, module filenames, or package directory names. # dotted names, module filenames, or package directory names.
# Alases for this option include "objects" and "values". # Alases for this option include "objects" and "values".
modules: __init__.py, modules: theano
[a-z]*.py,
[A-Z]*.py,
gof/__init__.py,
gof/[a-z]*.py,
gof/[A-Z]*.py
# The type of output that should be generated. Should be one # The type of output that should be generated. Should be one
# of: html, text, latex, dvi, ps, pdf. # of: html, text, latex, dvi, ps, pdf.
...@@ -125,9 +120,9 @@ separate-classes: no ...@@ -125,9 +120,9 @@ separate-classes: no
# Use this URL prefix to configure the string returned for external API. # Use this URL prefix to configure the string returned for external API.
#external-api-root: epydoc:http://epydoc.sourceforge.net/api #external-api-root: epydoc:http://epydoc.sourceforge.net/api
external-api: wiki doc # external-api: wiki doc
external-api-root: wiki:http://lgcm.iro.umontreal.ca/theano/wiki/ doc:http://lgcm.iro.umontreal.ca/auto_theano/doc/ # external-api-root: wiki:http://lgcm.iro.umontreal.ca/theano/wiki/ doc:http://lgcm.iro.umontreal.ca/auto_theano/doc/
external-api-file: wiki:wiki.idx doc:doc/doc.idx # external-api-file: wiki:wiki.idx doc:doc/doc.idx
### Graph options ### Graph options
......
# -*- coding: utf-8 -*-
#
# theano documentation build configuration file, created by
# sphinx-quickstart on Tue Oct 7 16:34:06 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys, os
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'ext']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.txt'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = 'theano'
copyright = '2008, Olivier Breuleux, James Bergstra'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be searched
# for source files.
#exclude_dirs = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
#html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'theanodoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index', 'theano.tex', 'theano Documentation',
'Olivier Breuleux, James Bergstra', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
...@@ -60,16 +60,6 @@ When you install a package, only the package name can be imported directly. If y ...@@ -60,16 +60,6 @@ When you install a package, only the package name can be imported directly. If y
.. _basicnumpy: http://lgcm.iro.umontreal.ca/theano/wiki/BasicNumpy .. _basicnumpy: http://lgcm.iro.umontreal.ca/theano/wiki/BasicNumpy
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png
:target: http://pylearn.org/auto_theano
:alt: THEANO
:align: top
:class: borderless
:width: 60
:height: 18
.. _README: ../README.html .. _README: ../README.html
.. _Download: ../README.html#downloading-theano .. _Download: ../README.html#downloading-theano
.. _Documentation: index.html .. _Documentation: index.html
......
...@@ -87,16 +87,6 @@ If we had wanted a more brute-force approach to graph construction, we could hav ...@@ -87,16 +87,6 @@ If we had wanted a more brute-force approach to graph construction, we could hav
Note how the call to `Apply` modifies the `owner` and `index` fields of the `Result` s passed as outputs to point to itself and the rank they occupy in the output list. This whole machinery builds a DAG (Directed Acyclic Graph) representing the computation, a graph that theano can compile and optimize. Note how the call to `Apply` modifies the `owner` and `index` fields of the `Result` s passed as outputs to point to itself and the rank they occupy in the output list. This whole machinery builds a DAG (Directed Acyclic Graph) representing the computation, a graph that theano can compile and optimize.
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png
:target: http://pylearn.org/auto_theano
:alt: THEANO
:align: top
:class: borderless
:width: 60
:height: 18
.. _README: ../README.html .. _README: ../README.html
.. _Download: ../README.html#downloading-theano .. _Download: ../README.html#downloading-theano
.. _Documentation: index.html .. _Documentation: index.html
......
=====================================
Theano Project Documentation Overview
=====================================
.. toctree::
:glob:
*
Documentation is divided broadly into two kinds: user documentation and
developer documentation.
- `Using Theano` covers how to *use* what is already in the Theano library to
build graphs and evaluate them.
- `Extending Theano` introduces how Theano works and explains how to add new
data and expression types, as well as optimizations to accompany them.
- `Hacking Theano` introduces you to what's under the hood: the compilation
process, the Env, C code generation.
Using Theano
============
- First of all, read the `n00b guide`_. It is a cut-and-paste, tutorial-style intro to what Theano can do.
- Familiarize yourself with the `glossary of terminology`_.
- Join `theano-users`_.
- Learn to use the typelist_, and the oplist_. These are the building blocks
of theano expression graphs.
- Browse through some of the `Howto`_ recipes on the wiki.
.. _Howto:
.. _theano-users: http://groups.google.com/group/theano-users?pli=1
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _n00b guide: n00b.html
.. _glossary of terminology: ../api/term-index.html
.. _typelist: typelist.html
.. _oplist: oplist.html
Extending Theano
================
- Read about `How Theano Works <UserAdvanced.html>`__. This introduces the
major interface data structures: Op, Type, Result, Apply.
- How to make a new Op.
- How to make a new Optimization.
- How to make a new data Type.
Hacking Theano
==============
- `Get Started as a Developer <DevStartGuide.html>`__ by setting up mercurial, getting a few accounts,
setting up your environment, and getting some background in mercurial, python,
and numpy.
- Join `theano-dev`_ to participate in development discussion.
- Pick a task from the `task list`_, or suggest one on `theano-users`_.
Features/ideas are generally discussed on `theano-users`_. Technical
discussions of how to actually implement something should be on
`theano-dev`_.
- Browse `Theano's API <../api/>`__.
- Keep an eye on the `Mercurial Changelog <http://pylearn.org/hg/theano>`__.
- Send us your work as a patch to `theano-dev`_ or commit directly to the trunk.
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
...@@ -237,16 +237,6 @@ code. The question is how to automatically extract the source files and inline ...@@ -237,16 +237,6 @@ code. The question is how to automatically extract the source files and inline
them into this documentation.* them into this documentation.*
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png
:target: http://pylearn.org/auto_theano
:alt: THEANO
:align: top
:class: borderless
:width: 60
:height: 18
.. _README: ../README.html .. _README: ../README.html
.. _Download: ../README.html#downloading-theano .. _Download: ../README.html#downloading-theano
.. _Documentation: index.html .. _Documentation: index.html
......
import os
from docutils import nodes
import epydoc.docwriter.xlink as xlink
def role_fn(name, rawtext, text, lineno, inliner,
options={}, content=[]):
node = nodes.reference(rawtext, text, refuri = "http://pylearn.org/theano/wiki/%s" % text)
return [node], []
def setup(app):
help(xlink)
#role = xlink.create_api_role('api', True)
#print role
xlink.register_api('api', xlink.DocUrlGenerator())
xlink.set_api_file('api', os.path.join(app.outdir, 'api', 'api-objects.txt'))
xlink.set_api_root('api', os.path.join(app.outdir, 'api', ''))
xlink.create_api_role('api', True)
app.add_role("wiki", role_fn)
=====================================
Theano Project Documentation Overview
=====================================
Documentation is divided broadly into two kinds: user documentation and ======
developer documentation. Theano
======
- `Using Theano` covers how to *use* what is already in the Theano library to .. toctree::
build graphs and evaluate them. :maxdepth: 2
- `Extending Theano` introduces how Theano works and explains how to add new README
data and expression types, as well as optimizations to accompany them. doc/index
- `Hacking Theano` introduces you to what's under the hood: the compilation -------------------------------------------------------------------
process, the Env, C code generation. A python library for manipulating and evaluating matrix expressions
-------------------------------------------------------------------
Theano is a library in Python, built to evaluate complicated
expressions (especially matrix-valued ones) as quickly as possible.
It was written at LISA_ to explore techniques for machine learning.
Our project uses the name to honour the ancient Greek mathematician.
Using Theano --------------------------------------------------------------------------------
============
- First of all, read the `n00b guide`_. It is a cut-and-paste, tutorial-style intro to what Theano can do. .. _not in the normal sense: :wiki:`WhatIsTheano`
- Familiarize yourself with the `glossary of terminology`_. Overview
========
- Join `theano-users`_. **To get up & running quickly** see README_.
- Learn to use the typelist_, and the oplist_. These are the building blocks All **documentation** can be reached from the `Theano Project Documentation Overview`_.
of theano expression graphs.
- Browse through some of the `Howto`_ recipes on the wiki. As developers of an open source project, we rely on **feedback** for
determining what features to implement, and what documentation needs to be
improved. The best forum for feedback is the theano-users_ mailing list.
.. _Howto: All **discussion** about theano also takes place on the theano-users_ mailing list.
.. _theano-users: http://groups.google.com/group/theano-users?pli=1
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _n00b guide: n00b.html
.. _glossary of terminology: ../api/term-index.html
.. _typelist: typelist.html
.. _oplist: oplist.html
Extending Theano
================
- Read about `How Theano Works <UserAdvanced.html>`__. This introduces the If you find a **bug**, please file a `bug report`_ or send email to
major interface data structures: Op, Type, Result, Apply. the theano-users_ mailing list. **Patch** submissions should be
sent to theano-dev_.
- How to make a new Op. We welcome all kinds of **contributions**. Our `task list`_ is
full of interesting ideas awaiting a champion. If you have any
questions regarding how to extend Theano, please feel free to ask on
the Theano-dev_ mailing list.
- How to make a new Optimization. Theano is in active development and should be considered **experimental**.
APIs are subject to change at any time.
- How to make a new data Type.
Hacking Theano Download
============== ========
- `Get Started as a Developer <DevStartGuide.html>`__ by setting up mercurial, getting a few accounts, We recommend that you use the `latest snapshot`_,
setting up your environment, and getting some background in mercurial, python, Better yet, use `mercurial`_ to keep your installation fresh.
and numpy. The snapshots usually contain *more features* and *fewer bugs* than the
"official" releases |---| they're not only for developers!
- Join `theano-dev`_ to participate in development discussion.
- Pick a task from the `task list`_, or suggest one on `theano-users`_. Indices and tables
Features/ideas are generally discussed on `theano-users`_. Technical ==================
discussions of how to actually implement something should be on
`theano-dev`_.
- Browse `Theano's API <../api/>`__. * :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
- Keep an eye on the `Mercurial Changelog <http://pylearn.org/hg/theano>`__.
- Send us your work as a patch to `theano-dev`_ or commit directly to the trunk.
.. |---| unicode:: U+02014 .. em dash
:trim:
.. _latest snapshot: http://pylearn.org/hg/theano/archive/tip.tar.gz
.. _bug report: http://lgcm.iro.umontreal.ca/theano/newticket
.. _theano-users: http://groups.google.com/group/theano-users?pli=1
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1 .. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _reStructuredText: rst.html
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority .. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _reStructuredText: http://docutils.sourceforge.net/rst.html .. _README: README.html
.. _Quick-Start: README.html#quick-start
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_ .. _Theano Project Documentation Overview: doc/index.html
.. _Mercurial: http://www.selenic.com/mercurial/wiki/
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png .. _docutils: http://docutils.sourceforge.net
:target: http://pylearn.org/auto_theano .. _epydoc: http://epydoc.sourceforge.net/
:alt: THEANO .. _scipy: http://scipy.org/
:align: top .. _Python: http://www.python.org/
:class: borderless
:width: 60
:height: 18
.. _README: ../README.html
.. _Download: ../README.html#downloading-theano
.. _Documentation: index.html
.. _Wiki: http://pylearn.org/theano
.. _TRAC: http://trac.edgewall.org/ .. _TRAC: http://trac.edgewall.org/
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority .. _LISA: http://www.iro.umontreal.ca/rubrique.php3?id_rubrique=27
import unittest
from type import Type
import graph
from graph import Result, Apply
from op import Op
from opt import *
import destroyhandler
from env import Env, InconsistencyError
from toolbox import ReplaceValidate
from copy import copy
PatternOptimizer = lambda p1, p2, ign=True: OpKeyOptimizer(PatternSub(p1, p2), ignore_newtrees=ign)
OpSubOptimizer = lambda op1, op2, fail=keep_going, ign=True: TopoOptimizer(OpSub(op1, op2), ignore_newtrees=ign, failure_callback = fail)
def as_result(x):
assert isinstance(x, Result)
return x
class MyType(Type):
def filter(self, data):
return data
def __eq__(self, other):
return isinstance(other, MyType)
def MyResult(name):
return Result(MyType(), None, None, name = name)
def MyValue(data):
return graph.Value(MyType(), data = data)
class MyOp(Op):
def __init__(self, nin, name, vmap = {}, dmap = {}, nout = 1, tolerate_same = []):
self.nin = nin
self.nout = nout
self.name = name
self.destroy_map = dmap
self.view_map = vmap
self.tolerate_same = tolerate_same
def make_node(self, *inputs):
assert len(inputs) == self.nin
inputs = map(as_result, inputs)
for input in inputs:
if not isinstance(input.type, MyType):
raise Exception("Error 1")
outputs = [MyResult(self.name + "_R") for i in xrange(self.nout)]
return Apply(self, inputs, outputs)
def __str__(self):
return self.name
sigmoid = MyOp(1, 'Sigmoid')
transpose_view = MyOp(1, 'TransposeView', vmap = {0: [0]})
add = MyOp(2, 'Add')
add_in_place = MyOp(2, 'AddInPlace', dmap = {0: [0]})
add_in_place_2 = MyOp(2, 'AddInPlace', dmap = {0: [0]}, tolerate_same = [(0, 1)])
dot = MyOp(2, 'Dot')
def inputs():
x = MyResult('x')
y = MyResult('y')
z = MyResult('z')
return x, y, z
_Env = Env
def Env(inputs, outputs, validate = True):
e = _Env(inputs, outputs)
##e.extend(EquivTool(e))
e.extend(destroyhandler.DestroyHandler())
e.extend(ReplaceValidate())
if validate:
e.validate()
return e
class FailureWatch:
# when passed to OpSubOptimizer or PatternOptimizer, counts the number of failures
def __init__(self):
self.failures = 0
def __call__(self, exc, nav, pairs):
assert isinstance(exc, InconsistencyError)
self.failures += 1
class _test_protocol(unittest.TestCase):
def test_misc(self):
x, y, z = inputs()
e = transpose_view(transpose_view(transpose_view(transpose_view(x))))
g = Env([x,y,z], [e])
assert g.consistent()
chk = g.checkpoint()
PatternOptimizer((transpose_view, (transpose_view, 'x')), 'x').optimize(g)
assert str(g) == "[x]"
new_e = add(x,y)
g.replace_validate(x, new_e)
assert str(g) == "[Add(x, y)]"
g.replace(new_e, dot(add_in_place(x,y), transpose_view(x)))
assert str(g) == "[Dot(AddInPlace(x, y), TransposeView(x))]"
assert not g.consistent()
g.revert(chk)
assert g.consistent()
assert str(g) == "[TransposeView(TransposeView(TransposeView(TransposeView(x))))]"
class _test_protocol_skip(unittest.TestCase):
def test_aliased_inputs_replacement(self):
x, y, z = inputs()
tv = transpose_view(x)
tvv = transpose_view(tv)
sx = sigmoid(x)
e = add_in_place(x, tv)
g = Env([x, y], [e], False)
assert not g.consistent()
g.replace(tv, sx)
assert g.consistent()
g.replace(sx, tv)
assert not g.consistent()
g.replace(tv, tvv)
assert not g.consistent()
g.replace(tv, sx)
assert g.consistent()
def test_indestructible(self):
x, y, z = inputs()
x.tag.indestructible = True
x = copy(x)
assert x.tag.indestructible # checking if indestructible survives the copy!
e = add_in_place(x, y)
g = Env([x,y,z], [e], False)
assert not g.consistent()
g.replace_validate(e, add(x, y))
assert g.consistent()
def test_usage_loop_through_views_2(self):
x, y, z = inputs()
e0 = transpose_view(transpose_view(sigmoid(x)))
e = dot(add_in_place(x,y), transpose_view(e0))
g = Env([x,y,z], [e])
assert g.consistent() # because sigmoid can do the copy
# print g
# print g.destroy_handler.children
g.replace(e0, x)
assert not g.consistent() # we cut off the path to the sigmoid
def test_destroyers_loop(self):
# AddInPlace(x, y) and AddInPlace(y, x) should not coexist
x, y, z = inputs()
e1 = add(x, y)
e2 = add(y, x)
g = Env([x,y,z], [e1, e2])
chk = g.checkpoint()
assert g.consistent()
g.replace_validate(e1, add_in_place(x, y))
assert g.consistent()
try:
g.replace_validate(e2, add_in_place(y, x))
self.fail()
except InconsistencyError:
pass
assert g.consistent()
g.revert(chk)
g.replace_validate(e2, add_in_place(y, x))
assert g.consistent()
try:
g.replace_validate(e1, add_in_place(x, y))
self.fail()
except InconsistencyError:
pass
assert g.consistent()
class _test_0(unittest.TestCase):
def test_aliased_inputs(self):
x, y, z = inputs()
e = add_in_place(x, x)
g = Env([x], [e], False)
assert not g.consistent()
def test_aliased_inputs2(self):
x, y, z = inputs()
e = add_in_place(x, transpose_view(x))
g = Env([x], [e], False)
assert not g.consistent()
def test_aliased_inputs_tolerate(self):
x, y, z = inputs()
e = add_in_place_2(x, x)
g = Env([x], [e], False)
assert g.consistent()
def test_aliased_inputs_tolerate2(self):
x, y, z = inputs()
e = add_in_place_2(x, transpose_view(x))
g = Env([x], [e], False)
assert not g.consistent()
def test_indestructible_through_views(self):
x, y, z = inputs()
x.tag.indestructible = True
tv = transpose_view(x)
e = add_in_place(tv, y)
g = Env([x,y,z], [e], False)
assert not g.consistent()
g.replace_validate(tv, sigmoid(x))
assert g.consistent()
def test_indirect(self):
x, y, z = inputs()
e0 = add_in_place(x, y)
e = dot(sigmoid(e0), transpose_view(x))
g = Env([x,y,z], [e], False)
assert not g.consistent()
new_e0 = add(x, y)
g.replace(e0, new_e0)
assert g.consistent()
g.replace(new_e0, add_in_place(x, y))
assert not g.consistent()
def test_indirect_2(self):
x, y, z = inputs()
e0 = transpose_view(x)
e = dot(sigmoid(add_in_place(x, y)), e0)
g = Env([x,y,z], [e], False)
assert not g.consistent()
new_e0 = add(e0, y)
g.replace(e0, new_e0)
assert g.consistent()
def test_long_destroyers_loop(self):
x, y, z = inputs()
e = dot(dot(add_in_place(x,y), add_in_place(y,z)), add(z,x))
g = Env([x,y,z], [e])
assert g.consistent()
OpSubOptimizer(add, add_in_place).optimize(g)
assert g.consistent()
assert str(g) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]" # we don't want to see that!
e2 = dot(dot(add_in_place(x,y), add_in_place(y,z)), add_in_place(z,x))
try:
g2 = Env(*graph.clone([x,y,z], [e2]))
self.fail()
except InconsistencyError:
pass
def test_misc_2(self):
x, y, z = inputs()
tv = transpose_view(x)
e = add_in_place(x, tv)
g = Env([x,y], [e], False)
assert not g.consistent()
g.replace(tv, x)
assert not g.consistent()
def test_multi_destroyers(self):
x, y, z = inputs()
e = add(add_in_place(x, y), add_in_place(x, y))
try:
g = Env([x,y,z], [e])
self.fail()
except InconsistencyError, e:
pass
def test_multi_destroyers_through_views(self):
x, y, z = inputs()
e = dot(add(transpose_view(z), y), add(z, x))
g = Env([x,y,z], [e])
assert g.consistent()
fail = FailureWatch()
OpSubOptimizer(add, add_in_place, fail).optimize(g)
assert g.consistent()
assert fail.failures == 1 # should have succeeded once and failed once
def test_repair_destroy_path(self):
x, y, z = inputs()
e1 = transpose_view(transpose_view(x))
e2 = transpose_view(transpose_view(e1))
e3 = add_in_place(e2, y)
e4 = add_in_place(e1, z)
g = Env([x,y,z], [e3, e4], False)
assert not g.consistent()
g.replace(e2, transpose_view(x))
assert not g.consistent()
def test_usage_loop(self):
x, y, z = inputs()
g = Env([x,y,z], [dot(add_in_place(x, z), x)], False)
assert not g.consistent()
OpSubOptimizer(add_in_place, add).optimize(g) # replace add_in_place with add
assert g.consistent()
def test_usage_loop_through_views(self):
x, y, z = inputs()
aip = add_in_place(x, y)
e = dot(aip, transpose_view(x))
g = Env([x,y,z], [e], False)
assert not g.consistent()
g.replace_validate(aip, add(x, z))
assert g.consistent()
def test_usage_loop_insert_views(self):
x, y, z = inputs()
e = dot(add_in_place(x, add(y, z)), sigmoid(sigmoid(sigmoid(sigmoid(sigmoid(x))))))
g = Env([x,y,z], [e])
assert g.consistent()
fail = FailureWatch()
OpSubOptimizer(sigmoid, transpose_view, fail).optimize(g)
assert g.consistent()
assert fail.failures == 1 # it must keep one sigmoid in the long sigmoid chain
def test_value_repl(self):
x, y, z = inputs()
sy = sigmoid(y)
e = add_in_place(x, sy)
g = Env([x,y], [e], False)
assert g.consistent()
g.replace(sy, MyValue("abc"))
assert g.consistent()
def test_value_repl_2(self):
x, y, z = inputs()
sy = sigmoid(y)
e = add_in_place(x, sy)
g = Env([x,y], [e], False)
assert g.consistent()
g.replace(sy, transpose_view(MyValue("abc")))
assert g.consistent()
pass
if __name__ == '__main__':
if 1:
unittest.main()
else:
testcase = _test_protocol
suite = unittest.TestLoader()
suite = suite.loadTestsFromTestCase(testcase)
unittest.TextTestRunner(verbosity=2).run(suite)
import unittest
from type import *
# todo: test generic
if __name__ == '__main__':
unittest.main()
import unittest, os, sys, traceback
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py':
modname = filename[:-3]
if modname in ['__init__', 'autotest']: continue
#print >>sys.stderr, 'Loading', modname
try:
module = __import__(modname)
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load module %s" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugparam:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
======
Theano
======
-------------------------------------------------------------------
A python library for manipulating and evaluating matrix expressions
-------------------------------------------------------------------
Theano is a library in Python, built to evaluate complicated
expressions (especially matrix-valued ones) as quickly as possible.
It was written at LISA_ to explore techniques for machine learning.
Our project uses the name to honour the ancient Greek mathematician.
--------------------------------------------------------------------------------
.. _not in the normal sense: :wiki:`WhatIsTheano`
Overview
========
**To get up & running quickly** see README_.
All **documentation** can be reached from the `Theano Project Documentation Overview`_.
As developers of an open source project, we rely on **feedback** for
determining what features to implement, and what documentation needs to be
improved. The best forum for feedback is the theano-users_ mailing list.
All **discussion** about theano also takes place on the theano-users_ mailing list.
If you find a **bug**, please file a `bug report`_ or send email to
the theano-users_ mailing list. **Patch** submissions should be
sent to theano-dev_.
We welcome all kinds of **contributions**. Our `task list`_ is
full of interesting ideas awaiting a champion. If you have any
questions regarding how to extend Theano, please feel free to ask on
the Theano-dev_ mailing list.
Theano is in active development and should be considered **experimental**.
APIs are subject to change at any time.
Download
========
We recommend that you use the `latest snapshot`_,
Better yet, use `mercurial`_ to keep your installation fresh.
The snapshots usually contain *more features* and *fewer bugs* than the
"official" releases |---| they're not only for developers!
.. class:: credits
Project by Mercurial_ and TRAC_.
Powered by Python_ and SciPy_.
Coded at the LISA_ lab.
.. class:: hidden
Google should index the mailing lists:
`theano-users <http://groups.google.com/group/theano-users?pli=1>`__,
and
`theano-dev <http://groups.google.com/group/theano-dev?pli=1>`__.
.. |---| unicode:: U+02014 .. em dash
:trim:
.. _latest snapshot: http://pylearn.org/hg/theano/archive/tip.tar.gz
.. _bug report: http://lgcm.iro.umontreal.ca/theano/newticket
.. _theano-users: http://groups.google.com/group/theano-users?pli=1
.. _theano-dev: http://groups.google.com/group/theano-dev?pli=1
.. _reStructuredText: rst.html
.. _task list: http://lgcm.iro.umontreal.ca/theano/query?status=accepted&status=assigned&status=new&status=reopened&group=milestone&max=200&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&col=time&report=9&order=priority
.. _README: README.html
.. _Quick-Start: README.html#quick-start
.. _Theano Project Documentation Overview: doc/index.html
.. _Mercurial: http://www.selenic.com/mercurial/wiki/
.. _docutils: http://docutils.sourceforge.net
.. _epydoc: http://epydoc.sourceforge.net/
.. _scipy: http://scipy.org/
.. _Python: http://www.python.org/
.. _TRAC: http://trac.edgewall.org/
.. _LISA: http://www.iro.umontreal.ca/rubrique.php3?id_rubrique=27
.. |TRAC| image:: http://www.edgewall.org/gfx/trac_logo.png
:target: http://www.edgewall.org/
:alt: Trac Logo
:align: middle
:class: borderless
:width: 193
:height: 32
.. |Python| image:: python.png
:alt: Python Logo
:align: middle
:class: borderless
:width: 193
:height: 32
.. |LISA| image:: http://www.iro.umontreal.ca/images/neurone_chip2.jpg
:target: http://www.iro.umontreal.ca/rubrique.php3?id_rubrique=27
:width: 193
:height: 32
:alt: LISA Logo
:align: middle
:class: borderless
.. header:: |THEANO| - README_ - Download_ - Documentation_ - Wiki_ - `Task List`_
.. _Download: README.html#downloading-theano
.. _Documentation: doc/index.html
.. _Wiki: http://pylearn.org/theano
.. |THEANO| image:: http://lgcm.iro.umontreal.ca/theano/chrome/site/theano_logo.png
:target: http://pylearn.org/auto_theano
:alt: THEANO
:align: top
:class: borderless
:width: 60
:height: 18
..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
## PENDING REWRITE OF opt.py
import unittest, os, sys, traceback
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py':
modname = filename[:-3]
if modname in ['__init__', 'autotest']: continue
#print >>sys.stderr, 'Loading', modname
try:
module = __import__(modname)
except Exception, e:
if 'relative import' not in e.message:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load module %s" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugparam:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
# TODO: everything?
import sys
import os
import inspect
from epydoc import docintrospecter
from epydoc.apidoc import RoutineDoc
def Op_to_RoutineDoc(op, routine_doc, module_name=None):
routine_doc.specialize_to(RoutineDoc)
#NB: this code is lifted from
# /u/bergstrj/pub/prefix/x86_64-unknown-linux-gnu-Fedora_release_7__Moonshine_/lib/python2.5/site-packages/epydoc
# /u/bergstrj/pub/prefix/x86_64-unknown-linux-gnu-Fedora_release_7__Moonshine_/lib/python2.5/site-packages/epydoc/docintrospecter.py
# op should be an op instance
assert hasattr(op, 'perform')
# Record the function's docstring.
routine_doc.docstring = getattr(op, '__doc__', '')
# Record the function's signature.
func = op.__epydoc_asRoutine
if isinstance(func, type(Op_to_RoutineDoc)):
(args, vararg, kwarg, defaults) = inspect.getargspec(func)
# Add the arguments.
routine_doc.posargs = args
routine_doc.vararg = vararg
routine_doc.kwarg = kwarg
# Set default values for positional arguments.
routine_doc.posarg_defaults = [None]*len(args)
# Set the routine's line number.
if hasattr(func, 'func_code'):
routine_doc.lineno = func.func_code.co_firstlineno
else:
# [XX] I should probably use UNKNOWN here??
# dvarrazzo: if '...' is to be changed, also check that
# `docstringparser.process_arg_field()` works correctly.
# See SF bug #1556024.
routine_doc.posargs = ['...']
routine_doc.posarg_defaults = [None]
routine_doc.kwarg = None
routine_doc.vararg = None
return routine_doc
docintrospecter.register_introspecter(
lambda value: getattr(value, '__epydoc_asRoutine', False),
Op_to_RoutineDoc,
priority=-1)
if __name__ == '__main__':
throot = "/".join(sys.path[0].split("/")[:-1])
os.chdir(throot)
def mkdir(path):
try:
os.mkdir(path)
except OSError:
pass
mkdir("html")
mkdir("html/doc")
mkdir("html/api")
if len(sys.argv) == 1 or sys.argv[1] != 'rst':
from epydoc.cli import cli
sys.path[0:0] = os.path.realpath('.')
sys.argv[:] = ['', '--config', 'doc/api/epydoc.conf', '-o', 'html/api']
cli()
# os.system("epydoc --config doc/api/epydoc.conf -o html/api")
if len(sys.argv) == 1 or sys.argv[1] != 'epydoc':
import sphinx
sys.path[0:0] = [os.path.realpath('doc')]
sphinx.main(['', 'doc', 'html'])
import unittest, os, sys, traceback, commands
theano_path = os.path.realpath("%s/.." % sys.path[0])
sys.path[0:0] = [theano_path]
def test_module(module_path, debugmode = False):
files = commands.getoutput("find %s -name _test_*.py" % module_path)
suite = None
tocut = len("/".join(module_path.split("/")[:-1])) + 1
for file in files.split("\n"):
file = file[tocut:]
try:
module = __import__(file[:-3])
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load %s" % file
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', file
if suite is None:
suite = tests
else:
suite.addTests(tests)
if suite is None:
return
if debugmode:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
def py_test(module_path):
py.test.cmdline.main([module_path])
def nopy_test(module_path):
print >>sys.stderr, "py.test is not installed!"
print >>sys.stderr, " easy_install py"
print >>sys.stderr, "or if you are installing locally"
print >>sys.stderr, " easy_install --prefix=/some/local/dir py"
return None
files = commands.getoutput("find %s -name test_*.py" % module_path)
suite = None
tocut = len("/".join(module_path.split("/")[:-1])) + 1
for file in files.split("\n"):
file = file[tocut:]
try:
module = __import__(file[:-3])
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load %s" % file
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
for method in dir(module):
if method.startswith("test_"):
method = getattr(module, method)
try:
r = method()
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Exception in %s.%s" % (file, method.__name__)
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
if hasattr(r, 'next'):
for fargs in r:
try:
fargs[0](*fargs[1:])
except Exception, e:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Exception in %s.%s, %s%s" % (file, method.__name__, fargs[0], fargs[1:])
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
mname = os.path.join(theano_path, "theano")
test_module(mname)
try:
import py.test
py_test(mname)
except ImportError:
nopy_test(mname)
import unittest, os, sys, traceback
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py':
modname = filename[:-3]
if modname in ['__init__', 'autotest']: continue
#print >>sys.stderr, 'Loading', modname
try:
module = __import__(modname)
except Exception, e:
if 'relative import' not in e.message:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load module %s" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugparam:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
import unittest, os, sys, traceback
if __name__ == '__main__':
def printUsage():
print >>sys.stderr, "Bad argument: ",sys.argv
print >>sys.stderr, "only --debug is supported"
sys.exit(1)
debugparam=""
if len(sys.argv)==2:
if sys.argv[1]=="--debug":
debugparam="--debug"
sys.argv.remove(debugparam)
else:
printUsage()
elif len(sys.argv)>2:
printUsage()
suite = None
filenames = os.listdir('.')
for filename in filenames:
if filename[-3:] == '.py':
modname = filename[:-3]
if modname in ['__init__', 'autotest']: continue
#print >>sys.stderr, 'Loading', modname
try:
module = __import__(modname)
except Exception, e:
if 'relative import' not in e.message:
print >>sys.stderr, "===================================================="
print >>sys.stderr, "Failed to load module %s" % modname
print >>sys.stderr, "===================================================="
traceback.print_exc()
print >>sys.stderr, "===================================================="
continue
tests = unittest.TestLoader().loadTestsFromModule(module)
if tests.countTestCases() > 0:
print >>sys.stderr, 'Testing', modname
if suite is None:
suite = tests
else:
suite.addTests(tests)
if debugparam:
suite.debug()
else:
unittest.TextTestRunner(verbosity=1).run(suite)
...@@ -19,53 +19,7 @@ import graph ...@@ -19,53 +19,7 @@ import graph
import link import link
import utils import utils
def set_compiledir(path=None): from compiledir import *
"""Set the directory into which theano will compile code objects
@param path: an absolute path or relative path. An argument of None will
trigger one of two default paths: firstly an environment variable called
'THEANO_COMPILEDIR' will be sought; failing that, an architecture-specific
directory will be chosen within $HOME/.theano.
@type path: string or None
@return: None
@note: This function will create the path (recursively) as a folder if it
is not present, not readable, or not writable. New folders will be created
with mode 0700.
"""
# N.B. The path is stored as an attribute of this function
if path is None:
# we need to set the default, which can come from one of two places
if os.getenv('THEANO_COMPILEDIR'):
path = os.getenv('THEANO_COMPILEDIR')
else:
platform_id = platform.platform() + '-' + platform.processor()
platform_id = re.sub("[\(\)\s]+", "_", platform_id)
path = os.path.join(os.getenv('HOME'), '.theano', 'compiledir_'+platform_id)
if not os.access(path, os.R_OK | os.W_OK):
os.makedirs(path, 7<<6) #read-write-execute for this user only
# PROBLEM: sometimes the first approach based on os.system('touch')
# returned -1 for an unknown reason; the alternate approach here worked
# in all cases... it was weird.
open(os.path.join(path, '__init__.py'), 'w').close()
set_compiledir.compiledir = path
def get_compiledir():
"""Return the directory where theano code objects should be compiled
@rtype: string
"""
if not hasattr(set_compiledir, 'compiledir'):
set_compiledir()
return set_compiledir.compiledir
class CodeBlock: class CodeBlock:
"""WRITEME """WRITEME
......
import os
import platform
import re
def set_compiledir(path=None):
"""Set the directory into which theano will compile code objects
@param path: an absolute path or relative path. An argument of None will
trigger one of two default paths: firstly an environment variable called
'THEANO_COMPILEDIR' will be sought; failing that, an architecture-specific
directory will be chosen within $HOME/.theano.
@type path: string or None
@return: None
@note: This function will create the path (recursively) as a folder if it
is not present, not readable, or not writable. New folders will be created
with mode 0700.
"""
# N.B. The path is stored as an attribute of this function
if path is None:
# we need to set the default, which can come from one of two places
if os.getenv('THEANO_COMPILEDIR'):
path = os.getenv('THEANO_COMPILEDIR')
else:
platform_id = platform.platform() + '-' + platform.processor()
platform_id = re.sub("[\(\)\s]+", "_", platform_id)
path = os.path.join(os.getenv('HOME'), '.theano', 'compiledir_'+platform_id)
if not os.access(path, os.R_OK | os.W_OK):
os.makedirs(path, 7<<6) #read-write-execute for this user only
# PROBLEM: sometimes the first approach based on os.system('touch')
# returned -1 for an unknown reason; the alternate approach here worked
# in all cases... it was weird.
open(os.path.join(path, '__init__.py'), 'w').close()
set_compiledir.compiledir = path
def get_compiledir():
"""Return the directory where theano code objects should be compiled
@rtype: string
"""
if not hasattr(set_compiledir, 'compiledir'):
set_compiledir()
return set_compiledir.compiledir
from compiledir import *
import sys
try: try:
sys.path.append(get_compiledir())
from cutils_ext import * from cutils_ext import *
except ImportError: except ImportError:
...@@ -27,6 +33,5 @@ except ImportError: ...@@ -27,6 +33,5 @@ except ImportError:
fun =weave.ext_tools.ext_function('run_cthunk', single_runner, ['cthunk']) fun =weave.ext_tools.ext_function('run_cthunk', single_runner, ['cthunk'])
fun.customize.add_extra_compile_arg('--permissive') fun.customize.add_extra_compile_arg('--permissive')
mod.add_function(fun) mod.add_function(fun)
mod.compile() mod.compile(location = get_compiledir())
from cutils_ext import * from cutils_ext import *
import unittest import unittest
from link import PerformLinker, Profiler from theano.gof.link import PerformLinker, Profiler
from cc import * from theano.gof.cc import *
from type import Type from theano.gof.type import Type
from graph import Result, Apply, Constant from theano.gof.graph import Result, Apply, Constant
from op import Op from theano.gof.op import Op
import env from theano.gof import env
import toolbox from theano.gof import toolbox
def as_result(x): def as_result(x):
assert isinstance(x, Result) assert isinstance(x, Result)
...@@ -135,77 +135,76 @@ def Env(inputs, outputs): ...@@ -135,77 +135,76 @@ def Env(inputs, outputs):
return e return e
class _test_CLinker(unittest.TestCase): ################
# Test CLinker #
def test_straightforward(self): ################
x, y, z = inputs()
e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z)) def test_clinker_straightforward():
lnk = CLinker().accept(Env([x, y, z], [e])) x, y, z = inputs()
fn = lnk.make_function() e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z))
self.failUnless(fn(2.0, 2.0, 2.0) == 2.0) lnk = CLinker().accept(Env([x, y, z], [e]))
fn = lnk.make_function()
# def test_orphan(self): assert fn(2.0, 2.0, 2.0) == 2.0
# x, y, z = inputs()
# z = Constant(tdouble, 4.12345678) def test_clinker_literal_inlining():
# e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z)) x, y, z = inputs()
# lnk = CLinker(Env([x, y], [e])) z = Constant(tdouble, 4.12345678)
# fn = lnk.make_function() e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z))
# self.failUnless(abs(fn(2.0, 2.0) + 0.12345678) < 1e-9) lnk = CLinker().accept(Env([x, y], [e]))
# print lnk.code_gen() fn = lnk.make_function()
# self.failUnless("4.12345678" not in lnk.code_gen()) # we do not expect the number to be inlined assert abs(fn(2.0, 2.0) + 0.12345678) < 1e-9
code = lnk.code_gen()
def test_literal_inlining(self): print "=== Code generated ==="
x, y, z = inputs() print code
z = Constant(tdouble, 4.12345678) assert "4.12345678" in code # we expect the number to be inlined
e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z))
lnk = CLinker().accept(Env([x, y], [e])) def test_clinker_single_node():
fn = lnk.make_function() x, y, z = inputs()
self.failUnless(abs(fn(2.0, 2.0) + 0.12345678) < 1e-9) node = add.make_node(x, y)
self.failUnless("4.12345678" in lnk.code_gen()) # we expect the number to be inlined lnk = CLinker().accept(Env(node.inputs, node.outputs))
fn = lnk.make_function()
def test_single_node(self): assert fn(2.0, 7.0) == 9
x, y, z = inputs()
node = add.make_node(x, y) def test_clinker_dups():
lnk = CLinker().accept(Env(node.inputs, node.outputs)) # Testing that duplicate inputs are allowed.
fn = lnk.make_function() x, y, z = inputs()
self.failUnless(fn(2.0, 7.0) == 9) e = add(x, x)
lnk = CLinker().accept(Env([x, x], [e]))
def test_dups(self): fn = lnk.make_function()
# Testing that duplicate inputs are allowed. assert fn(2.0, 2.0) == 4
x, y, z = inputs() # note: for now the behavior of fn(2.0, 7.0) is undefined
e = add(x, x)
lnk = CLinker().accept(Env([x, x], [e])) def test_clinker_dups_inner():
fn = lnk.make_function() # Testing that duplicates are allowed inside the graph
self.failUnless(fn(2.0, 2.0) == 4) x, y, z = inputs()
# note: for now the behavior of fn(2.0, 7.0) is undefined e = add(mul(y, y), add(x, z))
lnk = CLinker().accept(Env([x, y, z], [e]))
def test_dups_inner(self): fn = lnk.make_function()
# Testing that duplicates are allowed inside the graph assert fn(1.0, 2.0, 3.0) == 8.0
x, y, z = inputs()
e = add(mul(y, y), add(x, z))
lnk = CLinker().accept(Env([x, y, z], [e]))
fn = lnk.make_function()
self.failUnless(fn(1.0, 2.0, 3.0) == 8.0)
class _test_OpWiseCLinker(unittest.TestCase): ######################
# Test OpWiseCLinker #
######################
def test_opwiseclinker_straightforward():
x, y, z = inputs()
e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z))
lnk = OpWiseCLinker().accept(Env([x, y, z], [e]))
fn = lnk.make_function()
assert fn(2.0, 2.0, 2.0) == 2.0
def test_opwiseclinker_constant():
x, y, z = inputs()
x = Constant(tdouble, 7.2, name = 'x')
e = add(mul(x, y), mul(y, z))
lnk = OpWiseCLinker().accept(Env([y, z], [e]))
fn = lnk.make_function()
res = fn(1.5, 3.0)
assert res == 15.3
def test_straightforward(self):
x, y, z = inputs()
e = add(mul(add(x, y), div(x, y)), sub(sub(x, y), z))
lnk = OpWiseCLinker().accept(Env([x, y, z], [e]))
fn = lnk.make_function()
self.failUnless(fn(2.0, 2.0, 2.0) == 2.0)
def test_constant(self):
x, y, z = inputs()
x = Constant(tdouble, 7.2, name = 'x')
e = add(mul(x, y), mul(y, z))
lnk = OpWiseCLinker().accept(Env([y, z], [e]))
fn = lnk.make_function()
res = fn(1.5, 3.0)
self.failUnless(res == 15.3, res)
class MyExc(Exception): class MyExc(Exception):
...@@ -215,49 +214,34 @@ def _my_checker(x, y): ...@@ -215,49 +214,34 @@ def _my_checker(x, y):
raise MyExc("Output mismatch.", {'performlinker': x[0], 'clinker': y[0]}) raise MyExc("Output mismatch.", {'performlinker': x[0], 'clinker': y[0]})
class _test_DualLinker(unittest.TestCase): ###################
# Test DualLinker #
def test_straightforward(self): ###################
x, y, z = inputs()
e = add(mul(x, y), mul(y, z)) # add and mul are correct in C and in Python def test_duallinker_straightforward():
lnk = DualLinker(checker = _my_checker).accept(Env([x, y, z], [e])) x, y, z = inputs()
fn = lnk.make_function() e = add(mul(x, y), mul(y, z)) # add and mul are correct in C and in Python
res = fn(7.2, 1.5, 3.0) lnk = DualLinker(checker = _my_checker).accept(Env([x, y, z], [e]))
self.failUnless(res == 15.3, res) fn = lnk.make_function()
res = fn(7.2, 1.5, 3.0)
def test_mismatch(self): assert res == 15.3
x, y, z = inputs()
e = sub(mul(x, y), mul(y, z)) # sub is correct in C but erroneous in Python def test_duallinker_mismatch():
g = Env([x, y, z], [e]) x, y, z = inputs()
lnk = DualLinker(checker = _my_checker).accept(g) e = sub(mul(x, y), mul(y, z)) # sub is correct in C but erroneous in Python
fn = lnk.make_function() g = Env([x, y, z], [e])
lnk = DualLinker(checker = _my_checker).accept(g)
self.failUnless(CLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0) # good fn = lnk.make_function()
self.failUnless(OpWiseCLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0) # good
self.failUnless(PerformLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -10.0) # (purposely) wrong assert CLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0 # good
assert OpWiseCLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -4.0 # good
try: assert PerformLinker().accept(g).make_function()(1.0, 2.0, 3.0) == -10.0 # (purposely) wrong
# this runs OpWiseCLinker and PerformLinker in parallel and feeds
# results of matching operations to _my_checker to verify that they try:
# are the same. # this runs OpWiseCLinker and PerformLinker in parallel and feeds
res = fn(1.0, 2.0, 3.0) # results of matching operations to _my_checker to verify that they
self.fail() # are the same.
except MyExc, e: res = fn(1.0, 2.0, 3.0)
pass raise Exception("An exception should have been raised here!")
else: except MyExc, e:
self.fail() pass
# def test_orphan(self):
# x, y, z = inputs()
# x = Constant(tdouble, 7.2, name = 'x')
# e = add(mul(x, y), mul(y, z)) # add and mul are correct in C and in Python
# lnk = DualLinker(Env([y, z], [e]), checker = _my_checker)
# fn = lnk.make_function()
# res = fn(1.5, 3.0)
# self.failUnless(res == 15.3, res)
if __name__ == '__main__':
unittest.main()
import unittest
from theano.gof.type import Type
from theano.gof import graph
from theano.gof.graph import Result, Apply
from theano.gof.op import Op
from theano.gof.opt import *
from theano.gof import destroyhandler
from theano.gof.env import Env, InconsistencyError
from theano.gof.toolbox import ReplaceValidate
from copy import copy
PatternOptimizer = lambda p1, p2, ign=True: OpKeyOptimizer(PatternSub(p1, p2), ignore_newtrees=ign)
OpSubOptimizer = lambda op1, op2, fail=keep_going, ign=True: TopoOptimizer(OpSub(op1, op2), ignore_newtrees=ign, failure_callback = fail)
def as_result(x):
assert isinstance(x, Result)
return x
class MyType(Type):
def filter(self, data):
return data
def __eq__(self, other):
return isinstance(other, MyType)
def MyResult(name):
return Result(MyType(), None, None, name = name)
def MyValue(data):
return graph.Value(MyType(), data = data)
class MyOp(Op):
def __init__(self, nin, name, vmap = {}, dmap = {}, nout = 1, tolerate_same = []):
self.nin = nin
self.nout = nout
self.name = name
self.destroy_map = dmap
self.view_map = vmap
self.tolerate_same = tolerate_same
def make_node(self, *inputs):
assert len(inputs) == self.nin
inputs = map(as_result, inputs)
for input in inputs:
if not isinstance(input.type, MyType):
raise Exception("Error 1")
outputs = [MyResult(self.name + "_R") for i in xrange(self.nout)]
return Apply(self, inputs, outputs)
def __str__(self):
return self.name
sigmoid = MyOp(1, 'Sigmoid')
transpose_view = MyOp(1, 'TransposeView', vmap = {0: [0]})
add = MyOp(2, 'Add')
add_in_place = MyOp(2, 'AddInPlace', dmap = {0: [0]})
add_in_place_2 = MyOp(2, 'AddInPlace', dmap = {0: [0]}, tolerate_same = [(0, 1)])
dot = MyOp(2, 'Dot')
def inputs():
x = MyResult('x')
y = MyResult('y')
z = MyResult('z')
return x, y, z
_Env = Env
def Env(inputs, outputs, validate = True):
e = _Env(inputs, outputs)
e.extend(destroyhandler.DestroyHandler())
e.extend(ReplaceValidate())
if validate:
e.validate()
return e
class FailureWatch:
# when passed to OpSubOptimizer or PatternOptimizer, counts the number of failures
def __init__(self):
self.failures = 0
def __call__(self, exc, nav, pairs):
assert isinstance(exc, InconsistencyError)
self.failures += 1
def consistent(g):
print "Testing consistent:", g
try:
assert g.consistent()
except AssertionError:
print "Test failed! The graph was marked as NOT consistent."
raise
print "Test OK"
def inconsistent(g):
print "Testing NOT consistent:", g
try:
assert not g.consistent()
except AssertionError:
print "Test failed! The graph was marked as consistent."
raise
print "Test OK"
#################
# Test protocol #
#################
def test_misc():
x, y, z = inputs()
e = transpose_view(transpose_view(transpose_view(transpose_view(x))))
g = Env([x,y,z], [e])
consistent(g)
chk = g.checkpoint()
PatternOptimizer((transpose_view, (transpose_view, 'x')), 'x').optimize(g)
assert str(g) == "[x]"
new_e = add(x,y)
g.replace_validate(x, new_e)
assert str(g) == "[Add(x, y)]"
g.replace(new_e, dot(add_in_place(x,y), transpose_view(x)))
assert str(g) == "[Dot(AddInPlace(x, y), TransposeView(x))]"
inconsistent(g)
g.revert(chk)
consistent(g)
assert str(g) == "[TransposeView(TransposeView(TransposeView(TransposeView(x))))]"
######################
# Test protocol skip #
######################
def test_aliased_inputs_replacement():
x, y, z = inputs()
tv = transpose_view(x)
tvv = transpose_view(tv)
sx = sigmoid(x)
e = add_in_place(x, tv)
g = Env([x, y], [e], False)
inconsistent(g)
g.replace(tv, sx)
consistent(g)
g.replace(sx, tv)
inconsistent(g)
g.replace(tv, tvv)
inconsistent(g)
g.replace(tv, sx)
consistent(g)
def test_indestructible():
x, y, z = inputs()
x.tag.indestructible = True
x = copy(x)
assert x.tag.indestructible # checking if indestructible survives the copy!
e = add_in_place(x, y)
g = Env([x,y,z], [e], False)
inconsistent(g)
g.replace_validate(e, add(x, y))
consistent(g)
def test_usage_loop_through_views_2():
x, y, z = inputs()
e0 = transpose_view(transpose_view(sigmoid(x)))
e = dot(add_in_place(x,y), transpose_view(e0))
g = Env([x,y,z], [e])
consistent(g) # because sigmoid can do the copy
g.replace(e0, x)
inconsistent(g) # we cut off the path to the sigmoid
def test_destroyers_loop():
# AddInPlace(x, y) and AddInPlace(y, x) should not coexist
x, y, z = inputs()
e1 = add(x, y)
e2 = add(y, x)
g = Env([x,y,z], [e1, e2])
chk = g.checkpoint()
consistent(g)
g.replace_validate(e1, add_in_place(x, y))
consistent(g)
try:
g.replace_validate(e2, add_in_place(y, x))
raise Exception("Shouldn't have reached this point.")
except InconsistencyError:
pass
consistent(g)
g.revert(chk)
g.replace_validate(e2, add_in_place(y, x))
consistent(g)
try:
g.replace_validate(e1, add_in_place(x, y))
raise Exception("Shouldn't have reached this point.")
except InconsistencyError:
pass
consistent(g)
########
# Misc #
########
def test_aliased_inputs():
x, y, z = inputs()
e = add_in_place(x, x)
g = Env([x], [e], False)
inconsistent(g)
def test_aliased_inputs2():
x, y, z = inputs()
e = add_in_place(x, transpose_view(x))
g = Env([x], [e], False)
inconsistent(g)
def test_aliased_inputs_tolerate():
x, y, z = inputs()
e = add_in_place_2(x, x)
g = Env([x], [e], False)
consistent(g)
def test_aliased_inputs_tolerate2():
x, y, z = inputs()
e = add_in_place_2(x, transpose_view(x))
g = Env([x], [e], False)
inconsistent(g)
def test_indestructible_through_views():
x, y, z = inputs()
x.tag.indestructible = True
tv = transpose_view(x)
e = add_in_place(tv, y)
g = Env([x,y,z], [e], False)
inconsistent(g)
g.replace_validate(tv, sigmoid(x))
consistent(g)
def test_indirect():
x, y, z = inputs()
e0 = add_in_place(x, y)
e = dot(sigmoid(e0), transpose_view(x))
g = Env([x,y,z], [e], False)
inconsistent(g)
new_e0 = add(x, y)
g.replace(e0, new_e0)
consistent(g)
g.replace(new_e0, add_in_place(x, y))
inconsistent(g)
def test_indirect_2():
x, y, z = inputs()
e0 = transpose_view(x)
e = dot(sigmoid(add_in_place(x, y)), e0)
g = Env([x,y,z], [e], False)
inconsistent(g)
new_e0 = add(e0, y)
g.replace(e0, new_e0)
consistent(g)
def test_long_destroyers_loop():
x, y, z = inputs()
e = dot(dot(add_in_place(x,y), add_in_place(y,z)), add(z,x))
g = Env([x,y,z], [e])
consistent(g)
OpSubOptimizer(add, add_in_place).optimize(g)
consistent(g)
assert str(g) != "[Dot(Dot(AddInPlace(x, y), AddInPlace(y, z)), AddInPlace(z, x))]" # we don't want to see that!
e2 = dot(dot(add_in_place(x,y), add_in_place(y,z)), add_in_place(z,x))
try:
g2 = Env(*graph.clone([x,y,z], [e2]))
raise Exception("Shouldn't have reached this point.")
except InconsistencyError:
pass
def test_misc_2():
x, y, z = inputs()
tv = transpose_view(x)
e = add_in_place(x, tv)
g = Env([x,y], [e], False)
inconsistent(g)
g.replace(tv, x)
inconsistent(g)
def test_multi_destroyers():
x, y, z = inputs()
e = add(add_in_place(x, y), add_in_place(x, y))
try:
g = Env([x,y,z], [e])
raise Exception("Shouldn't have reached this point.")
except InconsistencyError, e:
pass
def test_multi_destroyers_through_views():
x, y, z = inputs()
e = dot(add(transpose_view(z), y), add(z, x))
g = Env([x,y,z], [e])
consistent(g)
fail = FailureWatch()
OpSubOptimizer(add, add_in_place, fail).optimize(g)
consistent(g)
assert fail.failures == 1 # should have succeeded once and failed once
def test_repair_destroy_path():
x, y, z = inputs()
e1 = transpose_view(transpose_view(x))
e2 = transpose_view(transpose_view(e1))
e3 = add_in_place(e2, y)
e4 = add_in_place(e1, z)
g = Env([x,y,z], [e3, e4], False)
inconsistent(g)
g.replace(e2, transpose_view(x))
inconsistent(g)
def test_usage_loop():
x, y, z = inputs()
g = Env([x,y,z], [dot(add_in_place(x, z), x)], False)
inconsistent(g)
OpSubOptimizer(add_in_place, add).optimize(g) # replace add_in_place with add
consistent(g)
def test_usage_loop_through_views():
x, y, z = inputs()
aip = add_in_place(x, y)
e = dot(aip, transpose_view(x))
g = Env([x,y,z], [e], False)
inconsistent(g)
g.replace_validate(aip, add(x, z))
consistent(g)
def test_usage_loop_insert_views():
x, y, z = inputs()
e = dot(add_in_place(x, add(y, z)), sigmoid(sigmoid(sigmoid(sigmoid(sigmoid(x))))))
g = Env([x,y,z], [e])
consistent(g)
fail = FailureWatch()
OpSubOptimizer(sigmoid, transpose_view, fail).optimize(g)
consistent(g)
assert fail.failures == 1 # it must keep one sigmoid in the long sigmoid chain
def test_value_repl():
x, y, z = inputs()
sy = sigmoid(y)
e = add_in_place(x, sy)
g = Env([x,y], [e], False)
consistent(g)
g.replace(sy, MyValue("abc"))
consistent(g)
def test_value_repl_2():
x, y, z = inputs()
sy = sigmoid(y)
e = add_in_place(x, sy)
g = Env([x,y], [e], False)
consistent(g)
g.replace(sy, transpose_view(MyValue("abc")))
consistent(g)
from collections import deque from collections import deque
import unittest from theano.gof.graph import *
from graph import *
from op import Op from theano.gof.op import Op
from type import Type from theano.gof.type import Type
from graph import Result from theano.gof.graph import Result
if 1:
testcase = unittest.TestCase
else:
testcase = object
realtestcase = unittest.TestCase
def as_result(x): def as_result(x):
...@@ -55,75 +47,31 @@ class MyOp(Op): ...@@ -55,75 +47,31 @@ class MyOp(Op):
MyOp = MyOp() MyOp = MyOp()
##########
# inputs #
##########
# class MyResult(Result): class TestInputs:
# def __init__(self, thingy):
# self.thingy = thingy
# Result.__init__(self, role = None )
# self.data = [self.thingy]
# def __eq__(self, other):
# return self.same_properties(other)
# def same_properties(self, other):
# return isinstance(other, MyResult) and other.thingy == self.thingy
# def __str__(self):
# return str(self.thingy)
# def __repr__(self):
# return str(self.thingy)
# class MyOp(Op): def test_inputs(self):
# def __init__(self, *inputs):
# for input in inputs:
# if not isinstance(input, MyResult):
# raise Exception("Error 1")
# self.inputs = inputs
# self.outputs = [MyResult(sum([input.thingy for input in inputs]))]
class _test_inputs(testcase):
def test_straightforward(self):
r1, r2 = MyResult(1), MyResult(2) r1, r2 = MyResult(1), MyResult(2)
node = MyOp.make_node(r1, r2) node = MyOp.make_node(r1, r2)
assert inputs(node.outputs) == [r1, r2] assert inputs(node.outputs) == [r1, r2]
def test_deep(self): def test_inputs_deep(self):
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
node = MyOp.make_node(r1, r2) node = MyOp.make_node(r1, r2)
node2 = MyOp.make_node(node.outputs[0], r5) node2 = MyOp.make_node(node.outputs[0], r5)
i = inputs(node2.outputs) i = inputs(node2.outputs)
self.failUnless(i == [r1, r2, r5], i) assert i == [r1, r2, r5], i
# def test_unreached_inputs(self):
# r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) #############
# op = MyOp(r1, r2) # as_string #
# op2 = MyOp(op.outputs[0], r5) #############
# try:
# # function doesn't raise if we put False instead of True
# ro = results_and_orphans([r1, r2, op2.outputs[0]], op.outputs, True)
# except Exception, e:
# if e[0] is results_and_orphans.E_unreached:
# return
# self.fail()
# class _test_orphans(testcase):
# def test_straightforward(self):
# r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
# node = MyOp.make_node(r1, r2)
# node2 = MyOp.make_node(node.outputs[0], r5)
# orph = orphans([r1, r2], node2.outputs)
# self.failUnless(orph == [r5], orph)
class _test_as_string(testcase): class X:
leaf_formatter = lambda self, leaf: str(leaf.type) leaf_formatter = lambda self, leaf: str(leaf.type)
node_formatter = lambda self, node, argstrings: "%s(%s)" % (node.op, node_formatter = lambda self, node, argstrings: "%s(%s)" % (node.op,
...@@ -133,19 +81,22 @@ class _test_as_string(testcase): ...@@ -133,19 +81,22 @@ class _test_as_string(testcase):
return as_string(inputs, outputs, return as_string(inputs, outputs,
leaf_formatter = self.leaf_formatter, leaf_formatter = self.leaf_formatter,
node_formatter = self.node_formatter) node_formatter = self.node_formatter)
class TestStr(X):
def test_straightforward(self): def test_as_string(self):
r1, r2 = MyResult(1), MyResult(2) r1, r2 = MyResult(1), MyResult(2)
node = MyOp.make_node(r1, r2) node = MyOp.make_node(r1, r2)
s = self.str([r1, r2], node.outputs) s = self.str([r1, r2], node.outputs)
self.failUnless(s == ["MyOp(R1, R2)"], s) assert s == ["MyOp(R1, R2)"]
def test_deep(self): def test_as_string_deep(self):
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
node = MyOp.make_node(r1, r2) node = MyOp.make_node(r1, r2)
node2 = MyOp.make_node(node.outputs[0], r5) node2 = MyOp.make_node(node.outputs[0], r5)
s = self.str([r1, r2, r5], node2.outputs) s = self.str([r1, r2, r5], node2.outputs)
self.failUnless(s == ["MyOp(MyOp(R1, R2), R5)"], s) assert s == ["MyOp(MyOp(R1, R2), R5)"]
def test_multiple_references(self): def test_multiple_references(self):
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
...@@ -161,16 +112,11 @@ class _test_as_string(testcase): ...@@ -161,16 +112,11 @@ class _test_as_string(testcase):
assert self.str(node2.inputs, node2.outputs) == ["MyOp(R3, R3)"] assert self.str(node2.inputs, node2.outputs) == ["MyOp(R3, R3)"]
class _test_clone(testcase): #########
# clone #
leaf_formatter = lambda self, leaf: str(leaf.type) #########
node_formatter = lambda self, node, argstrings: "%s(%s)" % (node.op,
", ".join(argstrings))
def str(self, inputs, outputs): class TestClone(X):
return as_string(inputs, outputs,
leaf_formatter = self.leaf_formatter,
node_formatter = self.node_formatter)
def test_accurate(self): def test_accurate(self):
r1, r2 = MyResult(1), MyResult(2) r1, r2 = MyResult(1), MyResult(2)
...@@ -198,6 +144,11 @@ class _test_clone(testcase): ...@@ -198,6 +144,11 @@ class _test_clone(testcase):
assert self.str(inputs(new_node.outputs), new_node.outputs) == ["MyOp(R7, R8)"] assert self.str(inputs(new_node.outputs), new_node.outputs) == ["MyOp(R7, R8)"]
assert self.str(inputs(node.outputs), node.outputs) == ["MyOp(MyOp(R1, R2), R5)"] assert self.str(inputs(node.outputs), node.outputs) == ["MyOp(MyOp(R1, R2), R5)"]
############
# toposort #
############
def prenode(obj): def prenode(obj):
if isinstance(obj, Result): if isinstance(obj, Result):
if obj.owner: if obj.owner:
...@@ -205,79 +156,64 @@ def prenode(obj): ...@@ -205,79 +156,64 @@ def prenode(obj):
if isinstance(obj, Apply): if isinstance(obj, Apply):
return obj.inputs return obj.inputs
class _test_toposort(testcase): class TestToposort:
def test0(self):
def test_0(self):
"""Test a simple graph""" """Test a simple graph"""
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
o = MyOp.make_node(r1, r2) o = MyOp.make_node(r1, r2)
o2 = MyOp.make_node(o.outputs[0], r5) o2 = MyOp.make_node(o.outputs[0], r5)
all = general_toposort(o2.outputs, prenode) all = general_toposort(o2.outputs, prenode)
self.failUnless(all == [r5, r2, r1, o, o.outputs[0], o2, o2.outputs[0]], all) assert all == [r5, r2, r1, o, o.outputs[0], o2, o2.outputs[0]]
all = io_toposort([r5], o2.outputs) all = io_toposort([r5], o2.outputs)
self.failUnless(all == [o, o2], all) assert all == [o, o2]
def test1(self): def test_1(self):
"""Test a graph with double dependencies""" """Test a graph with double dependencies"""
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
o = MyOp.make_node(r1, r1) o = MyOp.make_node(r1, r1)
o2 = MyOp.make_node(o.outputs[0], r5) o2 = MyOp.make_node(o.outputs[0], r5)
all = general_toposort(o2.outputs, prenode) all = general_toposort(o2.outputs, prenode)
self.failUnless(all == [r5, r1, o, o.outputs[0], o2, o2.outputs[0]], all) assert all == [r5, r1, o, o.outputs[0], o2, o2.outputs[0]]
def test2(self): def test_2(self):
"""Test a graph where the inputs have owners""" """Test a graph where the inputs have owners"""
r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5) r1, r2, r5 = MyResult(1), MyResult(2), MyResult(5)
o = MyOp.make_node(r1, r1) o = MyOp.make_node(r1, r1)
r2b = o.outputs[0] r2b = o.outputs[0]
o2 = MyOp.make_node(r2b, r2b) o2 = MyOp.make_node(r2b, r2b)
all = io_toposort([r2b], o2.outputs) all = io_toposort([r2b], o2.outputs)
self.failUnless(all == [o2], all) assert all == [o2]
o2 = MyOp.make_node(r2b, r5) o2 = MyOp.make_node(r2b, r5)
all = io_toposort([r2b], o2.outputs) all = io_toposort([r2b], o2.outputs)
self.failUnless(all == [o2], all) assert all == [o2]
def test3(self): def test_3(self):
"""Test a graph which is not connected""" """Test a graph which is not connected"""
r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4) r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4)
o0 = MyOp.make_node(r1, r2) o0 = MyOp.make_node(r1, r2)
o1 = MyOp.make_node(r3, r4) o1 = MyOp.make_node(r3, r4)
all = io_toposort([r1, r2, r3, r4], o0.outputs + o1.outputs) all = io_toposort([r1, r2, r3, r4], o0.outputs + o1.outputs)
self.failUnless(all == [o1,o0], all) assert all == [o1,o0]
def test4(self): def test_4(self):
"""Test inputs and outputs mixed together in a chain graph""" """Test inputs and outputs mixed together in a chain graph"""
r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4) r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4)
o0 = MyOp.make_node(r1, r2) o0 = MyOp.make_node(r1, r2)
o1 = MyOp.make_node(o0.outputs[0], r1) o1 = MyOp.make_node(o0.outputs[0], r1)
all = io_toposort([r1, o0.outputs[0]], [o0.outputs[0], o1.outputs[0]]) all = io_toposort([r1, o0.outputs[0]], [o0.outputs[0], o1.outputs[0]])
self.failUnless(all == [o1], all) assert all == [o1]
def test5(self): def test_5(self):
"""Test when outputs have clients""" """Test when outputs have clients"""
r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4) r1, r2, r3, r4 = MyResult(1), MyResult(2), MyResult(3), MyResult(4)
o0 = MyOp.make_node(r1, r2) o0 = MyOp.make_node(r1, r2)
o1 = MyOp.make_node(o0.outputs[0], r4) o1 = MyOp.make_node(o0.outputs[0], r4)
all = io_toposort([], o0.outputs) all = io_toposort([], o0.outputs)
self.failUnless(all == [o0], all) assert all == [o0]
if __name__ == '__main__':
if 1:
#run all tests
unittest.main()
elif 1:
#load some TestCase classes
suite = unittest.TestLoader()
suite = suite.loadTestsFromTestCase(_test_toposort)
#run just some of them
unittest.TextTestRunner(verbosity=2).run(suite)
else:
#run just a single test
_test_toposort('test0').debug()
from theano.gof import graph
from theano.gof.graph import Result, Apply, Constant
from theano.gof.type import Type
from theano.gof.op import Op
from theano.gof import env
from theano.gof import toolbox
import unittest from theano.gof.link import *
import graph
from graph import Result, Apply, Constant
from type import Type
from op import Op
import env
import toolbox
from link import *
#from _test_result import Double #from _test_result import Double
...@@ -78,7 +75,7 @@ def Env(inputs, outputs): ...@@ -78,7 +75,7 @@ def Env(inputs, outputs):
return e return e
class _test_PerformLinker(unittest.TestCase): class TestPerformLinker:
def test_thunk(self): def test_thunk(self):
x, y, z = inputs() x, y, z = inputs()
...@@ -105,14 +102,14 @@ class _test_PerformLinker(unittest.TestCase): ...@@ -105,14 +102,14 @@ class _test_PerformLinker(unittest.TestCase):
def test_input_output_same(self): def test_input_output_same(self):
x, y, z = inputs() x, y, z = inputs()
fn = perform_linker(Env([x], [x])).make_function() fn = perform_linker(Env([x], [x])).make_function()
self.failUnless(1.0 is fn(1.0)) assert 1.0 is fn(1.0)
def test_input_dependency0(self): def test_input_dependency0(self):
x, y, z = inputs() x, y, z = inputs()
a,d = add(x,y), div(x,y) a,d = add(x,y), div(x,y)
e = mul(a,d) e = mul(a,d)
fn = perform_linker(Env(*graph.clone([x, y, a], [e]))).make_function() fn = perform_linker(Env(*graph.clone([x, y, a], [e]))).make_function()
self.failUnless(fn(1.0,2.0,9.0) == 4.5) assert fn(1.0,2.0,9.0) == 4.5
def test_skiphole(self): def test_skiphole(self):
x,y,z = inputs() x,y,z = inputs()
...@@ -120,14 +117,16 @@ class _test_PerformLinker(unittest.TestCase): ...@@ -120,14 +117,16 @@ class _test_PerformLinker(unittest.TestCase):
r = raise_err(a) r = raise_err(a)
e = add(r,a) e = add(r,a)
fn = perform_linker(Env(*graph.clone([x, y,r], [e]))).make_function() fn = perform_linker(Env(*graph.clone([x, y,r], [e]))).make_function()
self.failUnless(fn(1.0,2.0,4.5) == 7.5) assert fn(1.0,2.0,4.5) == 7.5
def wrap_linker(env, linkers, wrapper): def wrap_linker(env, linkers, wrapper):
lnk = WrapLinker(linkers, wrapper).accept(env) lnk = WrapLinker(linkers, wrapper).accept(env)
return lnk return lnk
class _test_WrapLinker(unittest.TestCase):
def test0(self): class TestWrapLinker:
def test_0(self):
nodes = [] nodes = []
def wrap(i, node, th): def wrap(i, node, th):
nodes.append(node.op) nodes.append(node.op)
...@@ -138,10 +137,10 @@ class _test_WrapLinker(unittest.TestCase): ...@@ -138,10 +137,10 @@ class _test_WrapLinker(unittest.TestCase):
i[0].data = 1 i[0].data = 1
i[1].data = 2 i[1].data = 2
fn() fn()
self.failUnless(nodes == [div, add, mul], nodes) assert nodes == [div, add, mul]
self.failUnless(o[0].data is None) assert o[0].data is None
def test1(self): def test_1(self):
nodes = [] nodes = []
def wrap(i, node, th): def wrap(i, node, th):
nodes.append(node.op) nodes.append(node.op)
...@@ -153,44 +152,8 @@ class _test_WrapLinker(unittest.TestCase): ...@@ -153,44 +152,8 @@ class _test_WrapLinker(unittest.TestCase):
i[0].data = 1 i[0].data = 1
i[1].data = 2 i[1].data = 2
fn() fn()
self.failUnless(nodes == [div, add, mul], nodes) assert nodes == [div, add, mul]
self.failUnless(o[0].data == 1.5, o[0].data) assert o[0].data == 1.5
# def test_disconnected_input_output(self):
# x,y,z = inputs()
# a = add(x,y)
# a.data = 3.0 # simulate orphan calculation
# fn = perform_linker(env([z], [a])).make_function(inplace=True)
# self.failUnless(fn(1.0) == 3.0)
# self.failUnless(fn(2.0) == 3.0)
# def test_thunk_inplace(self):
# x, y, z = inputs()
# e = mul(add(x, y), div(x, y))
# fn, i, o = perform_linker(Env([x, y, z], [e])).make_thunk(True)
# fn()
# assert e.data == 1.5
# def test_thunk_not_inplace(self):
# x, y, z = inputs()
# e = mul(add(x, y), div(x, y))
# fn, i, o = perform_linker(env([x, y, z], [e])).make_thunk(False)
# fn()
# assert o[0].data == 1.5
# assert e.data != 1.5
# def test_function(self):
# x, y, z = inputs()
# e = mul(add(x, y), div(x, y))
# fn = perform_linker(env([x, y, z], [e])).make_function()
# assert fn(1.0, 2.0, 3.0) == 1.5
# assert e.data != 1.5 # not inplace
if __name__ == '__main__':
unittest.main()
......
import unittest
from copy import copy from copy import copy
from op import * from theano.gof.op import *
from type import Type, Generic from theano.gof.type import Type, Generic
from graph import Apply, Result from theano.gof.graph import Apply, Result
def as_result(x): def as_result(x):
assert isinstance(x, Result) assert isinstance(x, Result)
...@@ -38,7 +37,7 @@ class MyOp(Op): ...@@ -38,7 +37,7 @@ class MyOp(Op):
MyOp = MyOp() MyOp = MyOp()
class _test_Op(unittest.TestCase): class TestOp:
# Sanity tests # Sanity tests
def test_sanity_0(self): def test_sanity_0(self):
......
import unittest from theano.gof.type import Type
from theano.gof.graph import Result, Apply, Constant
from type import Type from theano.gof.op import Op
from graph import Result, Apply, Constant from theano.gof.opt import *
from op import Op from theano.gof.env import Env
from opt import * from theano.gof.toolbox import *
from env import Env
from toolbox import *
def as_result(x): def as_result(x):
...@@ -73,7 +71,7 @@ def inputs(): ...@@ -73,7 +71,7 @@ def inputs():
PatternOptimizer = lambda p1, p2, ign=False: OpKeyOptimizer(PatternSub(p1, p2), ignore_newtrees=ign) PatternOptimizer = lambda p1, p2, ign=False: OpKeyOptimizer(PatternSub(p1, p2), ignore_newtrees=ign)
TopoPatternOptimizer = lambda p1, p2, ign=True: TopoOptimizer(PatternSub(p1, p2), ignore_newtrees=ign) TopoPatternOptimizer = lambda p1, p2, ign=True: TopoOptimizer(PatternSub(p1, p2), ignore_newtrees=ign)
class _test_PatternOptimizer(unittest.TestCase): class TestPatternOptimizer:
def test_replace_output(self): def test_replace_output(self):
# replacing the whole graph # replacing the whole graph
...@@ -250,7 +248,7 @@ class _test_PatternOptimizer(unittest.TestCase): ...@@ -250,7 +248,7 @@ class _test_PatternOptimizer(unittest.TestCase):
OpSubOptimizer = lambda op1, op2: TopoOptimizer(OpSub(op1, op2)) OpSubOptimizer = lambda op1, op2: TopoOptimizer(OpSub(op1, op2))
OpSubOptimizer = lambda op1, op2: OpKeyOptimizer(OpSub(op1, op2)) OpSubOptimizer = lambda op1, op2: OpKeyOptimizer(OpSub(op1, op2))
class _test_OpSubOptimizer(unittest.TestCase): class TestOpSubOptimizer:
def test_straightforward(self): def test_straightforward(self):
x, y, z = inputs() x, y, z = inputs()
...@@ -267,7 +265,7 @@ class _test_OpSubOptimizer(unittest.TestCase): ...@@ -267,7 +265,7 @@ class _test_OpSubOptimizer(unittest.TestCase):
assert str(g) == "[Op1(Op2(x), Op4(y), Op4(z))]" assert str(g) == "[Op1(Op2(x), Op4(y), Op4(z))]"
class _test_MergeOptimizer(unittest.TestCase): class TestMergeOptimizer:
def test_straightforward(self): def test_straightforward(self):
x, y, z = inputs() x, y, z = inputs()
...@@ -330,42 +328,6 @@ class _test_MergeOptimizer(unittest.TestCase): ...@@ -330,42 +328,6 @@ class _test_MergeOptimizer(unittest.TestCase):
g = Env([x, y, z], [e1]) g = Env([x, y, z], [e1])
MergeOptimizer().optimize(g) MergeOptimizer().optimize(g)
strg = str(g) strg = str(g)
self.failUnless(strg == '[Op1(y, y)]' or strg == '[Op1(z, z)]', strg) assert strg == '[Op1(y, y)]' or strg == '[Op1(z, z)]'
# def test_identical_constant_args_with_destroymap(self):
# x, y, z = inputs()
# y.data = 2.0
# y.constant = False
# z.data = 2.0
# z.constant = True
# e1 = op_d(y, z)
# g = env([x, y, z], [e1])
# MergeOptimizer().optimize(g)
# strg = str(g)
# self.failUnless(strg == '[OpD(y, z)]', strg)
# def test_merge_with_destroyer_1(self):
# x, y, z = inputs()
# e1 = op_d(op1(x,y), y)
# e2 = op_d(op1(x,y), z)
# g = env([x, y, z], [e1,e2])
# MergeOptimizer().optimize(g)
# strg = str(g)
# self.failUnless(strg == '[OpD(Op1(x, y), y), OpD(Op1(x, y), z)]', strg)
# def test_merge_with_destroyer_2(self):
# x, y, z = inputs()
# e1 = op_d(op1(x,y), z)
# e2 = op_d(op1(x,y), z)
# g = env([x, y, z], [e1,e2])
# MergeOptimizer().optimize(g)
# strg = str(g)
# self.failUnless(strg == '[*1 -> OpD(Op1(x, y), z), *1]', strg)
if __name__ == '__main__':
unittest.main()
import unittest from theano.gof.graph import Result, Apply
from theano.gof.type import Type
from theano.gof.op import Op
from graph import Result, Apply from theano.gof.env import Env, InconsistencyError
from type import Type from theano.gof.toolbox import *
from op import Op
from env import Env, InconsistencyError
from toolbox import *
def as_result(x): def as_result(x):
...@@ -63,22 +61,8 @@ def inputs(): ...@@ -63,22 +61,8 @@ def inputs():
return x, y, z return x, y, z
# class _test_EquivTool(unittest.TestCase):
# def test_straightforward(self):
# x, y, z = inputs()
# sx = sigmoid(x)
# e = add(sx, sigmoid(y))
# g = Env([x, y, z], [e])
# g.extend(EquivTool(g))
# assert hasattr(g, 'equiv')
# assert g.equiv(sx) is sx
# g.replace(sx, dot(x, z))
# assert g.equiv(sx) is not sx
# assert g.equiv(sx).owner.op is dot
class _test_NodeFinder(unittest.TestCase): class TestNodeFinder:
def test_straightforward(self): def test_straightforward(self):
x, y, z = inputs() x, y, z = inputs()
...@@ -89,7 +73,7 @@ class _test_NodeFinder(unittest.TestCase): ...@@ -89,7 +73,7 @@ class _test_NodeFinder(unittest.TestCase):
assert hasattr(g, 'get_nodes') assert hasattr(g, 'get_nodes')
for type, num in ((add, 3), (sigmoid, 3), (dot, 2)): for type, num in ((add, 3), (sigmoid, 3), (dot, 2)):
if not len([x for x in g.get_nodes(type)]) == num: if not len([x for x in g.get_nodes(type)]) == num:
self.fail((type, num)) raise Exception("Expected: %i times %s" % (num, type))
new_e0 = add(y, z) new_e0 = add(y, z)
assert e0.owner in g.get_nodes(dot) assert e0.owner in g.get_nodes(dot)
assert new_e0.owner not in g.get_nodes(add) assert new_e0.owner not in g.get_nodes(add)
...@@ -98,21 +82,7 @@ class _test_NodeFinder(unittest.TestCase): ...@@ -98,21 +82,7 @@ class _test_NodeFinder(unittest.TestCase):
assert new_e0.owner in g.get_nodes(add) assert new_e0.owner in g.get_nodes(add)
for type, num in ((add, 4), (sigmoid, 3), (dot, 1)): for type, num in ((add, 4), (sigmoid, 3), (dot, 1)):
if not len([x for x in g.get_nodes(type)]) == num: if not len([x for x in g.get_nodes(type)]) == num:
self.fail((type, num)) raise Exception("Expected: %i times %s" % (num, type))
# def test_robustness(self):
# # this test used to make sense to have, but it doesn't work like that anymore
# x, y, z = inputs()
# e = add(add(sigmoid(x), sigmoid(sigmoid(z))), dot(add(x, y), dot(y, z)))
# g = Env([x, y, z], [e])
# g.extend(NodeFinder())
# gen = g.get_nodes(sigmoid) # I want to get Sigmoid instances
# g.replace(e, add(x, y)) # but here I prune them all
# assert len([x for x in gen]) == 0 # the generator should not yield them
if __name__ == '__main__':
unittest.main()
from theano.gof.type import *
# todo: test generic
...@@ -2,5 +2,4 @@ ...@@ -2,5 +2,4 @@
from basic import * from basic import *
from basic import _abs from basic import _abs
import opt
...@@ -648,7 +648,7 @@ def cast(t, dtype): ...@@ -648,7 +648,7 @@ def cast(t, dtype):
#to be removed as we get the epydoc routine-documenting thing going -JB 20080924 #to be removed as we get the epydoc routine-documenting thing going -JB 20080924
def _conversion(real_value): def _conversion(real_value):
__oplist_tag(real_value, 'casting') __oplist_tag(real_value, 'casting')
real_value.__module__='tensor' real_value.__module__='tensor.basic'
return real_value return real_value
convert_to_int8 = _conversion(elemwise.Elemwise(scal.Identity(scal.specific_out(scal.int8)))) convert_to_int8 = _conversion(elemwise.Elemwise(scal.Identity(scal.specific_out(scal.int8))))
......
...@@ -64,6 +64,20 @@ class RandomFunction(gof.Op): ...@@ -64,6 +64,20 @@ class RandomFunction(gof.Op):
return hash(self.fn) ^ hash(self.outtype) ^ hash(self.args) ^ hash(self.inplace) return hash(self.fn) ^ hash(self.outtype) ^ hash(self.args) ^ hash(self.inplace)
__oplist_constructor_list = []
"""List of functions to be listed as op constructors in the oplist (`gen_oplist`, doc/oplist.txt)."""
def constructor(f):
"""Add `f` to :doc:`oplist`.
Make `f` appear as a constructor in the oplist (`gen_oplist`, doc/oplist.txt).
"""
__oplist_constructor_list.append(f)
return f
def __oplist_tag(thing, tag):
tags = getattr(thing, '__oplist_tags', [])
tags.append(tag)
thing.__oplist_tags = tags
def random_function(fn, dtype, *rfargs, **rfkwargs): def random_function(fn, dtype, *rfargs, **rfkwargs):
""" """
Returns a wrapper around RandomFunction which automatically infers the number Returns a wrapper around RandomFunction which automatically infers the number
...@@ -76,6 +90,7 @@ def random_function(fn, dtype, *rfargs, **rfkwargs): ...@@ -76,6 +90,7 @@ def random_function(fn, dtype, *rfargs, **rfkwargs):
- make_lvector(x, y, z, ...) - make_lvector(x, y, z, ...)
- constants - constants
""" """
@constructor
def f(ndim, *args, **kwargs): def f(ndim, *args, **kwargs):
if isinstance(ndim, int): if isinstance(ndim, int):
r, shape, args = args[0], args[1], args[2:] r, shape, args = args[0], args[1], args[2:]
...@@ -94,10 +109,48 @@ def random_function(fn, dtype, *rfargs, **rfkwargs): ...@@ -94,10 +109,48 @@ def random_function(fn, dtype, *rfargs, **rfkwargs):
RS = numpy.random.RandomState RS = numpy.random.RandomState
# we need to provide defaults for all the functions in order to infer the argument types... # we need to provide defaults for all the functions in order to infer the argument types...
uniform = random_function(RS.uniform, 'float64', 0.0, 1.0) uniform = random_function(RS.uniform, 'float64', 0.0, 1.0)
uniform.__doc__ = """
Usage: uniform(random_state, size, low=0.0, high=1.0)
Sample from a uniform distribution between low and high.
If the size argument is ambiguous on the number of
dimensions, the first argument may be a plain integer
to supplement the missing information.
"""
binomial = random_function(RS.binomial, 'int64', 1, 0.5) binomial = random_function(RS.binomial, 'int64', 1, 0.5)
binomial.__doc__ = """
Usage: binomial(random_state, size, n=1, prob=0.5)
Sample n times with probability of success prob for each trial,
return the number of successes.
If the size argument is ambiguous on the number of
dimensions, the first argument may be a plain integer
to supplement the missing information.
"""
normal = random_function(RS.normal, 'float64', 0.0, 1.0) normal = random_function(RS.normal, 'float64', 0.0, 1.0)
normal.__doc__ = """
Usage: normal(random_state, size, avg=0.0, std=1.0)
Sample from a normal distribution centered on avg with
the specified standard deviation (std)
If the size argument is ambiguous on the number of
dimensions, the first argument may be a plain integer
to supplement the missing information.
"""
random_integers = random_function(RS.random_integers, 'int64', 0, 1) random_integers = random_function(RS.random_integers, 'int64', 0, 1)
random_integers.__doc__ = """
Usage: random_integers(random_state, size, low=0, high=1)
Sample a random integer between low and high, both inclusive.
If the size argument is ambiguous on the number of
dimensions, the first argument may be a plain integer
to supplement the missing information.
"""
@gof.local_optimizer @gof.local_optimizer
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
# #
import unittest import unittest
import numpy import numpy
import gof from theano import gof
from gradient import * from theano.gradient import *
import gradient from theano import gradient
class _test_grad_sources_inputs(unittest.TestCase): class _test_grad_sources_inputs(unittest.TestCase):
def test_retNone1(self): def test_retNone1(self):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论