mirror of https://github.com/python/peps
843 lines
79 KiB
HTML
843 lines
79 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 225 – Elementwise/Objectwise Operators | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0225/">
|
||
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
||
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
||
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
||
<meta property="og:title" content='PEP 225 – Elementwise/Objectwise Operators | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0225/">
|
||
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
||
<meta property="og:image:alt" content="Python PEPs">
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="description" content="Python Enhancement Proposals (PEPs)">
|
||
<meta name="theme-color" content="#3776ab">
|
||
</head>
|
||
<body>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Following system colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="9"></circle>
|
||
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected dark colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected light colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
<script>
|
||
|
||
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
||
</script>
|
||
<section id="pep-page-section">
|
||
<header>
|
||
<h1>Python Enhancement Proposals</h1>
|
||
<ul class="breadcrumbs">
|
||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 225</li>
|
||
</ul>
|
||
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
||
</button>
|
||
</header>
|
||
<article>
|
||
<section id="pep-content">
|
||
<h1 class="page-title">PEP 225 – Elementwise/Objectwise Operators</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Huaiyu Zhu <hzhu at users.sourceforge.net>,
|
||
Gregory Lielens <gregory.lielens at fft.be></dd>
|
||
<dt class="field-even">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</abbr></dd>
|
||
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-even">Created<span class="colon">:</span></dt>
|
||
<dd class="field-even">19-Sep-2000</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">2.1</dd>
|
||
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-even"><p></p></dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#introduction">Introduction</a></li>
|
||
<li><a class="reference internal" href="#background">Background</a></li>
|
||
<li><a class="reference internal" href="#proposed-extension">Proposed extension</a></li>
|
||
<li><a class="reference internal" href="#prototype-implementation">Prototype Implementation</a></li>
|
||
<li><a class="reference internal" href="#alternatives-to-adding-new-operators">Alternatives to adding new operators</a></li>
|
||
<li><a class="reference internal" href="#alternative-forms-of-infix-operators">Alternative forms of infix operators</a></li>
|
||
<li><a class="reference internal" href="#semantics-of-new-operators">Semantics of new operators</a></li>
|
||
<li><a class="reference internal" href="#examples">Examples</a></li>
|
||
<li><a class="reference internal" href="#miscellaneous-issues">Miscellaneous issues</a></li>
|
||
<li><a class="reference internal" href="#impact-on-general-elementization">Impact on general elementization</a><ul>
|
||
<li><a class="reference internal" href="#notes">Notes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#impact-on-named-operators">Impact on named operators</a></li>
|
||
<li><a class="reference internal" href="#credits-and-archives">Credits and archives</a></li>
|
||
<li><a class="reference internal" href="#additional-references">Additional References</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>The approach in the later <a class="pep reference internal" href="../pep-0465/" title="PEP 465 – A dedicated infix operator for matrix multiplication">PEP 465</a> was eventually accepted
|
||
in lieu of this PEP. The <a class="pep reference internal" href="../pep-0465/#rejected-alternatives-to-adding-a-new-operator" title="PEP 465 – A dedicated infix operator for matrix multiplication § Rejected alternatives to adding a new operator">Rejected Ideas</a>
|
||
of that PEP explains the rationale in more detail.</p>
|
||
</div>
|
||
<section id="introduction">
|
||
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
|
||
<p>This PEP describes a proposal to add new operators to Python which are useful
|
||
for distinguishing elementwise and objectwise operations, and summarizes
|
||
discussions in the news group comp.lang.python on this topic. See Credits and
|
||
Archives section at end. Issues discussed here include:</p>
|
||
<ul class="simple">
|
||
<li>Background.</li>
|
||
<li>Description of proposed operators and implementation issues.</li>
|
||
<li>Analysis of alternatives to new operators.</li>
|
||
<li>Analysis of alternative forms.</li>
|
||
<li>Compatibility issues</li>
|
||
<li>Description of wider extensions and other related ideas.</li>
|
||
</ul>
|
||
<p>A substantial portion of this PEP describes ideas that do not go into the
|
||
proposed extension. They are presented because the extension is essentially
|
||
syntactic sugar, so its adoption must be weighed against various possible
|
||
alternatives. While many alternatives may be better in some aspects, the
|
||
current proposal appears to be overall advantageous.</p>
|
||
<p>The issues concerning elementwise-objectwise operations extends to wider areas
|
||
than numerical computation. This document also describes how the current
|
||
proposal may be integrated with more general future extensions.</p>
|
||
</section>
|
||
<section id="background">
|
||
<h2><a class="toc-backref" href="#background" role="doc-backlink">Background</a></h2>
|
||
<p>Python provides six binary infix math operators: <code class="docutils literal notranslate"><span class="pre">+</span></code> <code class="docutils literal notranslate"><span class="pre">-</span></code> <code class="docutils literal notranslate"><span class="pre">*</span></code> <code class="docutils literal notranslate"><span class="pre">/</span></code> <code class="docutils literal notranslate"><span class="pre">%</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">**</span></code> hereafter generically represented by <code class="docutils literal notranslate"><span class="pre">op</span></code>. They can be overloaded
|
||
with new semantics for user-defined classes. However, for objects composed of
|
||
homogeneous elements, such as arrays, vectors and matrices in numerical
|
||
computation, there are two essentially distinct flavors of semantics. The
|
||
objectwise operations treat these objects as points in multidimensional spaces.
|
||
The elementwise operations treat them as collections of individual elements.
|
||
These two flavors of operations are often intermixed in the same formulas,
|
||
thereby requiring syntactical distinction.</p>
|
||
<p>Many numerical computation languages provide two sets of math operators. For
|
||
example, in MatLab, the ordinary <code class="docutils literal notranslate"><span class="pre">op</span></code> is used for objectwise operation while
|
||
<code class="docutils literal notranslate"><span class="pre">.op</span></code> is used for elementwise operation. In R, <code class="docutils literal notranslate"><span class="pre">op</span></code> stands for elementwise
|
||
operation while <code class="docutils literal notranslate"><span class="pre">%op%</span></code> stands for objectwise operation.</p>
|
||
<p>In Python, there are other methods of representation, some of which already
|
||
used by available numerical packages, such as:</p>
|
||
<ul class="simple">
|
||
<li>function: mul(a,b)</li>
|
||
<li>method: a.mul(b)</li>
|
||
<li>casting: a.E*b</li>
|
||
</ul>
|
||
<p>In several aspects these are not as adequate as infix operators. More details
|
||
will be shown later, but the key points are:</p>
|
||
<ul class="simple">
|
||
<li>Readability: Even for moderately complicated formulas, infix operators are
|
||
much cleaner than alternatives.</li>
|
||
<li>Familiarity: Users are familiar with ordinary math operators.</li>
|
||
<li>Implementation: New infix operators will not unduly clutter Python syntax.
|
||
They will greatly ease the implementation of numerical packages.</li>
|
||
</ul>
|
||
<p>While it is possible to assign current math operators to one flavor of
|
||
semantics, there is simply not enough infix operators to overload for the other
|
||
flavor. It is also impossible to maintain visual symmetry between these two
|
||
flavors if one of them does not contain symbols for ordinary math operators.</p>
|
||
</section>
|
||
<section id="proposed-extension">
|
||
<h2><a class="toc-backref" href="#proposed-extension" role="doc-backlink">Proposed extension</a></h2>
|
||
<ul class="simple">
|
||
<li>Six new binary infix operators <code class="docutils literal notranslate"><span class="pre">~+</span></code> <code class="docutils literal notranslate"><span class="pre">~-</span></code> <code class="docutils literal notranslate"><span class="pre">~*</span></code> <code class="docutils literal notranslate"><span class="pre">~/</span></code> <code class="docutils literal notranslate"><span class="pre">~%</span></code> <code class="docutils literal notranslate"><span class="pre">~**</span></code> are
|
||
added to core Python. They parallel the existing operators <code class="docutils literal notranslate"><span class="pre">+</span></code> <code class="docutils literal notranslate"><span class="pre">-</span></code> <code class="docutils literal notranslate"><span class="pre">*</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">/</span></code> <code class="docutils literal notranslate"><span class="pre">%</span></code> <code class="docutils literal notranslate"><span class="pre">**</span></code>.</li>
|
||
<li>Six augmented assignment operators <code class="docutils literal notranslate"><span class="pre">~+=</span></code> <code class="docutils literal notranslate"><span class="pre">~-=</span></code> <code class="docutils literal notranslate"><span class="pre">~*=</span></code> <code class="docutils literal notranslate"><span class="pre">~/=</span></code> <code class="docutils literal notranslate"><span class="pre">~%=</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">~**=</span></code> are added to core Python. They parallel the operators <code class="docutils literal notranslate"><span class="pre">+=</span></code> <code class="docutils literal notranslate"><span class="pre">-=</span></code>
|
||
<code class="docutils literal notranslate"><span class="pre">*=</span></code> <code class="docutils literal notranslate"><span class="pre">/=</span></code> <code class="docutils literal notranslate"><span class="pre">%=</span></code> <code class="docutils literal notranslate"><span class="pre">**=</span></code> available in Python 2.0.</li>
|
||
<li>Operator <code class="docutils literal notranslate"><span class="pre">~op</span></code> retains the syntactical properties of operator <code class="docutils literal notranslate"><span class="pre">op</span></code>,
|
||
including precedence.</li>
|
||
<li>Operator <code class="docutils literal notranslate"><span class="pre">~op</span></code> retains the semantical properties of operator <code class="docutils literal notranslate"><span class="pre">op</span></code> on
|
||
built-in number types.</li>
|
||
<li>Operator <code class="docutils literal notranslate"><span class="pre">~op</span></code> raise syntax error on non-number builtin types. This is
|
||
temporary until the proper behavior can be agreed upon.</li>
|
||
<li>These operators are overloadable in classes with names that prepend <em>t</em> (for
|
||
tilde) to names of ordinary math operators. For example, <code class="docutils literal notranslate"><span class="pre">__tadd__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__rtadd__</span></code> work for <code class="docutils literal notranslate"><span class="pre">~+</span></code> just as <code class="docutils literal notranslate"><span class="pre">__add__</span></code> and <code class="docutils literal notranslate"><span class="pre">__radd__</span></code> work for
|
||
<code class="docutils literal notranslate"><span class="pre">+</span></code>.</li>
|
||
<li>As with existing operators, the <code class="docutils literal notranslate"><span class="pre">__r*__()</span></code> methods are invoked when the
|
||
left operand does not provide the appropriate method.</li>
|
||
</ul>
|
||
<p>It is intended that one set of <code class="docutils literal notranslate"><span class="pre">op</span></code> or <code class="docutils literal notranslate"><span class="pre">~op</span></code> is used for elementwise
|
||
operations, the other for objectwise operations, but it is not specified which
|
||
version of operators stands for elementwise or objectwise operations, leaving
|
||
the decision to applications.</p>
|
||
<p>The proposed implementation is to patch several files relating to the
|
||
tokenizer, parser, grammar and compiler to duplicate the functionality of
|
||
corresponding existing operators as necessary. All new semantics are to be
|
||
implemented in the classes that overload them.</p>
|
||
<p>The symbol <code class="docutils literal notranslate"><span class="pre">~</span></code> is already used in Python as the unary <em>bitwise not</em> operator.
|
||
Currently it is not allowed for binary operators. The new operators are
|
||
completely backward compatible.</p>
|
||
</section>
|
||
<section id="prototype-implementation">
|
||
<h2><a class="toc-backref" href="#prototype-implementation" role="doc-backlink">Prototype Implementation</a></h2>
|
||
<p>Greg Lielens implemented the infix <code class="docutils literal notranslate"><span class="pre">~op</span></code> as a patch against Python 2.0b1
|
||
source <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>.</p>
|
||
<p>To allow <code class="docutils literal notranslate"><span class="pre">~</span></code> to be part of binary operators, the tokenizer would treat <code class="docutils literal notranslate"><span class="pre">~+</span></code>
|
||
as one token. This means that currently valid expression <code class="docutils literal notranslate"><span class="pre">~+1</span></code> would be
|
||
tokenized as <code class="docutils literal notranslate"><span class="pre">~+</span></code> <code class="docutils literal notranslate"><span class="pre">1</span></code> instead of <code class="docutils literal notranslate"><span class="pre">~</span> <span class="pre">+</span> <span class="pre">1</span></code>. The parser would then treat <code class="docutils literal notranslate"><span class="pre">~+</span></code>
|
||
as composite of <code class="docutils literal notranslate"><span class="pre">~</span> <span class="pre">+</span></code>. The effect is invisible to applications.</p>
|
||
<p>Notes about current patch:</p>
|
||
<ul class="simple">
|
||
<li>It does not include <code class="docutils literal notranslate"><span class="pre">~op=</span></code> operators yet.</li>
|
||
<li>The <code class="docutils literal notranslate"><span class="pre">~op</span></code> behaves the same as <code class="docutils literal notranslate"><span class="pre">op</span></code> on lists, instead of raising
|
||
exceptions.</li>
|
||
</ul>
|
||
<p>These should be fixed when the final version of this proposal is ready.</p>
|
||
<ul>
|
||
<li>It reserves <code class="docutils literal notranslate"><span class="pre">xor</span></code> as an infix operator with the semantics equivalent to:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__xor__</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">b</span><span class="p">:</span> <span class="k">return</span> <span class="n">a</span>
|
||
<span class="k">elif</span> <span class="ow">not</span> <span class="n">a</span><span class="p">:</span> <span class="k">return</span> <span class="n">b</span>
|
||
<span class="k">else</span><span class="p">:</span> <span class="mi">0</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>This preserves true value as much as possible, otherwise preserve left hand
|
||
side value if possible.</p>
|
||
<p>This is done so that bitwise operators could be regarded as elementwise
|
||
logical operators in the future (see below).</p>
|
||
</section>
|
||
<section id="alternatives-to-adding-new-operators">
|
||
<h2><a class="toc-backref" href="#alternatives-to-adding-new-operators" role="doc-backlink">Alternatives to adding new operators</a></h2>
|
||
<p>The discussions on comp.lang.python and python-dev mailing list explored many
|
||
alternatives. Some of the leading alternatives are listed here, using the
|
||
multiplication operator as an example.</p>
|
||
<ol class="arabic">
|
||
<li>Use function <code class="docutils literal notranslate"><span class="pre">mul(a,b)</span></code>.<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>No need for new operators.</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>Prefix forms are cumbersome for composite formulas.</li>
|
||
<li>Unfamiliar to the intended users.</li>
|
||
<li>Too verbose for the intended users.</li>
|
||
<li>Unable to use natural precedence rules.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Use method call <code class="docutils literal notranslate"><span class="pre">a.mul(b)</span></code>.<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>No need for new operators.</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>Asymmetric for both operands.</li>
|
||
<li>Unfamiliar to the intended users.</li>
|
||
<li>Too verbose for the intended users.</li>
|
||
<li>Unable to use natural precedence rules.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Use <em>shadow classes</em>. For matrix class define a shadow array class
|
||
accessible through a method <code class="docutils literal notranslate"><span class="pre">.E</span></code>, so that for matrices <em>a</em> and <em>b</em>,
|
||
<code class="docutils literal notranslate"><span class="pre">a.E*b</span></code> would be a matrix object that is <code class="docutils literal notranslate"><span class="pre">elementwise_mul(a,b)</span></code>.<p>Likewise define a shadow matrix class for arrays accessible through a method
|
||
<code class="docutils literal notranslate"><span class="pre">.M</span></code> so that for arrays <em>a</em> and <em>b</em>, <code class="docutils literal notranslate"><span class="pre">a.M*b</span></code> would be an array that is
|
||
<code class="docutils literal notranslate"><span class="pre">matrixwise_mul(a,b)</span></code>.</p>
|
||
<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>No need for new operators.</li>
|
||
<li>Benefits of infix operators with correct precedence rules.</li>
|
||
<li>Clean formulas in applications.</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>Hard to maintain in current Python because ordinary numbers cannot have
|
||
user defined class methods; i.e. <code class="docutils literal notranslate"><span class="pre">a.E*b</span></code> will fail if a is a pure
|
||
number.</li>
|
||
<li>Difficult to implement, as this will interfere with existing method calls,
|
||
like <code class="docutils literal notranslate"><span class="pre">.T</span></code> for transpose, etc.</li>
|
||
<li>Runtime overhead of object creation and method lookup.</li>
|
||
<li>The shadowing class cannot replace a true class, because it does not
|
||
return its own type. So there need to be a <code class="docutils literal notranslate"><span class="pre">M</span></code> class with shadow <code class="docutils literal notranslate"><span class="pre">E</span></code>
|
||
class, and an <code class="docutils literal notranslate"><span class="pre">E</span></code> class with shadow <code class="docutils literal notranslate"><span class="pre">M</span></code> class.</li>
|
||
<li>Unnatural to mathematicians.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Implement matrixwise and elementwise classes with easy casting to the other
|
||
class. So matrixwise operations for arrays would be like <code class="docutils literal notranslate"><span class="pre">a.M*b.M</span></code> and
|
||
elementwise operations for matrices would be like <code class="docutils literal notranslate"><span class="pre">a.E*b.E</span></code>. For error
|
||
detection <code class="docutils literal notranslate"><span class="pre">a.E*b.M</span></code> would raise exceptions.<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>No need for new operators.</li>
|
||
<li>Similar to infix notation with correct precedence rules.</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>Similar difficulty due to lack of user-methods for pure numbers.</li>
|
||
<li>Runtime overhead of object creation and method lookup.</li>
|
||
<li>More cluttered formulas.</li>
|
||
<li>Switching of flavor of objects to facilitate operators becomes persistent.
|
||
This introduces long range context dependencies in application code that
|
||
would be extremely hard to maintain.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Using mini parser to parse formulas written in arbitrary extension placed in
|
||
quoted strings.<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>Pure Python, without new operators</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>The actual syntax is within the quoted string, which does not resolve the
|
||
problem itself.</li>
|
||
<li>Introducing zones of special syntax.</li>
|
||
<li>Demanding on the mini-parser.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Introducing a single operator, such as <code class="docutils literal notranslate"><span class="pre">@</span></code>, for matrix multiplication.<p>Advantage:</p>
|
||
<ul class="simple">
|
||
<li>Introduces less operators</li>
|
||
</ul>
|
||
<p>Disadvantage:</p>
|
||
<ul class="simple">
|
||
<li>The distinctions for operators like <code class="docutils literal notranslate"><span class="pre">+</span></code> <code class="docutils literal notranslate"><span class="pre">-</span></code> <code class="docutils literal notranslate"><span class="pre">**</span></code> are equally
|
||
important. Their meaning in matrix or array-oriented packages would be
|
||
reversed (see below).</li>
|
||
<li>The new operator occupies a special character.</li>
|
||
<li>This does not work well with more general object-element issues.</li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<p>Among these alternatives, the first and second are used in current applications
|
||
to some extent, but found inadequate. The third is the most favorite for
|
||
applications, but it will incur huge implementation complexity. The fourth
|
||
would make applications codes very context-sensitive and hard to maintain.
|
||
These two alternatives also share significant implementational difficulties due
|
||
to current type/class split. The fifth appears to create more problems than it
|
||
would solve. The sixth does not cover the same range of applications.</p>
|
||
</section>
|
||
<section id="alternative-forms-of-infix-operators">
|
||
<h2><a class="toc-backref" href="#alternative-forms-of-infix-operators" role="doc-backlink">Alternative forms of infix operators</a></h2>
|
||
<p>Two major forms and several minor variants of new infix operators were
|
||
discussed:</p>
|
||
<ul>
|
||
<li>Bracketed form:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="n">op</span><span class="p">)</span>
|
||
<span class="p">[</span><span class="n">op</span><span class="p">]</span>
|
||
<span class="p">{</span><span class="n">op</span><span class="p">}</span>
|
||
<span class="o"><</span><span class="n">op</span><span class="o">></span>
|
||
<span class="p">:</span><span class="n">op</span><span class="p">:</span>
|
||
<span class="o">~</span><span class="n">op</span><span class="o">~</span>
|
||
<span class="o">%</span><span class="n">op</span><span class="o">%</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Meta character form:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">.</span><span class="n">op</span>
|
||
<span class="nd">@op</span>
|
||
<span class="o">~</span><span class="n">op</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Alternatively the meta character is put after the operator.</p>
|
||
</li>
|
||
<li>Less consistent variations of these themes. These are considered
|
||
unfavorably. For completeness some are listed here:<ul class="simple">
|
||
<li>Use <code class="docutils literal notranslate"><span class="pre">@/</span></code> and <code class="docutils literal notranslate"><span class="pre">/@</span></code> for left and right division</li>
|
||
<li>Use <code class="docutils literal notranslate"><span class="pre">[*]</span></code> and <code class="docutils literal notranslate"><span class="pre">(*)</span></code> for outer and inner products</li>
|
||
<li>Use a single operator <code class="docutils literal notranslate"><span class="pre">@</span></code> for multiplication.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Use <code class="docutils literal notranslate"><span class="pre">__call__</span></code> to simulate multiplication:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">a</span><span class="p">)(</span><span class="n">b</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>Criteria for choosing among the representations include:</p>
|
||
<ul class="simple">
|
||
<li>No syntactical ambiguities with existing operators.</li>
|
||
<li>Higher readability in actual formulas. This makes the bracketed forms
|
||
unfavorable. See examples below.</li>
|
||
<li>Visually similar to existing math operators.</li>
|
||
<li>Syntactically simple, without blocking possible future extensions.</li>
|
||
</ul>
|
||
<p>With these criteria the overall winner in bracket form appear to be <code class="docutils literal notranslate"><span class="pre">{op}</span></code>.
|
||
A clear winner in the meta character form is <code class="docutils literal notranslate"><span class="pre">~op</span></code>. Comparing these it
|
||
appears that <code class="docutils literal notranslate"><span class="pre">~op</span></code> is the favorite among them all.</p>
|
||
<p>Some analysis are as follows:</p>
|
||
<ul class="simple">
|
||
<li>The <code class="docutils literal notranslate"><span class="pre">.op</span></code> form is ambiguous: <code class="docutils literal notranslate"><span class="pre">1.+a</span></code> would be different from <code class="docutils literal notranslate"><span class="pre">1</span> <span class="pre">.+a</span></code>.</li>
|
||
<li>The bracket type operators are most favorable when standing alone, but
|
||
not in formulas, as they interfere with visual parsing of parentheses for
|
||
precedence and function argument. This is so for <code class="docutils literal notranslate"><span class="pre">(op)</span></code> and <code class="docutils literal notranslate"><span class="pre">[op]</span></code>, and
|
||
somewhat less so for <code class="docutils literal notranslate"><span class="pre">{op}</span></code> and <code class="docutils literal notranslate"><span class="pre"><op></span></code>.</li>
|
||
<li>The <code class="docutils literal notranslate"><span class="pre"><op></span></code> form has the potential to be confused with <code class="docutils literal notranslate"><span class="pre"><</span></code> <code class="docutils literal notranslate"><span class="pre">></span></code> and <code class="docutils literal notranslate"><span class="pre">=</span></code>.</li>
|
||
<li>The <code class="docutils literal notranslate"><span class="pre">@op</span></code> is not favored because <code class="docutils literal notranslate"><span class="pre">@</span></code> is visually heavy (dense, more like
|
||
a letter): <code class="docutils literal notranslate"><span class="pre">a@+b</span></code> is more readily read as <code class="docutils literal notranslate"><span class="pre">a@</span> <span class="pre">+</span> <span class="pre">b</span></code> than <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">@+</span> <span class="pre">b</span></code>.</li>
|
||
<li>For choosing meta-characters: Most of existing ASCII symbols have already
|
||
been used. The only three unused are <code class="docutils literal notranslate"><span class="pre">@</span></code> <code class="docutils literal notranslate"><span class="pre">$</span></code> <code class="docutils literal notranslate"><span class="pre">?</span></code>.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="semantics-of-new-operators">
|
||
<h2><a class="toc-backref" href="#semantics-of-new-operators" role="doc-backlink">Semantics of new operators</a></h2>
|
||
<p>There are convincing arguments for using either set of operators as objectwise
|
||
or elementwise. Some of them are listed here:</p>
|
||
<ol class="arabic simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">op</span></code> for element, <code class="docutils literal notranslate"><span class="pre">~op</span></code> for object<ul class="simple">
|
||
<li>Consistent with current multiarray interface of Numeric package.</li>
|
||
<li>Consistent with some other languages.</li>
|
||
<li>Perception that elementwise operations are more natural.</li>
|
||
<li>Perception that elementwise operations are used more frequently</li>
|
||
</ul>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">op</span></code> for object, <code class="docutils literal notranslate"><span class="pre">~op</span></code> for element<ul class="simple">
|
||
<li>Consistent with current linear algebra interface of MatPy package.</li>
|
||
<li>Consistent with some other languages.</li>
|
||
<li>Perception that objectwise operations are more natural.</li>
|
||
<li>Perception that objectwise operations are used more frequently.</li>
|
||
<li>Consistent with the current behavior of operators on lists.</li>
|
||
<li>Allow <code class="docutils literal notranslate"><span class="pre">~</span></code> to be a general elementwise meta-character in future
|
||
extensions.</li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<p>It is generally agreed upon that</p>
|
||
<ul class="simple">
|
||
<li>There is no absolute reason to favor one or the other.</li>
|
||
<li>It is easy to cast from one representation to another in a sizable chunk of
|
||
code, so the other flavor of operators is always minority.</li>
|
||
<li>There are other semantic differences that favor existence of array-oriented
|
||
and matrix-oriented packages, even if their operators are unified.</li>
|
||
<li>Whatever the decision is taken, codes using existing interfaces should not be
|
||
broken for a very long time.</li>
|
||
</ul>
|
||
<p>Therefore, not much is lost, and much flexibility retained, if the semantic
|
||
flavors of these two sets of operators are not dictated by the core language.
|
||
The application packages are responsible for making the most suitable choice.
|
||
This is already the case for NumPy and MatPy which use opposite semantics.
|
||
Adding new operators will not break this. See also observation after
|
||
subsection 2 in the Examples below.</p>
|
||
<p>The issue of numerical precision was raised, but if the semantics is left to
|
||
the applications, the actual precisions should also go there.</p>
|
||
</section>
|
||
<section id="examples">
|
||
<h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2>
|
||
<p>Following are examples of the actual formulas that will appear using various
|
||
operators or other representations described above.</p>
|
||
<ol class="arabic">
|
||
<li>The matrix inversion formula:<ul>
|
||
<li>Using <code class="docutils literal notranslate"><span class="pre">op</span></code> for object and <code class="docutils literal notranslate"><span class="pre">~op</span></code> for element:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">-</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">*</span> <span class="n">u</span> <span class="o">/</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o">+</span> <span class="n">v</span><span class="o">/</span><span class="n">a</span><span class="o">*</span><span class="n">u</span><span class="p">)</span> <span class="o">*</span> <span class="n">v</span> <span class="o">/</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">-</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">*</span> <span class="n">u</span> <span class="o">*</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o">+</span> <span class="n">v</span><span class="o">*</span><span class="n">a</span><span class="o">.</span><span class="n">I</span><span class="o">*</span><span class="n">u</span><span class="p">)</span><span class="o">.</span><span class="n">I</span> <span class="o">*</span> <span class="n">v</span> <span class="o">*</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Using <code class="docutils literal notranslate"><span class="pre">op</span></code> for element and <code class="docutils literal notranslate"><span class="pre">~op</span></code> for object:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">@-</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">@*</span> <span class="n">u</span> <span class="o">@/</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o">@+</span> <span class="n">v</span><span class="o">@/</span><span class="n">a</span><span class="o">@*</span><span class="n">u</span><span class="p">)</span> <span class="o">@*</span> <span class="n">v</span> <span class="o">@/</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">~-</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">~*</span> <span class="n">u</span> <span class="o">~/</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o">~+</span> <span class="n">v</span><span class="o">~/</span><span class="n">a</span><span class="o">~*</span><span class="n">u</span><span class="p">)</span> <span class="o">~*</span> <span class="n">v</span> <span class="o">~/</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">(</span><span class="o">-</span><span class="p">)</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="n">u</span> <span class="p">(</span><span class="o">/</span><span class="p">)</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="n">v</span><span class="p">(</span><span class="o">/</span><span class="p">)</span><span class="n">a</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="n">u</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="n">v</span> <span class="p">(</span><span class="o">/</span><span class="p">)</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">u</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">v</span><span class="p">[</span><span class="o">/</span><span class="p">]</span><span class="n">a</span><span class="p">[</span><span class="o">*</span><span class="p">]</span><span class="n">u</span><span class="p">)</span> <span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">v</span> <span class="p">[</span><span class="o">/</span><span class="p">]</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o"><-></span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o"><*></span> <span class="n">u</span> <span class="o"></></span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o"><+></span> <span class="n">v</span><span class="o"></></span><span class="n">a</span><span class="o"><*></span><span class="n">u</span><span class="p">)</span> <span class="o"><*></span> <span class="n">v</span> <span class="o"></></span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">{</span><span class="o">-</span><span class="p">}</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="p">{</span><span class="o">*</span><span class="p">}</span> <span class="n">u</span> <span class="p">{</span><span class="o">/</span><span class="p">}</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="p">{</span><span class="o">+</span><span class="p">}</span> <span class="n">v</span><span class="p">{</span><span class="o">/</span><span class="p">}</span><span class="n">a</span><span class="p">{</span><span class="o">*</span><span class="p">}</span><span class="n">u</span><span class="p">)</span> <span class="p">{</span><span class="o">*</span><span class="p">}</span> <span class="n">v</span> <span class="p">{</span><span class="o">/</span><span class="p">}</span> <span class="n">a</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>Observation: For linear algebra using <code class="docutils literal notranslate"><span class="pre">op</span></code> for object is preferable.</p>
|
||
<p>Observation: The <code class="docutils literal notranslate"><span class="pre">~op</span></code> type operators look better than <code class="docutils literal notranslate"><span class="pre">(op)</span></code> type in
|
||
complicated formulas.</p>
|
||
<ul>
|
||
<li>using named operators:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="nd">@sub</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="nd">@mul</span> <span class="n">u</span> <span class="nd">@div</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="nd">@add</span> <span class="n">v</span> <span class="nd">@div</span> <span class="n">a</span> <span class="nd">@mul</span> <span class="n">u</span><span class="p">)</span> <span class="nd">@mul</span> <span class="n">v</span> <span class="nd">@div</span> <span class="n">a</span>
|
||
|
||
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">~</span><span class="n">sub</span> <span class="n">a</span><span class="o">.</span><span class="n">I</span> <span class="o">~</span><span class="n">mul</span> <span class="n">u</span> <span class="o">~</span><span class="n">div</span> <span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">I</span> <span class="o">~</span><span class="n">add</span> <span class="n">v</span> <span class="o">~</span><span class="n">div</span> <span class="n">a</span> <span class="o">~</span><span class="n">mul</span> <span class="n">u</span><span class="p">)</span> <span class="o">~</span><span class="n">mul</span> <span class="n">v</span> <span class="o">~</span><span class="n">div</span> <span class="n">a</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>Observation: Named operators are not suitable for math formulas.</p>
|
||
</li>
|
||
<li>Plotting a 3d graph<ul>
|
||
<li>Using <code class="docutils literal notranslate"><span class="pre">op</span></code> for object and <code class="docutils literal notranslate"><span class="pre">~op</span></code> for element:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">z</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="o">~**</span><span class="mi">2</span> <span class="o">~+</span> <span class="n">y</span><span class="o">~**</span><span class="mi">2</span><span class="p">);</span> <span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Using op for element and ~op for object:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">z</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">y</span><span class="o">**</span><span class="mi">2</span><span class="p">);</span> <span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<p>Observation: Elementwise operations with broadcasting allows much more
|
||
efficient implementation than MatLab.</p>
|
||
<p>Observation: It is useful to have two related classes with the semantics of
|
||
<code class="docutils literal notranslate"><span class="pre">op</span></code> and <code class="docutils literal notranslate"><span class="pre">~op</span></code> swapped. Using these the <code class="docutils literal notranslate"><span class="pre">~op</span></code> operators would only
|
||
need to appear in chunks of code where the other flavor dominates, while
|
||
maintaining consistent semantics of the code.</p>
|
||
</li>
|
||
<li>Using <code class="docutils literal notranslate"><span class="pre">+</span></code> and <code class="docutils literal notranslate"><span class="pre">-</span></code> with automatic broadcasting:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">c</span><span class="p">;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">T</span><span class="o">*</span><span class="n">a</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Observation: This would silently produce hard-to-trace bugs if one of <em>b</em> or
|
||
<em>c</em> is row vector while the other is column vector.</p>
|
||
</li>
|
||
</ol>
|
||
</section>
|
||
<section id="miscellaneous-issues">
|
||
<h2><a class="toc-backref" href="#miscellaneous-issues" role="doc-backlink">Miscellaneous issues</a></h2>
|
||
<ul>
|
||
<li>Need for the <code class="docutils literal notranslate"><span class="pre">~+</span></code> <code class="docutils literal notranslate"><span class="pre">~-</span></code> operators. The objectwise <code class="docutils literal notranslate"><span class="pre">+</span></code> <code class="docutils literal notranslate"><span class="pre">-</span></code> are
|
||
important because they provide important sanity checks as per linear algebra.
|
||
The elementwise <code class="docutils literal notranslate"><span class="pre">+</span></code> <code class="docutils literal notranslate"><span class="pre">-</span></code> are important because they allow broadcasting
|
||
that are very efficient in applications.</li>
|
||
<li>Left division (solve). For matrix, <code class="docutils literal notranslate"><span class="pre">a*x</span></code> is not necessarily equal to
|
||
<code class="docutils literal notranslate"><span class="pre">x*a</span></code>. The solution of <code class="docutils literal notranslate"><span class="pre">a*x==b</span></code>, denoted <code class="docutils literal notranslate"><span class="pre">x=solve(a,b)</span></code>, is therefore
|
||
different from the solution of <code class="docutils literal notranslate"><span class="pre">x*a==b</span></code>, denoted <code class="docutils literal notranslate"><span class="pre">x=div(b,a)</span></code>. There are
|
||
discussions about finding a new symbol for solve. [Background: MatLab use
|
||
<code class="docutils literal notranslate"><span class="pre">b/a</span></code> for <code class="docutils literal notranslate"><span class="pre">div(b,a)</span></code> and <code class="docutils literal notranslate"><span class="pre">a\b</span></code> for <code class="docutils literal notranslate"><span class="pre">solve(a,b)</span></code>.]<p>It is recognized that Python provides a better solution without requiring a
|
||
new symbol: the <code class="docutils literal notranslate"><span class="pre">inverse</span></code> method <code class="docutils literal notranslate"><span class="pre">.I</span></code> can be made to be delayed so that
|
||
<code class="docutils literal notranslate"><span class="pre">a.I*b</span></code> and <code class="docutils literal notranslate"><span class="pre">b*a.I</span></code> are equivalent to Matlab’s <code class="docutils literal notranslate"><span class="pre">a\b</span></code> and <code class="docutils literal notranslate"><span class="pre">b/a</span></code>. The
|
||
implementation is quite simple and the resulting application code clean.</p>
|
||
</li>
|
||
<li>Power operator. Python’s use of <code class="docutils literal notranslate"><span class="pre">a**b</span></code> as <code class="docutils literal notranslate"><span class="pre">pow(a,b)</span></code> has two perceived
|
||
disadvantages:<ul class="simple">
|
||
<li>Most mathematicians are more familiar with <code class="docutils literal notranslate"><span class="pre">a^b</span></code> for this purpose.</li>
|
||
<li>It results in long augmented assignment operator <code class="docutils literal notranslate"><span class="pre">~**=</span></code>.</li>
|
||
</ul>
|
||
<p>However, this issue is distinct from the main issue here.</p>
|
||
</li>
|
||
<li>Additional multiplication operators. Several forms of multiplications are
|
||
used in (multi-)linear algebra. Most can be seen as variations of
|
||
multiplication in linear algebra sense (such as Kronecker product). But two
|
||
forms appear to be more fundamental: outer product and inner product.
|
||
However, their specification includes indices, which can be either<ul class="simple">
|
||
<li>associated with the operator, or</li>
|
||
<li>associated with the objects.</li>
|
||
</ul>
|
||
<p>The latter (the Einstein notation) is used extensively on paper, and is also
|
||
the easier one to implement. By implementing a tensor-with-indices class, a
|
||
general form of multiplication would cover both outer and inner products, and
|
||
specialize to linear algebra multiplication as well. The index rule can be
|
||
defined as class methods, like:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">i</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">c</span><span class="o">.</span><span class="n">i</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># a_ijkl = b_ijmn c_lnkm</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Therefore, one objectwise multiplication is sufficient.</p>
|
||
</li>
|
||
<li>Bitwise operators.<ul class="simple">
|
||
<li>The proposed new math operators use the symbol ~ that is <em>bitwise not</em>
|
||
operator. This poses no compatibility problem but somewhat complicates
|
||
implementation.</li>
|
||
<li>The symbol <code class="docutils literal notranslate"><span class="pre">^</span></code> might be better used for <code class="docutils literal notranslate"><span class="pre">pow</span></code> than bitwise <code class="docutils literal notranslate"><span class="pre">xor</span></code>. But
|
||
this depends on the future of bitwise operators. It does not immediately
|
||
impact on the proposed math operator.</li>
|
||
<li>The symbol <code class="docutils literal notranslate"><span class="pre">|</span></code> was suggested to be used for matrix solve. But the new
|
||
solution of using delayed <code class="docutils literal notranslate"><span class="pre">.I</span></code> is better in several ways.</li>
|
||
<li>The current proposal fits in a larger and more general extension that will
|
||
remove the need for special bitwise operators. (See elementization below.)</li>
|
||
</ul>
|
||
</li>
|
||
<li>Alternative to special operator names used in definition,<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="s2">"+"</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="ow">in</span> <span class="n">place</span> <span class="n">of</span> <span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This appears to require greater syntactical change, and would only be useful
|
||
when arbitrary additional operators are allowed.</p>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<section id="impact-on-general-elementization">
|
||
<h2><a class="toc-backref" href="#impact-on-general-elementization" role="doc-backlink">Impact on general elementization</a></h2>
|
||
<p>The distinction between objectwise and elementwise operations are meaningful in
|
||
other contexts as well, where an object can be conceptually regarded as a
|
||
collection of elements. It is important that the current proposal does not
|
||
preclude possible future extensions.</p>
|
||
<p>One general future extension is to use <code class="docutils literal notranslate"><span class="pre">~</span></code> as a meta operator to <em>elementize</em>
|
||
a given operator. Several examples are listed here:</p>
|
||
<ol class="arabic">
|
||
<li>Bitwise operators. Currently Python assigns six operators to bitwise
|
||
operations: and (<code class="docutils literal notranslate"><span class="pre">&</span></code>), or (<code class="docutils literal notranslate"><span class="pre">|</span></code>), xor (<code class="docutils literal notranslate"><span class="pre">^</span></code>), complement (<code class="docutils literal notranslate"><span class="pre">~</span></code>), left
|
||
shift (<code class="docutils literal notranslate"><span class="pre"><<</span></code>) and right shift (<code class="docutils literal notranslate"><span class="pre">>></span></code>), with their own precedence levels.<p>Among them, the <code class="docutils literal notranslate"><span class="pre">&</span></code> <code class="docutils literal notranslate"><span class="pre">|</span></code> <code class="docutils literal notranslate"><span class="pre">^</span></code> <code class="docutils literal notranslate"><span class="pre">~</span></code> operators can be regarded as
|
||
elementwise versions of lattice operators applied to integers regarded as
|
||
bit strings.:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">5</span> <span class="ow">and</span> <span class="mi">6</span> <span class="c1"># 6</span>
|
||
<span class="mi">5</span> <span class="ow">or</span> <span class="mi">6</span> <span class="c1"># 5</span>
|
||
|
||
<span class="mi">5</span> <span class="o">~</span><span class="ow">and</span> <span class="mi">6</span> <span class="c1"># 4</span>
|
||
<span class="mi">5</span> <span class="o">~</span><span class="ow">or</span> <span class="mi">6</span> <span class="c1"># 7</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>These can be regarded as general elementwise lattice operators, not
|
||
restricted to bits in integers.</p>
|
||
<p>In order to have named operators for <code class="docutils literal notranslate"><span class="pre">xor</span></code> <code class="docutils literal notranslate"><span class="pre">~xor</span></code>, it is necessary to
|
||
make <code class="docutils literal notranslate"><span class="pre">xor</span></code> a reserved word.</p>
|
||
</li>
|
||
<li>List arithmetics.:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span> <span class="c1"># [1, 2, 3, 4]</span>
|
||
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="o">~+</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span> <span class="c1"># [4, 6]</span>
|
||
|
||
<span class="p">[</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">]</span> <span class="o">*</span> <span class="mi">2</span> <span class="c1"># ['a', 'b', 'a', 'b']</span>
|
||
<span class="s1">'ab'</span> <span class="o">*</span> <span class="mi">2</span> <span class="c1"># 'abab'</span>
|
||
|
||
<span class="p">[</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">]</span> <span class="o">~*</span> <span class="mi">2</span> <span class="c1"># ['aa', 'bb']</span>
|
||
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="o">~*</span> <span class="mi">2</span> <span class="c1"># [2, 4]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>It is also consistent to Cartesian product:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span><span class="o">*</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span> <span class="c1"># [(1,3),(1,4),(2,3),(2,4)]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>List comprehension.:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">];</span> <span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
|
||
<span class="o">~</span><span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span> <span class="c1"># [f(x,y) for x, y in zip(a,b)]</span>
|
||
<span class="o">~</span><span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="o">*</span><span class="n">b</span><span class="p">)</span> <span class="c1"># [f(x,y) for x in a for y in b]</span>
|
||
<span class="n">a</span> <span class="o">~+</span> <span class="n">b</span> <span class="c1"># [x + y for x, y in zip(a,b)]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Tuple generation (the zip function in Python 2.0):<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span> <span class="c1"># ([1,2, 3], [4, 5, 6])</span>
|
||
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span><span class="o">~</span><span class="p">,[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span> <span class="c1"># [(1,4), (2, 5), (3,6)]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Using <code class="docutils literal notranslate"><span class="pre">~</span></code> as generic elementwise meta-character to replace map:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">~</span><span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="c1"># map(f, a, b)</span>
|
||
<span class="o">~~</span><span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="c1"># map(lambda *x:map(f, *x), a, b)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>More generally,:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="o">~</span><span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="nb">map</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="o">~~</span><span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="nb">map</span><span class="p">(</span><span class="o">~</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">x</span><span class="p">)</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Elementwise format operator (with broadcasting):<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
|
||
<span class="nb">print</span> <span class="p">[</span><span class="s2">"</span><span class="si">%5d</span><span class="s2"> "</span><span class="p">]</span> <span class="o">~%</span> <span class="n">a</span>
|
||
<span class="n">a</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]]</span>
|
||
<span class="nb">print</span> <span class="p">[</span><span class="s2">"</span><span class="si">%5d</span><span class="s2"> "</span><span class="p">]</span> <span class="o">~~%</span> <span class="n">a</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Rich comparison:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="o">~<</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="c1"># [1, 0, 0]</span>
|
||
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="o">~==</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="c1"># [0, 1, 0]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Rich indexing:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">]</span> <span class="o">~</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="c1"># [c, d, b]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Tuple flattening:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">);</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span>
|
||
<span class="n">f</span><span class="p">(</span><span class="o">~</span><span class="n">a</span><span class="p">,</span> <span class="o">~</span><span class="n">b</span><span class="p">)</span> <span class="c1"># f(1,2,3,4)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Copy operator:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">~=</span> <span class="n">b</span> <span class="c1"># a = b.copy()</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ol>
|
||
<blockquote>
|
||
<div>There can be specific levels of deep copy:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">~~=</span> <span class="n">b</span> <span class="c1"># a = b.copy(2)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div></blockquote>
|
||
<section id="notes">
|
||
<h3><a class="toc-backref" href="#notes" role="doc-backlink">Notes</a></h3>
|
||
<ol class="arabic simple">
|
||
<li>There are probably many other similar situations. This general approach
|
||
seems well suited for most of them, in place of several separated extensions
|
||
for each of them (parallel and cross iteration, list comprehension, rich
|
||
comparison, etc).</li>
|
||
<li>The semantics of <em>elementwise</em> depends on applications. For example, an
|
||
element of matrix is two levels down from the list-of-list point of view.
|
||
This requires more fundamental change than the current proposal. In any
|
||
case, the current proposal will not negatively impact on future
|
||
possibilities of this nature.</li>
|
||
</ol>
|
||
<p>Note that this section describes a type of future extensions that is consistent
|
||
with current proposal, but may present additional compatibility or other
|
||
problems. They are not tied to the current proposal.</p>
|
||
</section>
|
||
</section>
|
||
<section id="impact-on-named-operators">
|
||
<h2><a class="toc-backref" href="#impact-on-named-operators" role="doc-backlink">Impact on named operators</a></h2>
|
||
<p>The discussions made it generally clear that infix operators is a scarce
|
||
resource in Python, not only in numerical computation, but in other fields as
|
||
well. Several proposals and ideas were put forward that would allow infix
|
||
operators be introduced in ways similar to named functions. We show here that
|
||
the current extension does not negatively impact on future extensions in this
|
||
regard.</p>
|
||
<ol class="arabic">
|
||
<li>Named infix operators.<p>Choose a meta character, say <code class="docutils literal notranslate"><span class="pre">@</span></code>, so that for any identifier <code class="docutils literal notranslate"><span class="pre">opname</span></code>,
|
||
the combination <code class="docutils literal notranslate"><span class="pre">@opname</span></code> would be a binary infix operator, and:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="nd">@opname</span> <span class="n">b</span> <span class="o">==</span> <span class="n">opname</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Other representations mentioned include:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">.</span><span class="n">name</span> <span class="o">~</span><span class="n">name</span><span class="o">~</span> <span class="p">:</span><span class="n">name</span><span class="p">:</span> <span class="p">(</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="o">%</span><span class="n">name</span><span class="o">%</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and similar variations. The pure bracket based operators cannot be used
|
||
this way.</p>
|
||
<p>This requires a change in the parser to recognize <code class="docutils literal notranslate"><span class="pre">@opname</span></code>, and parse it
|
||
into the same structure as a function call. The precedence of all these
|
||
operators would have to be fixed at one level, so the implementation would
|
||
be different from additional math operators which keep the precedence of
|
||
existing math operators.</p>
|
||
<p>The current proposed extension do not limit possible future extensions of
|
||
such form in any way.</p>
|
||
</li>
|
||
<li>More general symbolic operators.<p>One additional form of future extension is to use meta character and
|
||
operator symbols (symbols that cannot be used in syntactical structures
|
||
other than operators). Suppose <code class="docutils literal notranslate"><span class="pre">@</span></code> is the meta character. Then:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">@+</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">@@+</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">@+-</span> <span class="n">b</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>would all be operators with a hierarchy of precedence, defined by:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="s2">"+"</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="s2">"@+"</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="s2">"@@+"</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="s2">"@+-"</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>One advantage compared with named operators is greater flexibility for
|
||
precedences based on either the meta character or the ordinary operator
|
||
symbols. This also allows operator composition. The disadvantage is that
|
||
they are more like <em>line noise</em>. In any case the current proposal does not
|
||
impact its future possibility.</p>
|
||
<p>These kinds of future extensions may not be necessary when Unicode becomes
|
||
generally available.</p>
|
||
<p>Note that this section discusses compatibility of the proposed extension
|
||
with possible future extensions. The desirability or compatibility of these
|
||
other extensions themselves are specifically not considered here.</p>
|
||
</li>
|
||
</ol>
|
||
</section>
|
||
<section id="credits-and-archives">
|
||
<h2><a class="toc-backref" href="#credits-and-archives" role="doc-backlink">Credits and archives</a></h2>
|
||
<p>The discussions mostly happened in July to August of 2000 on news group
|
||
comp.lang.python and the mailing list python-dev. There are altogether several
|
||
hundred postings, most can be retrieved from these two pages (and searching
|
||
word “operator”):</p>
|
||
<blockquote>
|
||
<div><a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/">http://www.python.org/pipermail/python-list/2000-July/</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/">http://www.python.org/pipermail/python-list/2000-August/</a></div></blockquote>
|
||
<p>The names of contributors are too numerous to mention here, suffice to say that
|
||
a large proportion of ideas discussed here are not our own.</p>
|
||
<p>Several key postings (from our point of view) that may help to navigate the
|
||
discussions include:</p>
|
||
<blockquote>
|
||
<div><a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/108893.html">http://www.python.org/pipermail/python-list/2000-July/108893.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/108777.html">http://www.python.org/pipermail/python-list/2000-July/108777.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/108848.html">http://www.python.org/pipermail/python-list/2000-July/108848.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109237.html">http://www.python.org/pipermail/python-list/2000-July/109237.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109250.html">http://www.python.org/pipermail/python-list/2000-July/109250.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109310.html">http://www.python.org/pipermail/python-list/2000-July/109310.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109448.html">http://www.python.org/pipermail/python-list/2000-July/109448.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109491.html">http://www.python.org/pipermail/python-list/2000-July/109491.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109537.html">http://www.python.org/pipermail/python-list/2000-July/109537.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109607.html">http://www.python.org/pipermail/python-list/2000-July/109607.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109709.html">http://www.python.org/pipermail/python-list/2000-July/109709.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109804.html">http://www.python.org/pipermail/python-list/2000-July/109804.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/109857.html">http://www.python.org/pipermail/python-list/2000-July/109857.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/110061.html">http://www.python.org/pipermail/python-list/2000-July/110061.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-July/110208.html">http://www.python.org/pipermail/python-list/2000-July/110208.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/111427.html">http://www.python.org/pipermail/python-list/2000-August/111427.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/111558.html">http://www.python.org/pipermail/python-list/2000-August/111558.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/112551.html">http://www.python.org/pipermail/python-list/2000-August/112551.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/112606.html">http://www.python.org/pipermail/python-list/2000-August/112606.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/112758.html">http://www.python.org/pipermail/python-list/2000-August/112758.html</a><p><a class="reference external" href="http://www.python.org/pipermail/python-dev/2000-July/013243.html">http://www.python.org/pipermail/python-dev/2000-July/013243.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-dev/2000-July/013364.html">http://www.python.org/pipermail/python-dev/2000-July/013364.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-dev/2000-August/014940.html">http://www.python.org/pipermail/python-dev/2000-August/014940.html</a></p>
|
||
</div></blockquote>
|
||
<p>These are earlier drafts of this PEP:</p>
|
||
<blockquote>
|
||
<div><a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/111785.html">http://www.python.org/pipermail/python-list/2000-August/111785.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-list/2000-August/112529.html">http://www.python.org/pipermail/python-list/2000-August/112529.html</a>
|
||
<a class="reference external" href="http://www.python.org/pipermail/python-dev/2000-August/014906.html">http://www.python.org/pipermail/python-dev/2000-August/014906.html</a></div></blockquote>
|
||
<p>There is an alternative PEP (officially, <a class="pep reference internal" href="../pep-0211/" title="PEP 211 – Adding A New Outer Product Operator">PEP 211</a>) by Greg Wilson, titled
|
||
“Adding New Linear Algebra Operators to Python”.</p>
|
||
<p>Its first (and current) version is at:</p>
|
||
<blockquote>
|
||
<div><a class="reference external" href="http://www.python.org/pipermail/python-dev/2000-August/014876.html">http://www.python.org/pipermail/python-dev/2000-August/014876.html</a>
|
||
<a class="pep reference internal" href="../pep-0211/" title="PEP 211 – Adding A New Outer Product Operator">PEP 211</a></div></blockquote>
|
||
</section>
|
||
<section id="additional-references">
|
||
<h2><a class="toc-backref" href="#additional-references" role="doc-backlink">Additional References</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id2" role="doc-footnote">
|
||
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
|
||
<dd><a class="reference external" href="http://MatPy.sourceforge.net/Misc/index.html">http://MatPy.sourceforge.net/Misc/index.html</a></aside>
|
||
</aside>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0225.rst">https://github.com/python/peps/blob/main/peps/pep-0225.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0225.rst">2023-09-09 17:39:29 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#introduction">Introduction</a></li>
|
||
<li><a class="reference internal" href="#background">Background</a></li>
|
||
<li><a class="reference internal" href="#proposed-extension">Proposed extension</a></li>
|
||
<li><a class="reference internal" href="#prototype-implementation">Prototype Implementation</a></li>
|
||
<li><a class="reference internal" href="#alternatives-to-adding-new-operators">Alternatives to adding new operators</a></li>
|
||
<li><a class="reference internal" href="#alternative-forms-of-infix-operators">Alternative forms of infix operators</a></li>
|
||
<li><a class="reference internal" href="#semantics-of-new-operators">Semantics of new operators</a></li>
|
||
<li><a class="reference internal" href="#examples">Examples</a></li>
|
||
<li><a class="reference internal" href="#miscellaneous-issues">Miscellaneous issues</a></li>
|
||
<li><a class="reference internal" href="#impact-on-general-elementization">Impact on general elementization</a><ul>
|
||
<li><a class="reference internal" href="#notes">Notes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#impact-on-named-operators">Impact on named operators</a></li>
|
||
<li><a class="reference internal" href="#credits-and-archives">Credits and archives</a></li>
|
||
<li><a class="reference internal" href="#additional-references">Additional References</a></li>
|
||
</ul>
|
||
|
||
<br>
|
||
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0225.rst">Page Source (GitHub)</a>
|
||
</nav>
|
||
</section>
|
||
<script src="../_static/colour_scheme.js"></script>
|
||
<script src="../_static/wrap_tables.js"></script>
|
||
<script src="../_static/sticky_banner.js"></script>
|
||
</body>
|
||
</html> |