1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <!-- ra:: (version 14, updated 2021 February 22)
- (c) Daniel Llorens 2005-2020
- Permission is granted to copy, distribute and/or modify this document
- under the terms of the GNU Free Documentation License, Version 1.3 or
- any later version published by the Free Software Foundation; with no
- Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -->
- <!-- Created by GNU Texinfo 6.3, http://www.gnu.org/software/texinfo/ -->
- <head>
- <title>ra:: —An array library for C++20</title>
- <meta name="description" content="ra:: —An array library for C++20">
- <meta name="keywords" content="ra:: —An array library for C++20">
- <meta name="resource-type" content="document">
- <meta name="distribution" content="global">
- <meta name="Generator" content="makeinfo">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <link href="#Top" rel="start" title="Top">
- <link href="#Indices" rel="index" title="Indices">
- <link href="dir.html#Top" rel="up" title="(dir)">
- <style type="text/css">
- <!--
- a.summary-letter {text-decoration: none}
- blockquote.indentedblock {margin-right: 0em}
- blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
- blockquote.smallquotation {font-size: smaller}
- div.display {margin-left: 3.2em}
- div.example {margin-left: 3.2em}
- div.lisp {margin-left: 3.2em}
- div.smalldisplay {margin-left: 3.2em}
- div.smallexample {margin-left: 3.2em}
- div.smalllisp {margin-left: 3.2em}
- kbd {font-style: oblique}
- pre.display {font-family: inherit}
- pre.format {font-family: inherit}
- pre.menu-comment {font-family: serif}
- pre.menu-preformatted {font-family: serif}
- pre.smalldisplay {font-family: inherit; font-size: smaller}
- pre.smallexample {font-size: smaller}
- pre.smallformat {font-family: inherit; font-size: smaller}
- pre.smalllisp {font-size: smaller}
- span.nolinebreak {white-space: nowrap}
- span.roman {font-family: initial; font-weight: normal}
- span.sansserif {font-family: sans-serif; font-weight: normal}
- ul.no-bullet {list-style: none}
- -->
- </style>
- </head>
- <body lang="en">
- <h1 class="settitle" align="center">ra:: —An array library for C++20</h1>
- <a name="Top"></a>
- <div class="header">
- <p>
- Next: <a href="#Overview" accesskey="n" rel="next">Overview</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="ra_003a_003a"></a>
- <h1 class="top"><code>ra::</code></h1>
- <p><code>ra::</code> (version 14, updated 2021 February 22)
- </p>
- <p>(c) Daniel Llorens 2005–2020
- </p>
- <div class="smalldisplay">
- <pre class="smalldisplay">Permission is granted to copy, distribute and/or modify this document
- under the terms of the GNU Free Documentation License, Version 1.3 or
- any later version published by the Free Software Foundation; with no
- Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
- </pre></div>
- <p><code>ra::</code><a name="DOCF1" href="#FOOT1"><sup>1</sup></a> is a general purpose multidimensional array and expression template library for C++20. Please keep in mind that this manual is a work in progress. There are many errors and whole sections unwritten.
- </p>
- <table class="menu" border="0" cellspacing="0">
- <tr><td align="left" valign="top">• <a href="#Overview" accesskey="1">Overview</a>:</td><td> </td><td align="left" valign="top">Array programming and C++.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Usage" accesskey="2">Usage</a>:</td><td> </td><td align="left" valign="top">Everything you can do with <code>ra::</code>.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Extras" accesskey="3">Extras</a>:</td><td> </td><td align="left" valign="top">Additional libraries provided with <code>ra::</code>.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Hazards" accesskey="4">Hazards</a>:</td><td> </td><td align="left" valign="top">User beware.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Internals" accesskey="5">Internals</a>:</td><td> </td><td align="left" valign="top">For all the world to see.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#The-future" accesskey="6">The future</a>:</td><td> </td><td align="left" valign="top">Could be even better.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Reference" accesskey="7">Reference</a>:</td><td> </td><td align="left" valign="top">Systematic list of types and functions.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Sources" accesskey="8">Sources</a>:</td><td> </td><td align="left" valign="top">It’s been done before.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Indices" accesskey="9">Indices</a>:</td><td> </td><td align="left" valign="top">Or try the search function.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Notes">Notes</a>:</td><td> </td><td align="left" valign="top">Technically...
- </td></tr>
- </table>
- <hr>
- <a name="Overview"></a>
- <div class="header">
- <p>
- Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Overview-1"></a>
- <h2 class="chapter">1 Overview</h2>
- <p>A multidimensional array is a container whose elements can be looked up using a multi-index (i₀, i₁, ...). Each of the indices i₀, i₁, ... has a constant range [0, n₀), [0, n₁), ... independent of the values of the other indices, so the array is ‘rectangular’. The number of indices in the multi-index is the <em>rank</em> of the array, and the list (n₀, n₁, ... nᵣ₋₁) is the <em>shape</em> of the array. We speak of a rank-<em>r</em> array or of an <em>r</em>-array.
- </p>
- <p>Often we deal with multidimensional <em>expressions</em> where the elements aren’t stored anywhere, but are computed on demand when the expression is looked up. In this general sense, an ‘array’ is just a function of integers with a rectangular domain.
- </p>
- <p>Arrays (in the form of <em>matrices</em>, <em>vectors</em>, or <em>tensors</em>) are very common objects in math and programming, and it is enormously useful to be able to manipulate arrays as individual entities rather than as aggregates. Not only is
- </p>
- <pre class="verbatim">A = B+C;
- </pre>
- <p>much more compact and easier to read than
- </p>
- <pre class="verbatim">for (int i=0; i!=m; ++i)
- for (int j=0; j!=n; ++j)
- for (int k=0; k!=p; ++k)
- A(i, j, k) = B(i, j, k)+C(i, j, k);
- </pre>
- <p>but it’s also safer and less redundant. For example, the order of the loops may be something you don’t really care about.
- </p>
- <p>However, if array operations are implemented naively, a piece of code such as <code>A=B+C</code> may result in the creation of a temporary to hold <code>B+C</code> which is then assigned to <code>A</code>. Needless to say this is very wasteful if the arrays involved are large.
- </p>
- <a name="index-Blitz_002b_002b"></a>
- <p>Fortunately the problem is almost as old as aggregate data types, and other programming languages have addressed it with optimizations such as <a href="https://en.wikipedia.org/wiki/Loop_fission_and_fusion">‘loop fusion’</a>, ‘drag along’ [<a href="#Sources">Abr70</a>]
- , or ‘deforestation’ [<a href="#Sources">Wad90</a>]
- . In the C++ context the technique of ‘expression templates’ was pioneered in the late 90s by libraries such as Blitz++ [<a href="#Sources">bli17</a>]
- . It works by making <code>B+C</code> into an ‘expression object’ which holds references to its arguments and performs the sum only when its elements are looked up. The compiler removes the temporary expression objects during optimization, so that <code>A=B+C</code> results (in principle) in the same generated code as the complicated loop nest above.
- </p>
- <table class="menu" border="0" cellspacing="0">
- <tr><td align="left" valign="top">• <a href="#Rank-polymorphism" accesskey="1">Rank polymorphism</a>:</td><td> </td><td align="left" valign="top">What makes arrays special.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Drag-along-and-beating" accesskey="2">Drag along and beating</a>:</td><td> </td><td align="left" valign="top">The basic array optimizations.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Why-C_002b_002b" accesskey="3">Why C++</a>:</td><td> </td><td align="left" valign="top">High level, low level.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Guidelines" accesskey="4">Guidelines</a>:</td><td> </td><td align="left" valign="top">How <code>ra::</code> tries to do things.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Other-libraries" accesskey="5">Other libraries</a>:</td><td> </td><td align="left" valign="top">Inspiration and desperation.
- </td></tr>
- </table>
- <hr>
- <a name="Rank-polymorphism"></a>
- <div class="header">
- <p>
- Next: <a href="#Drag-along-and-beating" accesskey="n" rel="next">Drag along and beating</a>, Up: <a href="#Overview" accesskey="u" rel="up">Overview</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Rank-polymorphism-1"></a>
- <h3 class="section">1.1 Rank polymorphism</h3>
- <p><em>Rank polymorphism</em> is the ability to treat an array of rank <em>r</em> as an array of lower rank where the elements are themselves arrays.
- </p>
- <a name="index-cell"></a>
- <a name="index-frame"></a>
- <p>For example, think of a matrix A, a 2-array with sizes (n₀, n₁) where the elements A(i₀, i₁) are numbers. If we consider the subarrays (rows) A(0, ...), A(1, ...), ..., A(n₀-1, ...) as individual elements, then we have a new view of A as a 1-array of size n₀ with those rows as elements. We say that the rows A(i₀)≡A(i₀, ...) are the 1-<em>cells</em> of A, and the numbers A(i₀, i₁) are 0-cells of A. For an array of arbitrary rank <em>r</em> the (<em>r</em>-1)-cells of A are called its <em>items</em>. The prefix of the shape (n₀, n₁, ... nₙ₋₁₋ₖ) that is not taken up by the k-cell is called the k-<em>frame</em>.
- </p>
- <p>An obvious way to store an array in linearly addressed memory is to place its items one after another. So we would store a 3-array as
- </p>
- <blockquote>
- <p>A: [A(0), A(1), ...]
- </p></blockquote>
- <p>and the items of A(i₀), etc. are in turn stored in the same way, so
- </p>
- <blockquote>
- <p>A: [A(0): [A(0, 0), A(0, 1) ...], ...]
- </p></blockquote>
- <p>and the same for the items of A(i₀, i₁), etc.
- </p>
- <blockquote>
- <p>A: [[A(0, 0): [A(0, 0, 0), A(0, 0, 1) ...], A(0, 1): [A(0, 1, 0), A(0, 1, 1) ...]], ...]
- </p></blockquote>
- <a name="index-order_002c-row_002dmajor"></a>
- <p>This way to lay out an array in memory is called <em>row-major order</em> or <em>C-order</em>, since it’s the default order for built-in arrays in C (see <a href="#Other-libraries">Other libraries</a>). A row-major array A with sizes (n₀, n₁, ... nᵣ₋₁) can be looked up like this:
- </p>
- <a name="x_002dstrides"></a><blockquote>
- <p>A(i₀, i₁, ...) = (storage-of-A) [(((i₀n₁ + i₁)n₂ + i₂)n₃ + ...)+iᵣ₋₁] = (storage-of-A) [o + s₀i₀ + s₁i₁ + ...]
- </p></blockquote>
- <p>where the numbers (s₀, s₁, ...) are called the <em>strides</em><a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. Note that the ‘linear’ or ‘raveled’ address [o + s₀i₀ + s₁i₁ + ...] is an affine function of (i₀, i₁, ...). If we represent an array as a tuple
- </p>
- <blockquote>
- <p>A ≡ ((storage-of-A), o, (s₀, s₁, ...))
- </p></blockquote>
- <p>then any affine transformation of the indices can be achieved simply by modifying the numbers (o, (s₀, s₁, ...)), with no need to touch the storage. This includes very common operations such as: <a href="#x_002dtranspose">transposing</a> axes, <a href="#x_002dreverse">reversing</a> the order along an axis, most cases of <a href="#Slicing">slicing</a>, and sometimes even reshaping or tiling the array.
- </p>
- <p>A basic example is obtaining the i₀-th item of A:
- </p>
- <blockquote>
- <p>A(i₀) ≡ ((storage-of-A), o+s₀i₀, (s₁, ...))
- </p></blockquote>
- <p>Note that we can iterate over these items by simply bumping the pointer o+s₀i₀. This means that iterating over (k>0)-cells doesn’t cost any more than iterating over 0-cells (see <a href="#Cell-iteration">Cell iteration</a>).
- </p>
- <hr>
- <a name="Drag-along-and-beating"></a>
- <div class="header">
- <p>
- Next: <a href="#Why-C_002b_002b" accesskey="n" rel="next">Why C++</a>, Previous: <a href="#Rank-polymorphism" accesskey="p" rel="prev">Rank polymorphism</a>, Up: <a href="#Overview" accesskey="u" rel="up">Overview</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Drag-along-and-beating-1"></a>
- <h3 class="section">1.2 Drag along and beating</h3>
- <p>These two fundamental array optimizations are described in [<a href="#Sources">Abr70</a>]
- .
- </p>
- <p><em>Drag-along</em> is the process that delays evaluation of array operations. Expression templates can be seen as an implementation of drag-along. Drag-along isn’t an optimization in and of itself; it simply preserves the necessary information up to the point where the expression can be executed efficiently.
- </p>
- <p><em>Beating</em> is the implementation of certain array operations on the array <a href="#Containers-and-views">view</a> descriptor instead of on the array contents. For example, if <code>A</code> is a 1-array, one can implement <a href="#x_002dreverse"><code>reverse(A, 0)</code></a> by negating the <a href="#x_002dstrides">stride</a> and moving the offset to the other end of the array, without having to move any elements. More generally, beating applies to any function-of-indices (generator) that can take the place of an array in an array expression. For instance, an expression such as <a href="#x_002diota"><code>1+iota(3, 0)</code></a> can be beaten into <code>iota(3, 1)</code>, and this can enable further optimizations.
- </p>
- <hr>
- <a name="Why-C_002b_002b"></a>
- <div class="header">
- <p>
- Next: <a href="#Guidelines" accesskey="n" rel="next">Guidelines</a>, Previous: <a href="#Drag-along-and-beating" accesskey="p" rel="prev">Drag along and beating</a>, Up: <a href="#Overview" accesskey="u" rel="up">Overview</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Why-C_002b_002b-1"></a>
- <h3 class="section">1.3 Why C++</h3>
- <p>Of course the main reason is that (this being a personal project) I’m more familiar with C++ than with other languages to which the following might apply.
- </p>
- <p>C++ supports the low level control that is necessary for interoperation with external libraries and languages, but still has the abstraction power to create the features we want even though the language has no native support for most of them.
- </p>
- <a name="index-APL"></a>
- <a name="index-J"></a>
- <p>The classic array languages, APL [<a href="#Sources">FI73</a>]
- and J [<a href="#Sources">Ric08</a>]
- , have array support baked in. The same is true for other languages with array facilities such as Fortran or Octave/Matlab. Array libraries for general purpose languages usually depend heavily on C extensions. In Numpy’s case [<a href="#Sources">num17</a>]
- this is both for reasons of flexibility (e.g. to obtain predictable memory layout and machine types) and of performance.
- </p>
- <p>On the other extreme, an array library for C would be hampered by the limited means of abstraction in the language (no polymorphism, no metaprogramming, etc.) so the natural choice of C programmers is to resort to code generators, which eventually turn into new languages.
- </p>
- <p>In C++, a library is enough.
- </p>
- <hr>
- <a name="Guidelines"></a>
- <div class="header">
- <p>
- Next: <a href="#Other-libraries" accesskey="n" rel="next">Other libraries</a>, Previous: <a href="#Why-C_002b_002b" accesskey="p" rel="prev">Why C++</a>, Up: <a href="#Overview" accesskey="u" rel="up">Overview</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Guidelines-1"></a>
- <h3 class="section">1.4 Guidelines</h3>
- <p><code>ra::</code> attempts to be general, consistent, and transparent.
- </p>
- <p>Generality is achieved by removing arbitrary restrictions and by adopting the rank extension mechanism of J. <code>ra::</code> supports array operations with an arbitrary number of arguments. Any of the arguments in an array expression can be read from or written to. Arrays or array expressions can be of any rank. Slicing operations work for subscripts of any rank, as in APL. You can use your own types as array elements.
- </p>
- <p>Consistency is achieved by having a clear set of concepts and having the realizations of those concepts adhere to the concept as closely as possible. <code>ra::</code> offers a few different types of views and containers, but it should be possible to use them interchangeably whenever the properties that justify their existence are not involved. When this isn’t possible, it’s a bug. For example, it used to be the case that you couldn’t create a higher rank iterator on a <code>SmallView</code>, even though you could do it on a <code>View</code>; this was a bug.
- </p>
- <p>Sometimes consistency requires a choice. For example, given array views A and B, <code>A=B</code> copies the contents of view B into view A. To change view A instead (to treat A as a pointer) would be the default meaning of A=B for C++ types, and result in better consistency with the rest of the language, but I have decided that having consistency between views and containers (which ‘are’ their contents in a sense that views aren’t) is more important.
- </p>
- <p>Transparency is achieved by avoiding opaque types. An array view consists of a pointer and a list of strides and I see no point in hiding that. Manipulating the strides directly is often useful. A container consists of storage and a view and that isn’t hidden either. Some of the types have an obscure implementation but I consider that a defect. Ideally you should be able to rewrite expressions on the fly, or plug in your own traversal methods or storage handling.
- </p>
- <p>That isn’t to mean that you need to be in command of a lot of internal detail to be able to use the library. I hope to have provided a high level interface to most operations and a reasonably sweet syntax. However, transparency is critical to achieve interoperation with external libraries and languages. When you need to, you’ll be able to guarantee that an array is stored by compact columns or that the real parts are interleaved with the imaginary parts.
- </p>
- <hr>
- <a name="Other-libraries"></a>
- <div class="header">
- <p>
- Previous: <a href="#Guidelines" accesskey="p" rel="prev">Guidelines</a>, Up: <a href="#Overview" accesskey="u" rel="up">Overview</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Other-array-libraries"></a>
- <h3 class="section">1.5 Other array libraries</h3>
- <p>Here I try to list the C++ array libraries that I know of, or libraries that I think deserve a mention for the way they deal with arrays. It is not an extensive review, since I have only used a few of these libraries myself. Please follow the links if you want to be properly informed.
- </p>
- <p>Since the C++ standard library doesn’t offer a standard multidimensional array type, some libraries for specific tasks (linear algebra operations, finite elements, optimization) offer an accessory array library, which may be more or less general. Other libraries have generic array interfaces without needing to provide an array type. FFTW is a good example, maybe because it isn’t C++!
- </p>
- <a name="Standard-C_002b_002b"></a>
- <h4 class="subsection">1.5.1 Standard C++</h4>
- <p>The C++ language offers multidimensional arrays as a legacy feature from C, e.g. <code>int a[3][4]</code>. These decay to pointers when you do nearly anything with them, don’t know their own sizes or rank at runtime, and are generally too limited.
- </p>
- <p>The C++ standard library also offers a number of contiguous storage containers that can be used as 1-arrays: <code><array></code>, <code><vector></code> and <code><valarray></code>. Neither supports higher ranks out of the box, but <code><valarray></code> offers array operations for 1-arrays. <code>ra::</code> makes use of <code><array></code> and <code><vector></code> for storage and bootstrapping.
- </p>
- <p><code>ra::</code> accepts built-in arrays and standard library types as array objects (see <a href="#Compatibility">Compatibility</a>).
- </p>
- <a name="Blitz_002b_002b"></a>
- <h4 class="subsection">1.5.2 Blitz++</h4>
- <a name="index-Blitz_002b_002b-1"></a>
- <p>Blitz++ [<a href="#Sources">bli17</a>]
- pioneered the use of expression templates in C++. It supported higher rank arrays, as high as it was practical in C++98, but not dynamic rank. It also supported small arrays with compile time sizes (<code>Tiny</code>), and convenience features such as Fortran-order constructors and arbitrary lower bounds for the array indices (both of which <code>ra::</code> chooses not to support). It placed a strong emphasis on performance, with array traversal methods such as blocking, space filling curves, etc.
- </p>
- <p>To date it remains, I believe, one of the most general array libraries for C++. However, the implementation had to fight the limitations of C++98, and it offered no general rank extension mechanism.
- </p>
- <p>One important difference between Blitz++ and <code>ra::</code> is that Blitz++’s arrays were reference counted. <code>ra::</code> doesn’t do any memory management on its own: the default container types are explicitly values (data-owning) or views. You can select your own storage for the data-owning objects, including reference-counted storage (<code>ra::</code> declares a type using <code>std::shared_ptr</code>), but this is not the default.
- </p>
- <a name="Other-C_002b_002b-libraries"></a>
- <h4 class="subsection">1.5.3 Other C++ libraries</h4>
- <p>I guess this is important enough!
- </p>
- <a name="Other-languages"></a>
- <h4 class="subsection">1.5.4 Other languages</h4>
- <p>TODO Maybe review other languages, at least the big ones (Fortran/APL/J/Matlab/Numpy).
- </p>
- <hr>
- <a name="Usage"></a>
- <div class="header">
- <p>
- Next: <a href="#Extras" accesskey="n" rel="next">Extras</a>, Previous: <a href="#Overview" accesskey="p" rel="prev">Overview</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Usage-1"></a>
- <h2 class="chapter">2 Usage</h2>
- <p>This is an extended exposition of the features of <code>ra::</code> and is probably best read in order. For details on specific functions or types, please see <a href="#Reference">Reference</a>.
- </p>
- <table class="menu" border="0" cellspacing="0">
- <tr><td align="left" valign="top">• <a href="#Using-the-library" accesskey="1">Using the library</a>:</td><td> </td><td align="left" valign="top"><code>ra::</code> is a header-only library.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Containers-and-views" accesskey="2">Containers and views</a>:</td><td> </td><td align="left" valign="top">Data objects.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Array-operations" accesskey="3">Array operations</a>:</td><td> </td><td align="left" valign="top">Building and traversing expressions.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Rank-extension" accesskey="4">Rank extension</a>:</td><td> </td><td align="left" valign="top">How array operands are matched.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Cell-iteration" accesskey="5">Cell iteration</a>:</td><td> </td><td align="left" valign="top">At any rank.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Slicing" accesskey="6">Slicing</a>:</td><td> </td><td align="left" valign="top">Subscripting is a special operation.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Special-objects" accesskey="7">Special objects</a>:</td><td> </td><td align="left" valign="top">Not arrays, yet arrays.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#The-rank-conjunction" accesskey="8">The rank conjunction</a>:</td><td> </td><td align="left" valign="top">J comes to C++.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Compatibility" accesskey="9">Compatibility</a>:</td><td> </td><td align="left" valign="top">With the STL and other libraries.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Extension">Extension</a>:</td><td> </td><td align="left" valign="top">Using your own types and more.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Functions">Functions</a>:</td><td> </td><td align="left" valign="top">Ready to go.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Error-handling">Error handling</a>:</td><td> </td><td align="left" valign="top">What to check and what to do.
- </td></tr>
- </table>
- <hr>
- <a name="Using-the-library"></a>
- <div class="header">
- <p>
- Next: <a href="#Containers-and-views" accesskey="n" rel="next">Containers and views</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Using-ra_003a_003a"></a>
- <h3 class="section">2.1 Using <code>ra::</code></h3>
- <p><code>ra::</code> is a header only library with no dependencies, so you just need to place the ‘<samp>ra/</samp>’ folder somewhere in your include path and add <code>#include "ra/ra.hh"</code> at the top of your sources.
- </p>
- <p>A compiler with C++20 support is required. At the time of writing this means <b>gcc 10.1</b> with <samp>-std=c++20</samp>. Check the top README.md for more up-to-date information.
- </p>
- <p>Here is a minimal program<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>:
- </p>
- <div class="example">
- <pre class="verbatim">#include "ra/ra.hh"
- #include <iostream>
- int main()
- {
- ra::Big<char, 2> A({2, 5}, "helloworld");
- std::cout << ra::noshape << format_array(transpose<1, 0>(A), "|") << std::endl;
- }
- </pre><pre class="example">-| h|w
- e|o
- l|r
- l|l
- d|d
- </pre></div>
- <p>You may want to <code>#include "ra/real.hh"</code> and <code>"ra/complex.hh"</code>. These put some functions in the global namespace that make it easier to work on built-in scalar types or array expressions indistinctly. They are not required for the rest of the library to function.
- </p>
- <a name="index-container"></a>
- <hr>
- <a name="Containers-and-views"></a>
- <div class="header">
- <p>
- Next: <a href="#Array-operations" accesskey="n" rel="next">Array operations</a>, Previous: <a href="#Using-the-library" accesskey="p" rel="prev">Using the library</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Containers-and-views-1"></a>
- <h3 class="section">2.2 Containers and views</h3>
- <p><code>ra::</code> offers two kinds of data objects. The first kind, the <em>container</em>, owns its data. Creating a container requires memory and destroying it causes that memory to be freed.
- </p>
- <p>There are three kinds of containers: static size, static rank/dynamic size, and dynamic rank. Here static means ‘compile time constant’ while dynamic means ‘run time constant’. Some dynamic size arrays can be resized but dynamic rank arrays cannot normally have their rank changed. Instead, you create a new container or view with the rank you want.
- </p>
- <p>For example:
- </p>
- <div class="example">
- <pre class="verbatim">{
- ra::Small<double, 2, 3> a(0.); // a static size 2x3 array
- ra::Big<double, 2> b({2, 3}, 0.); // a dynamic size 2x3 array
- ra::Big<double> c({2, 3}, 0.); // a dynamic rank 2x3 array
- // a, b, c destroyed at end of scope
- }
- </pre></div>
- <p>The main reason to have all these different types is performance; the compiler can do a better job when it knows the size or the rank of the array. Also, the sizes of a static size array do not need to be stored in memory, so when you have thousands of small arrays it pays off to use the static size types. Static size or static rank arrays are also safer to use; sometimes <code>ra::</code> will be able to detect errors in the sizes or ranks of array operands at compile time, if the appropriate types are used.
- </p>
- <p>Container constructors come in two forms. The first form takes a single argument which is copied into the new container. This argument provides shape information if the container type requires it.<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>
- </p>
- <div class="example">
- <pre class="verbatim">using ra::Small, ra::Big;
- Small<int, 2, 2> a = {{1, 2}, {3, 4}}; // explicit contents
- Big<int, 2> a1 = {{1, 2}, {3, 4}}; // explicit contents
- Small<int, 2, 2> a2 = {{1, 2}}; // error: bad size
- Small<int, 2, 2> b = 7; // 7 is copied into b
- Small<int, 2, 2> c = a; // the contents of a are copied into c
- Big<int> d = a; // d takes the shape of a and a is copied into d
- Big<int> e = 0; // e is a 0-array with one element f()==0.
- </pre></div>
- <p>The second form takes two arguments, one giving the shape, the second the contents.
- </p>
- <a name="index-none"></a>
- <a name="index-uninitialized-container"></a>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 2> a({2, 3}, 1.); // a has size 2x3 and be filled with 1.
- ra::Big<double> b({2, 3}, ra::none); // b has size 2x3 and contents don't matter
- ra::Big<double> c({2, 3}, a); // c has size 2x3 and a is copied into c
- </pre></div>
- <p>The last example may result in an error if the shape of <code>a</code> and (2, <!-- /@w -->3) don’t match. Here the shape of <code>1.</code> [which is ()] matches (2, <!-- /@w -->3) by a mechanism of rank extension (see <a href="#Rank-extension">Rank extension</a>). The special value <code>ra::none</code> can be used to request <a href="https://en.cppreference.com/w/cpp/language/default_initialization">default initialization</a> of the container’s elements.
- </p>
- <p>When the content argument is a pointer or a 1D brace list, it’s handled especially, not for shape<a name="DOCF5" href="#FOOT5"><sup>5</sup></a>, but only as the (row-major) ravel of the content. The pointer constructor is unsafe —use at your own risk!<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>
- </p>
- <a name="index-order_002c-column_002dmajor"></a>
- <div class="example">
- <pre class="verbatim">Small<int, 2, 2> aa = {1, 2, 3, 4}; // ravel of the content
- ra::Big<double, 2> a({2, 3}, {1, 2, 3, 4, 5, 6}); // same as a = {{1, 2, 3}, {4, 5, 6}}
- </pre></div>
- <div class="example">
- <pre class="verbatim">double bx[6] = {1, 2, 3, 4, 5, 6}
- ra::Big<double, 2> b({3, 2}, bx); // {{1, 2}, {3, 4}, {5, 6}}
- double cx[4] = {1, 2, 3, 4}
- ra::Big<double, 2> c({3, 2}, cx); // *** WHO NOSE ***
- </pre></div>
- <div class="example">
- <pre class="verbatim">using sizes = mp::int_list<2, 3>;
- using strides = mp::int_list<1, 2>;
- ra::SmallArray<double, sizes, strides> a {{1, 2, 3}, {4, 5, 6}}; // stored column-major: 1 4 2 5 3 6
- </pre></div>
- <p>These produce compile time errors:
- </p>
- <div class="example">
- <pre class="verbatim">Big<int, 2> b = {1, 2, 3, 4}; // error: shape cannot be deduced from ravel
- Small<int, 2, 2> b = {1, 2, 3, 4 5}; // error: bad size
- Small<int, 2, 2> b = {1, 2, 3}; // error: bad size
- </pre></div>
- <a name="x_002dscalar_002dchar_002dstar"></a><p>Sometimes the pointer constructor gets in the way (see <a href="#x_002dscalar"><code>scalar</code></a>): </p>
- <div class="example">
- <pre class="verbatim">ra::Big<char const *, 1> A({3}, "hello"); // error: try to convert char to char const *
- ra::Big<char const *, 1> A({3}, ra::scalar("hello")); // ok, "hello" is a single item
- cout << ra::noshape << format_array(A, "|") << endl;
- </pre><pre class="example">-| hello|hello|hello
- </pre></div>
- <a name="index-view"></a>
- <p>A <em>view</em> is similar to a container in that it points to actual data in memory. However, the view doesn’t own that data and destroying the view won’t affect it. For example:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double> c({2, 3}, 0.); // a dynamic rank 2x3 array
- {
- auto c1 = c(1); // the second row of array c
- // c1 is destroyed here
- }
- cout << c(1, 1) << endl; // ok
- </pre></div>
- <p>The data accessed through a view is the data of the ‘root’ container, so modifying the former will be reflected in the latter.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double> c({2, 3}, 0.);
- auto c1 = c(1);
- c1(2) = 9.; // c(1, 2) = 9.
- </pre></div>
- <p>Just as for containers, there are separate types of views depending on whether the size is known at compile time, the rank is known at compile time but the size is not, or neither the size nor the rank are known at compile time. <code>ra::</code> has functions to create the most common kinds of views:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double> c {{1, 2, 3}, {4, 5, 6}};
- auto ct = transpose<1, 0>(c); // {{1, 4}, {2, 5}, {3, 6}}
- auto cr = reverse(c, 0); // {{4, 5, 6}, {1, 2, 3}}
- </pre></div>
- <p>However, views can point to anywhere in memory and that memory doesn’t have to belong to an <code>ra::</code> container. For example:
- </p>
- <div class="example">
- <pre class="verbatim">int raw[6] = {1, 2, 3, 4, 5, 6};
- ra::View<int> v1({{2, 3}, {3, 1}}, raw); // view with sizes {2, 3} strides {3, 1}
- ra::View<int> v2({2, 3}, raw); // same, default C (row-major) strides
- </pre></div>
- <p>Containers can be treated as views of the same ‘dynamicness’. If you declare a function
- </p>
- <div class="example">
- <pre class="verbatim">void f(ra::View<int, 3> & v);
- </pre></div>
- <p>you may pass it an object of type <code>ra::Big<int, 3></code>.
- </p>
- <hr>
- <a name="Array-operations"></a>
- <div class="header">
- <p>
- Next: <a href="#Rank-extension" accesskey="n" rel="next">Rank extension</a>, Previous: <a href="#Containers-and-views" accesskey="p" rel="prev">Containers and views</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Array-operations-1"></a>
- <h3 class="section">2.3 Array operations</h3>
- <p>To apply an operation to each element of an array, use the function <code>for_each</code>. The array is traversed in an order that is decided by the library.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Small<double, 2, 3> a = {{1, 2, 3}, {4, 5, 6}};
- double s = 0.;
- for_each([&s](auto && a) { s+=a; }, a);
- </pre><pre class="example">⇒ s = 21.
- </pre></div>
- <p>To construct an array expression but stop short of traversing it, use the function <code>map</code>. The expression will be traversed when it is assigned to a view, printed out, etc.
- </p>
- <div class="example">
- <pre class="verbatim">using T = ra::Small<double, 2, 2>;
- T a = {{1, 2}, {3, 4}};
- T b = {{10, 20}, {30, 40}};
- T c = map([](auto && a, auto && b) { return a+b; }, a, b); // (1)
- </pre><pre class="example">⇒ c = {{11, 22}, {33, 44}}
- </pre></div>
- <p>Expressions may take any number of arguments and be nested arbitrarily.
- </p>
- <div class="example">
- <pre class="verbatim">T d = 0;
- for_each([](auto && a, auto && b, auto && d) { d = a+b; },
- a, b, d); // same as (1)
- for_each([](auto && ab, auto && d) { d = ab; },
- map([](auto && a, auto && b) { return a+b; },
- a, b),
- d); // same as (1)
- </pre></div>
- <p>The operator of an expression may return a reference and you may assign to an expression in that case. <code>ra::</code> will complain if the expression is somehow not assignable.
- </p>
- <div class="example">
- <pre class="verbatim">T d = 0;
- map([](auto & d) -> decltype(auto) { return d; }, d) // just pass d along
- = map([](auto && a, auto && b) { return a+b; }, a, b); // same as (1)
- </pre></div>
- <p><code>ra::</code> defines many shortcuts for common array operations. You can of course just do:
- </p>
- <div class="example">
- <pre class="verbatim">T c = a+b; // same as (1)
- </pre></div>
- <hr>
- <a name="Rank-extension"></a>
- <div class="header">
- <p>
- Next: <a href="#Cell-iteration" accesskey="n" rel="next">Cell iteration</a>, Previous: <a href="#Array-operations" accesskey="p" rel="prev">Array operations</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Rank-extension-1"></a>
- <h3 class="section">2.4 Rank extension</h3>
- <p>Rank extension is the mechanism that allows <code>R+S</code> to be defined even when <code>R</code>, <code>S</code> may have different ranks. The idea is an interpolation of the following basic cases.
- </p>
- <p>Suppose first that <code>R</code> and <code>S</code> have the same rank. We require that the shapes be the same. Then the shape of <code>R+S</code> will be the same as the shape of either <code>R</code> or <code>S</code> and the elements of <code>R+S</code> will be
- </p>
- <blockquote>
- <p><code>(R+S)(i₀ i₁ ... i₍ᵣ₋₁₎) = R(i₀ i₁ ... i₍ᵣ₋₁₎) + S(i₀ i₁ ... i₍ᵣ₋₁₎)</code>
- </p></blockquote>
- <p>where <code>r</code> is the rank of <code>R</code>.
- </p>
- <p>Now suppose that <code>S</code> has rank 0. The shape of <code>R+S</code> is the same as the shape of <code>R</code> and the elements of <code>R+S</code> will be
- </p>
- <blockquote>
- <p><code>(R+S)(i₀ i₁ ... i₍ᵣ₋₁₎) = R(i₀ i₁ ... i₍ᵣ₋₁₎) + S()</code>.
- </p></blockquote>
- <p>The two rules above are supported by all primitive array languages, e.g. Matlab [<a href="#Sources">Mat</a>]
- . But suppose that <code>S</code> has rank <code>s</code>, where <code>0<s<r</code>. Looking at the expressions above, it seems natural to define <code>R+S</code> by
- </p>
- <blockquote>
- <p><code>(R+S)(i₀ i₁ ... i₍ₛ₋₁₎ ... i₍ᵣ₋₁₎) = R(i₀ i₁ ... i₍ₛ₋₁₎ ... i₍ᵣ₋₁₎) + S(i₀ i₁ ... i₍ₛ₋₁₎)</code>.
- </p></blockquote>
- <p>That is, after we run out of indices in <code>S</code>, we simply repeat the elements. We have aligned the shapes so:
- </p>
- <blockquote>
- <pre class="verbatim">[n₀ n₁ ... n₍ₛ₋₁₎ ... n₍ᵣ₋₁₎]
- [n₀ n₁ ... n₍ₛ₋₁₎]
- </pre></blockquote>
- <a name="index-shape-agreement_002c-prefix"></a>
- <a name="index-shape-agreement_002c-suffix"></a>
- <a name="index-Numpy"></a>
- <p>This rank extension rule is used by the J language [<a href="#Sources">J S</a>]
- and is known as <em>prefix agreement</em>. The opposite rule of <em>suffix agreement</em> is used, for example, in Numpy [<a href="#Sources">num17</a>]
- <a name="DOCF7" href="#FOOT7"><sup>7</sup></a>.
- </p>
- <p>As you can verify, the prefix agreement rule is distributive. Therefore it can be applied to nested expressions or to expressions with any number of arguments. It is applied systematically throughout <code>ra::</code>, even in assignments. For example,
- </p>
- <div class="example">
- <pre class="verbatim">ra::Small<int, 3> x {3, 5, 9};
- ra::Small<int, 3, 2> a = x; // assign x(i) to each a(i, j)
- </pre><pre class="example">⇒ a = {{3, 3}, {5, 5}, {9, 9}}
- </pre></div>
- <div class="example">
- <pre class="verbatim">ra::Small<int, 3> x(0.);
- ra::Small<int, 3, 2> a = {{1, 2}, {3, 4}, {5, 6}};
- x += a; // sum the rows of a
- </pre><pre class="example">⇒ x = {3, 7, 11}
- </pre></div>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 3> a({5, 3, 3}, ra::_0);
- ra::Big<double, 1> b({5}, 0.);
- b += transpose<0, 1, 1>(a); // b(i) = ∑ⱼ a(i, j, j)
- </pre><pre class="example">⇒ b = {0, 3, 6, 9, 12}
- </pre></div>
- <a name="index-Numpy-1"></a>
- <a name="index-broadcasting_002c-singleton_002c-newaxis"></a>
- <p>An weakness of prefix agreement is that the axes you want to match aren’t always the prefix axes. Other array systems offer a feature similar to rank extension called ‘broadcasting’ that is a bit more flexible. For example, in the way it’s implemented in Numpy [<a href="#Sources">num17</a>]
- , an array of shape [A B 1 D] will match an array of shape [A B C D]. The process of broadcasting consists in inserting so-called ‘singleton dimensions’ (axes with size one) to align the axes that one wishes to match. You can think of prefix agreement as a particular case of broadcasting where the singleton dimensions are added to the end of the shorter shapes automatically.
- </p>
- <p>A drawback of singleton broadcasting is that it muddles the distinction between a scalar and a vector of size 1. Sometimes, an axis of size 1 is no more than that, and if 2≠3 is a size error, it isn’t obvious why 1≠2 shouldn’t be. To avoid this problem, <code>ra::</code> supports broadcasting with undefined size axes (see <a href="#x_002dinsert"><code>insert</code></a>).
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 3> a({5, 3}, ra::_0);
- ra::Big<double, 1> b({3}, 0.);
- ra::Big<double, 3> c({1, 3}, ra::_0);
- // b(?, i) += a(j, i) → b(i) = ∑ⱼ a(j, i) (sum columns)
- b(ra::insert<1>) += a;
- c = a; // 1 ≠ 5, still an agreement error
- </pre></div>
- <p>Still another way to align array axes is provided by the <a href="#The-rank-conjunction">rank conjunction</a>.
- </p>
- <p>Even with axis insertion, it is still necessary that the axes one wishes to match are in the same order in all the arguments.
- <a href="#x_002dtranspose">Transposing</a> the axes before extension is a possible workaround.
- </p>
- <hr>
- <a name="Cell-iteration"></a>
- <div class="header">
- <p>
- Next: <a href="#Slicing" accesskey="n" rel="next">Slicing</a>, Previous: <a href="#Rank-extension" accesskey="p" rel="prev">Rank extension</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Cell-iteration-1"></a>
- <h3 class="section">2.5 Cell iteration</h3>
- <p><code>map</code> and <code>for_each</code> apply their operators to each element of their arguments; in other words, to the 0-cells of the arguments. But it is possible to specify directly the rank of the cells that one iterates over:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 3> a({5, 4, 3}, ra::_0);
- for_each([](auto && b) { /* b has shape (5 4 3) */ }, iter<3>(a));
- for_each([](auto && b) { /* b has shape (4 3) */ }, iter<2>(a));
- for_each([](auto && b) { /* b has shape (3) */ }, iter<1>(a));
- for_each([](auto && b) { /* b has shape () */ }, iter<0>(a)); // elements
- for_each([](auto && b) { /* b has shape () */ }, a); // same as iter<0>(a); default
- </pre></div>
- <p>One may specify the <em>frame</em> rank instead:
- </p>
- <div class="example">
- <pre class="verbatim">for_each([](auto && b) { /* b has shape () */ }, iter<-3>(a)); // same as iter<0>(a)
- for_each([](auto && b) { /* b has shape (3) */ }, iter<-2>(a)); // same as iter<1>(a)
- for_each([](auto && b) { /* b has shape (4 3) */ }, iter<-1>(a)); // same as iter<2>(a)
- </pre></div>
- <p>In this way it is possible to match shapes in various ways. Compare
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 2> a = {{1, 2, 3}, {4, 5, 6}};
- ra::Big<double, 1> b = {10, 20};
- ra::Big<double, 2> c = a * b; // multiply (each item of a) by (each item of b)
- </pre><pre class="example">⇒ a = {{10, 20, 30}, {80, 100, 120}}
- </pre></div>
- <p>with
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 2> a = {{1, 2, 3}, {4, 5, 6}};
- ra::Big<double, 1> b = {10, 20, 30};
- ra::Big<double, 2> c({2, 3}, 0.);
- iter<1>(c) = iter<1>(a) * iter<1>(b); // multiply (each item of a) by (b)
- </pre><pre class="example">⇒ a = {{10, 40, 90}, {40, 100, 180}}
- </pre></div>
- <p>Note that in this case we cannot construct <code>c</code> directly from <code>iter<1>(a) * iter<1>(b)</code>, since the constructor for <code>ra::Big</code> matches its argument using (the equivalent of) <code>iter<0>(*this)</code>. See <a href="#x_002diter"><code>iter</code></a> for more examples.
- </p>
- <p>Cell iteration is appropriate when the operations take naturally operands of rank > 0; for instance, the operation ‘determinant of a matrix’ is naturally of rank 2. When the operation is of rank 0, such as <code>*</code> above, there may be faster ways to rearrange shapes for matching (see <a href="#The-rank-conjunction">The rank conjunction</a>).
- </p>
- <p>FIXME More examples.
- </p>
- <hr>
- <a name="Slicing"></a>
- <div class="header">
- <p>
- Next: <a href="#Special-objects" accesskey="n" rel="next">Special objects</a>, Previous: <a href="#Cell-iteration" accesskey="p" rel="prev">Cell iteration</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Slicing-1"></a>
- <h3 class="section">2.6 Slicing</h3>
- <p>Slicing is an array extension of the subscripting operation. However, tradition and convenience have given it a special status in most array languages, together with some peculiar semantics that <code>ra::</code> supports.
- </p>
- <p>The form of the scripting operator <code>A(i₀, i₁, ...)</code> makes it plain that <code>A</code> is a function of <code>rank(A)</code> integer arguments. An array extension is immediately available through <code>map</code>. For example:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 1> a = {1., 2., 3., 4.};
- ra::Big<int, 1> i = {1, 3};
- map(a, i) = 77.;
- </pre><pre class="example">⇒ a = {1., 77., 3, 77.}
- </pre></div>
- <p>Just as with any use of <code>map</code>, array arguments are subject to the prefix agreement rule.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 2> a({2, 2}, {1., 2., 3., 4.});
- ra::Big<int, 1> i = {1, 0};
- ra::Big<double, 1> b = map(a, i, 0);
- </pre><pre class="example">⇒ b = {3., 1.} // {a(1, 0), a(0, 0)}
- </pre></div>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> j = {0, 1};
- b = map(a, i, j);
- </pre><pre class="example">⇒ b = {3., 2.} // {a(1, 0), a(0, 1)}
- </pre></div>
- <p>The latter is a form of sparse subscripting.
- </p>
- <p>Most array operations (e.g. <code>+</code>) are defined through <code>map</code> in this way. For example, <code>A+B+C</code> is defined as <code>map(+, A, B, C)</code> (or the equivalent <code>map(+, map(+, A, B), C)</code>). Not so for the subscripting operation:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double, 2> A {{1., 2.}, {3., 4.}};
- ra::Big<int, 1> i = {1, 0};
- ra::Big<int, 1> j = {0, 1};
- // {{A(i₀, j₀), A(i₀, j₁)}, {A(i₁, j₀), A(i₁, j₁)}}
- ra::Big<double, 2> b = A(i, j);
- </pre><pre class="example">⇒ b = {{3., 4.}, {1., 2.}}
- </pre></div>
- <p><code>A(i, j, ...)</code> is defined as the <em>outer product</em> of the indices <code>(i, j, ...)</code> with operator <code>A</code>, because this operation sees much more use in practice than <code>map(A, i, j ...)</code>.
- </p>
- <p>Besides, when the subscripts <code>i, j, ...</code> are scalars or <em>linear ranges</em> (integer sequences of the form <code>(o, o+s, ..., o+s*(n-1))</code>), the subscripting can be performed inmediately at constant cost and without needing to construct an expression object. This optimization is called <a href="#Drag-along-and-beating"><em>beating</em></a>.
- </p>
- <p><code>ra::</code> isn’t smart enough to know when an arbitrary expression might be a linear range, so the following special objects are provided:
- </p>
- <a name="x_002diota"></a><dl>
- <dt><a name="index-iota"></a>Special object<!-- /@w -->: <strong>iota</strong> <em>count [start:0 [step:1]]</em></dt>
- <dd><p>Create a linear range <code>start, start+step, ... start+step*(count-1)</code>.
- </p></dd></dl>
- <p>This can used anywhere an array expression is expected.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> a = ra::iota(4, 3 -2);
- </pre><pre class="example">⇒ a = {3, 1, -1, -3}
- </pre></div>
- <p>Here, <code>b</code> and <code>c</code> are <code>View</code>s (see <a href="#Containers-and-views">Containers and views</a>).
- </p><div class="example">
- <pre class="verbatim">ra::Big<int, 1> a = {1, 2, 3, 4, 5, 6};
- auto b = a(iota(3));
- auto c = a(iota(3, 3));
- </pre><pre class="example">⇒ a = {1, 2, 3}
- ⇒ a = {4, 5, 6}
- </pre></div>
- <dl>
- <dt><a name="index-all"></a>Special object<!-- /@w -->: <strong>all</strong></dt>
- <dd><p>Create a linear range <code>0, 1, ... (nᵢ-1)</code> when used as a subscript for the <code>i</code>-th argument of a subscripting expression.
- </p></dd></dl>
- <p>This object cannot stand alone as an array expression. All the examples below result in <code>View</code> objects:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 2> a({3, 2}, {1, 2, 3, 4, 5, 6});
- auto b = a(ra::all, ra::all); // (1) a view of the whole of a
- auto c = a(iota(3), iota(2)); // same as (1)
- auto d = a(iota(3), ra::all); // same as (1)
- auto e = a(ra:all, iota(2)); // same as (1)
- auto f = a(0, ra::all); // first row of a
- auto g = a(ra::all, 1); // second column of a
- </pre></div>
- <p><code>all</code> is a special case (<code>dots<1></code>) of the more general object <code>dots</code>.
- </p>
- <dl>
- <dt><a name="index-dots_003cn_003e"></a>Special object<!-- /@w -->: <strong>dots<n></strong></dt>
- <dd><p>Equivalent to as many instances of <code>ra::all</code> as indicated by <code>n</code>, which must not be negative. Each instance takes the place of one argument to the subscripting operation.
- </p></dd></dl>
- <p>This object cannot stand alone as an array expression. All the examples below result in <code>View</code> objects:
- </p>
- <div class="example">
- <pre class="verbatim">auto h = a(ra::all, ra::all); // same as (1)
- auto i = a(ra::all, ra::dots<1>); // same as (1)
- auto j = a(ra::dots<2>); // same as (1)
- auto k = a(ra::dots<0>, ra::dots<2>); // same as (1)
- auto l = a(0, ra::dots<1>); // first row of a
- auto m = a(ra::dots<1>, 1); // second column of a
- </pre></div>
- <p>This is useful when writing rank-generic code, see <code>examples/maxwell.cc</code> in the distribution for an example.
- </p>
- <a name="x_002dinsert"></a><dl>
- <dt><a name="index-insert_003cn_003e"></a>Special object<!-- /@w -->: <strong>insert<n></strong></dt>
- <dd><p>Inserts <code>n</code> new axes at the subscript position. <code>n</code> must not be negative.
- </p></dd></dl>
- <p>The new axes have stride 0 and undefined size, so they will match any size on those axes by repeating items. <code>insert</code> objects cannot stand alone as an array expression. The examples below result in <code>View</code> objects:
- </p>
- <div class="example">
- <pre class="verbatim">auto h = a(insert<0>); // same as (1)
- auto k = a(insert<1>); // shape [undefined, 3, 2]
- </pre></div>
- <a name="index-broadcasting_002c-singleton_002c-Numpy"></a>
- <p><code>insert<n></code> main use is to prepare arguments for broadcasting. In other array systems (e.g. Numpy) broadcasting is done with singleton dimensions, that is, dimensions of size one match dimensions of any size. In <code>ra::</code> singleton dimensions aren’t special, so broadcasting requires the use of <code>insert</code>. For example: </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> x = {1, 10};
- // match shapes [2, U, U] with [U, 3, 2] to produce [2, 3, 2]
- cout << x(ra::all, ra::insert<2>) * a(insert<1>) << endl;
- </pre><pre class="example">-| 2 3 2
- 1 2
- 3 4
- 5 6
- 10 20
- 30 40
- 50 60
- </pre></div>
- <p>Here’s a way to perform the outer product of two <code>Views</code> of static rank (but see <a href="#x_002dfrom"><code>from</code></a> for a more general way):
- </p><div class="example">
- <pre class="verbatim">cout << (a(ra::dots<a.rank()>, ra::insert<b.rank()>) * b(ra::insert<a.rank()>, ra::dots<b.rank()>)) << endl;
- // same thing by prefix matching
- cout << (a * b(ra::insert<a.rank()>)) << endl;
- </pre></div>
- <p>In addition to the special objects listed above, you can also omit any trailing <code>ra::all</code> subscripts. For example:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 3> a({2, 2, 2}, {1, 2, 3, 4, 5, 6, 7, 8});
- auto a0 = a(0); // same as a(0, ra::all, ra::all)
- auto a10 = a(1, 0); // same as a(1, 0, ra::all)
- </pre><pre class="example">⇒ a0 = {{1, 2}, {3, 4}}
- ⇒ a10 = {5, 6}
- </pre></div>
- <p>This supports the notion (see <a href="#Rank-polymorphism">Rank polymorphism</a>) that a 3-array is also an 2-array where the elements are 1-arrays themselves, or a 1-array where the elements are 2-arrays. This important property is directly related to the mechanism of rank extension (see <a href="#Rank-extension">Rank extension</a>).
- </p>
- <a name="Subscripting-and-rank_002d0-views"></a>
- <h4 class="subsection">2.6.1 Subscripting and rank-0 views</h4>
- <a name="index-view_002c-rank-0"></a>
- <a name="index-rank_002c-dynamic"></a>
- <a name="index-rank_002c-static"></a>
- <p>When the result of the subscripting operation would have rank 0, the type returned is the type of the view <em>element</em> and not a rank-0 view as long as the rank of the result can be determined at compile time. When that’s not possible (for instance, the subscripted view has dynamic rank) then a rank-0 view is returned instead. An automatic conversion is defined for rank-0 views, but manual conversion may be needed in some contexts.
- </p>
- <div class="example">
- <pre class="verbatim">using T = std::complex<double>;
- int f(T &);
- Big<T, 2> a({2, 3}, 0); // static rank
- Big<T> b({2, 3}, 0); // dynamic rank
- cout << a(0, 0).real_part() << endl; // ok, a(0, 0) returns complex &
- // cout << b(0, 0).real_part() << endl; // error, View<T> has no member real_part
- cout << ((T &)(b(0, 0))).real_part() << endl; // ok, manual conversion to T &
- cout << f(b(0, 0)) << endl; // ok, automatic conversion from View<T> to T &
- // cout << f(a(0)) << endl; // compile time error, conversion failed since static rank of a(0) is not 0
- // cout << f(b(0)) << endl; // runtime error, conversion failed since dynamic rank of b(0) is not 0
- </pre></div>
- <hr>
- <a name="Special-objects"></a>
- <div class="header">
- <p>
- Next: <a href="#The-rank-conjunction" accesskey="n" rel="next">The rank conjunction</a>, Previous: <a href="#Slicing" accesskey="p" rel="prev">Slicing</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Special-objects-1"></a>
- <h3 class="section">2.7 Special objects</h3>
- <dl>
- <dt><a name="index-TensorIndex_003cn_002c"></a>Special object<!-- /@w -->: <strong>TensorIndex<n,</strong> <em>integer_type=ra::dim_t></em></dt>
- <dd><p><code>TensorIndex<n></code> represents the <code>n</code>-th index of an array expression. <code>TensorIndex<n></code> is itself an array expression of rank <code>n</code>-1 and size undefined. It must be used with other terms whose dimensions are defined, so that the overall shape of the array expression can be determined.
- </p>
- <p><code>ra::</code> offers the shortcut <code>ra::_0</code> for <code>ra::TensorIndex<0>{}</code>, etc.
- </p></dd></dl>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> v = {1, 2, 3};
- cout << (v - ra::_0) << endl; // { 1-0, 2-1, 3-2 }
- // cout << (ra::_0) << endl; // error: TensorIndex cannot drive array expression
- // cout << (v - ra::_1) << endl; // error: TensorIndex cannot drive array expression
- ra::Big<int, 2> a({3, 2}, 0);
- cout << (a + ra::_0 - ra::_1) << endl; // {{0, -1, -2}, {1, 0, -1}, {2, 1, 0}}
- </pre></div>
- <hr>
- <a name="The-rank-conjunction"></a>
- <div class="header">
- <p>
- Next: <a href="#Compatibility" accesskey="n" rel="next">Compatibility</a>, Previous: <a href="#Special-objects" accesskey="p" rel="prev">Special objects</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="The-rank-conjunction-1"></a>
- <h3 class="section">2.8 The rank conjunction</h3>
- <p>We have seen in <a href="#Cell-iteration">Cell iteration</a> that it is possible to treat an r-array as an array of lower rank with subarrays as its elements. With the <a href="#x_002diter"><code>iter<cell rank></code></a> construction, this ‘exploding’ is performed (notionally) on the argument; the operation of the array expression is applied blindly to these cells, whatever they turn out to be.
- </p>
- <div class="example">
- <pre class="verbatim">for_each(my_sort, iter<1>(A)); // (in ra::) my_sort is a regular function, cell rank must be given
- for_each(my_sort, iter<0>(A)); // (in ra::) error, bad cell rank
- </pre></div>
- <p>The array language J has instead the concept of <em>verb rank</em>. Every function (or <em>verb</em>) has an associated cell rank for each of its arguments. Therefore <code>iter<cell rank></code> is not needed.
- </p>
- <div class="example">
- <pre class="verbatim">for_each(sort_rows, A); // (not in ra::) will iterate over 1-cells of A, sort_rows knows
- </pre></div>
- <p><code>ra::</code> doesn’t have ‘verb ranks’ yet. In practice one can think of <code>ra::</code>’s operations as having a verb rank of 0. However, <code>ra::</code> supports a limited form of J’s <em>rank conjunction</em> with the function <a href="#x_002dwrank"><code>wrank</code></a>.
- </p>
- <p>This is an operator that takes one verb (such operators are known as <em>adverbs</em> in J) and produces another verb with different ranks. These ranks are used for rank extension through prefix agreement, but then the original verb is used on the cells that result. The rank conjunction can be nested, and this allows repeated rank extension before the innermost operation is applied.
- </p>
- <p>A standard example is ‘outer product’.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> a = {1, 2, 3};
- ra::Big<int, 1> b = {40, 50};
- ra::Big<int, 2> axb = map(ra::wrank<0, 1>([](auto && a, auto && b) { return a*b; }),
- a, b)
- </pre><pre class="example">⇒ axb = {{40, 80, 120}, {50, 100, 150}}
- </pre></div>
- <p>It works like this. The verb <code>ra::wrank<0, 1>([](auto && a, auto && b) { return a*b; })</code> has verb ranks (0, 1), so the 0-cells of <code>a</code> are paired with the 1-cells of <code>b</code>. In this case <code>b</code> has a single 1-cell. The frames and the cell shapes of each operand are:
- </p>
- <div class="example">
- <pre class="verbatim">a: 3 |
- b: | 2
- </pre></div>
- <p>Now the frames are rank-extended through prefix agreement.
- </p>
- <div class="example">
- <pre class="verbatim">a: 3 |
- b: 3 | 2
- </pre></div>
- <p>Now we need to perform the operation on each cell. The verb <code>[](auto && a, auto && b) { return a*b; }</code> has verb ranks (0, 0). This results in the 0-cells of <code>a</code> (which have shape ()) being rank-extended to the shape of the 1-cells of <code>b</code> (which is (2)).
- </p>
- <div class="example">
- <pre class="verbatim">a: 3 | 2
- b: 3 | 2
- </pre></div>
- <p>This use of the rank conjunction is packaged in <code>ra::</code> as the <a href="#x_002dfrom"><code>from</code></a> operator. It supports any number of arguments, not only two.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> a = {1, 2, 3};
- ra::Big<int, 1> b = {40, 50};
- ra::Big<int, 2> axb = from([](auto && a, auto && b) { return a*b; }), a, b)
- </pre><pre class="example">⇒ axb = {{40, 80, 120}, {50, 100, 150}}
- </pre></div>
- <p>Another example is matrix multiplication. For 2-array arguments C, A and B with shapes C: (m, n) A: (m, p) and B: (p, n), we want to perform the operation C(i, j) += A(i, k)*B(k, j). The axis alignment gives us the ranks we need to use.
- </p>
- <div class="example">
- <pre class="verbatim">C: m | | n
- A: m | p |
- B: | p | n
- </pre></div>
- <p>First we’ll align the first axes of C and A using the cell ranks (1, 1, 2). The cell shapes are:
- </p>
- <div class="example">
- <pre class="verbatim">C: m | n
- A: m | p
- B: | p n
- </pre></div>
- <p>Then we’ll use the ranks (1, 0, 1) on the cells:
- </p>
- <div class="example">
- <pre class="verbatim">C: m | | n
- A: m | p |
- B: | p | n
- </pre></div>
- <p>The final operation is a standard operation on arrays of scalars. In actual <code>ra::</code> syntax:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big A({3, 2}, {1, 2, 3, 4, 5, 6});
- ra::Big B({2, 3}, {7, 8, 9, 10, 11, 12});
- ra::Big C({3, 3}, 0.);
- for_each(ra::wrank<1, 1, 2>(ra::wrank<1, 0, 1>([](auto && c, auto && a, auto && b) { c += a*b; })), C, A, B);
- </pre><pre class="example">⇒ C = {{27, 30, 33}, {61, 68, 75}, {95, 106, 117}}
- </pre></div>
- <p>Note that <code>wrank</code> cannot be used to transpose axes in general.
- </p>
- <p>I hope that in the future something like <code>C(i, j) += A(i, k)*B(k, j)</code>, where <code>i, j, k</code> are special objects, can be automatically translated to the requisite combination of <code>wrank</code> and perhaps also <a href="#x_002dtranspose"><code>transpose</code></a>. For the time being, you have to align or transpose the axes yourself.
- </p>
- <hr>
- <a name="Compatibility"></a>
- <div class="header">
- <p>
- Next: <a href="#Extension" accesskey="n" rel="next">Extension</a>, Previous: <a href="#The-rank-conjunction" accesskey="p" rel="prev">The rank conjunction</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Compatibility-1"></a>
- <h3 class="section">2.9 Compatibility</h3>
- <a name="Using-other-C-and-C_002b_002b-types-with-ra_003a_003a"></a>
- <h4 class="subsection">2.9.1 Using other C and C++ types with <code>ra::</code></h4>
- <a name="index-foreign-type"></a>
- <p><code>ra::</code> accepts certain types from outside <code>ra::</code> (<em>foreign types</em>) as array expressions. Generally it is enough to mix the foreign type with a type from <code>ra::</code> and let deduction work.
- </p>
- <div class="example">
- <pre class="verbatim">std::vector<int> x = {1, 2, 3};
- ra::Small<int, 3> y = {6, 5, 4};
- cout << (x-y) << endl;
- </pre><pre class="example">-| -5 -3 -1
- </pre></div>
- <a name="index-start"></a>
- <p>Foreign types can be brought into <code>ra::</code> explicitly with the function <a href="#x_002dstart"><code>start</code></a>.
- </p>
- <div class="example">
- <pre class="verbatim">std::vector<int> x = {1, 2, 3};
- // cout << sum(x) << endl; // error, sum not found
- cout << sum(ra::start(x)) << endl;
- cout << ra::sum(x) << endl;
- </pre><pre class="example">-| 6
- 6
- </pre></div>
- <p>The following types are accepted as foreign types:
- </p>
- <ul>
- <li> <code>std::vector</code>
- produces an expression of rank 1 and dynamic size.
- </li><li> <code>std::array</code>
- produces an expression of rank 1 and static size.
- </li><li> Built-in arrays <a name="index-built_002din-array"></a>
- produce an expression of positive rank and static size.
- </li><li> Raw pointers
- produce an expression of rank 1 and <em>undefined</em> size. Raw pointers must be brought into <code>ra::</code> explicitly with the function <a href="#x_002dptr"><code>ptr</code></a>.
- </li></ul>
- <p>Compare:
- </p>
- <div class="example">
- <pre class="verbatim">int p[] = {1, 2, 3};
- int * z = p;
- ra::Big<int, 1> q {1, 2, 3};
- q += p; // ok, q is ra::, p is foreign object with size info
- ra::start(p) += q; // can't redefine operator+=(int[]), foreign needs ra::start()
- // z += q; // error: raw pointer needs ra::ptr()
- ra::ptr(z) += p; // ok, size is determined by foreign object p
- </pre></div>
- <a name="x_002dis_002dscalar"></a><p>Some types are accepted automatically as scalars. These include:
- </p><ul>
- <li> Any type <code>T</code> for which <code>std::is_scalar_v<T></code> is true, <em>except</em> pointers. These include <code>char</code>, <code>int</code>, <code>double</code>, etc.
- </li><li> <code>std::complex<T></code>, if you import <code>ra/complex.hh</code>.
- </li></ul>
- <p>You can add your own types as scalar types with the following declaration (see <code>ra/complex.hh</code>):
- </p>
- <pre class="verbatim"> namespace ra { template <> constexpr bool is_scalar_def<MYTYPE> = true; }
- </pre>
- <p>Otherwise, you can bring a scalar object into <code>ra::</code> on the spot, with the function <a href="#x_002dscalar"><code>scalar</code></a>.
- </p>
- <a name="Using-ra_003a_003a-types-with-the-STL"></a>
- <h4 class="subsection">2.9.2 Using <code>ra::</code> types with the STL</h4>
- <p>General <code>ra::</code> <a href="#Containers-and-views">views</a> provide STL compatible <code>ForwardIterator</code>s through the members <code>begin()</code> and <code>end()</code>. These iterators traverse the elements of the array (0-cells) in row major order, regardless of the internal order of the view.
- </p>
- <p>For <a href="#Containers-and-views">containers</a> <code>begin()</code> provides <code>RandomAccessIterator</code>s, which is handy for certain functions such as <code>sort</code>. There’s no reason why all views couldn’t provide <code>RandomAccessIterator</code>, but these wouldn’t be efficient in general for ranks above 1, and I haven’t implemented them. The container <code>RandomAccessIterator</code>s that are provided are in fact raw pointers.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int> x {3, 2, 1}; // x is a Container
- auto y = x(); // y is a View on x
- // std::sort(y.begin(), y.end()); // error: y.begin() is not RandomAccessIterator
- std::sort(x.begin(), x.end()); // ok, we know x is stored in row-major order
- </pre><pre class="example">⇒ x = {1, 2, 3}
- </pre></div>
- <a name="index-other-libraries_002c-interfacing-with"></a>
- <a name="Using-ra_003a_003a-types-with-other-libraries"></a>
- <h4 class="subsection">2.9.3 Using <code>ra::</code> types with other libraries</h4>
- <p>When you have to pass arrays back and forth between your program and an external library, perhaps even another language, it is necessary for both sides to agree on a memory layout. <code>ra::</code> gives you access to its own memory layout and allows you to obtain an <code>ra::</code> view on any type of memory.
- </p>
- <a name="The-good-array-citizen"></a>
- <h4 class="subsubsection">2.9.3.1 The good array citizen</h4>
- <p>FIXME Put these in examples/ and reference them here.
- </p>
- <a name="index-BLIS"></a>
- <p>The good array citizen describes its arrays with the same parameters as <code>ra::</code>, that is: a pointer, plus a size and a stride per dimension. You pass those and you’re done; you don’t have to worry about special cases. Say <a href="https://github.com/flame/blis">BLIS</a>:
- </p>
- <blockquote>
- <pre class="verbatim">#include <blis.h>
- ra::Big<double, 2> A({M, K}, ...);
- ra::Big<double, 2> B({K, N}, ...);
- ra::Big<double, 2> C({M, N}, ...);
- double alpha = ...;
- double beta = ...;
- // C := βC + αAB
- bli_dgemm(BLIS_NO_TRANSPOSE, BLIS_NO_TRANSPOSE, M, N, K, &alpha,
- A.data(), A.stride(0), A.stride(1),
- B.data(), B.stride(0), B.stride(1),
- &beta, C.data(), C.stride(0), C.stride(1));
- </pre></blockquote>
- <a name="index-FFTW"></a>
- <p>Another good array citizen, <a href="http://fftw.org">FFTW</a> handles arbitrary rank:
- </p>
- <blockquote>
- <pre class="verbatim">#include <fftw3.h>
- ...
- using complex = std::complex<double>;
- static_assert(sizeof(complex)==sizeof(fftw_complex));
- // forward DFT over the last r axes of a -> b
- void fftw(int r, ra::View<complex> const a, ra::View<complex> b)
- {
- int const rank = a.rank();
- assert(r>0 && r<=rank);
- assert(every(shape(a)==shape(b)));
- fftw_iodim dims[r];
- fftw_iodim howmany_dims[rank-r];
- for (int i=0; i!=rank; ++i) {
- if (i>=rank-r) {
- dims[i-rank+r].n = a.size(i);
- dims[i-rank+r].is = a.stride(i);
- dims[i-rank+r].os = b.stride(i);
- } else {
- howmany_dims[i].n = a.size(i);
- howmany_dims[i].is = a.stride(i);
- howmany_dims[i].os = b.stride(i);
- }
- }
- fftw_plan p;
- p = fftw_plan_guru_dft(r, dims, rank-r, howmany_dims,
- (fftw_complex *)(a.data()), (fftw_complex *)(b.data()),
- FFTW_FORWARD, FFTW_ESTIMATE);
- fftw_execute(p);
- fftw_destroy_plan(p);
- }
- </pre></blockquote>
- <a name="index-Guile"></a>
- <p>Translating array descriptors from a foreign language should be fairly simple. For example, this is how to convert a <a href="https://www.gnu.org/software/guile/manual/html_node/Accessing-Arrays-from-C.html#Accessing-Arrays-from-C">Guile</a> array view into an <code>ra::</code> view:
- </p>
- <blockquote>
- <pre class="verbatim"> SCM a; // say a is #nf64(...)
- ...
- scm_t_array_handle h;
- scm_array_get_handle(a, &h);
- scm_t_array_dim const * dims = scm_array_handle_dims(&h);
- View<double> v(map([](int i) { return ra::Dimv {dim[i].ubnd-dim[i].lbnd+1, dim[i].inc}; },
- ra::iota(scm_array_handle_rank(&h))),
- scm_array_handle_f64_writable_elements(&h));
- ...
- scm_array_handle_release(&h);
- </pre></blockquote>
- <a name="index-Numpy-2"></a>
- <a name="index-Python"></a>
- <p>Numpy’s C API has the type <a href="https://docs.scipy.org/doc/numpy/reference/c-api.array.html"><code>PyArrayObject</code></a> which can be used in the same way as Guile’s <code>scm_t_array_handle</code> in the example above.
- </p>
- <p>Generally it is simpler to let the foreign language handle the memory, even though there should be ways to transfer ownership (e.g. Guile has <a href="https://www.gnu.org/software/guile/manual/html_node/SRFI_002d4-API.html#index-scm_005ftake_005ff64vector"><code>scm_take_xxx</code></a>).
- </p>
- <a name="The-bad-array-citizen"></a>
- <h4 class="subsubsection">2.9.3.2 The bad array citizen</h4>
- <p>Unfortunately there are many libraries that don’t accept general array parameters, or that do strange things with particular values of sizes and/or strides.
- </p>
- <p>The most common case is that a library doesn’t handle strides at all, and it only accepts unit stride for rank 1 arrays, or packed row-major or column-major storage for higher rank arrays. In that case, you might be forced to copy your array before passing it along.
- </p>
- <p>FIXME using is_c_order, etc.
- </p>
- <p>Other libraries do accept strides, but not general ones. For example <a href="https://www.netlib.org/blas">https://www.netlib.org/blas</a>’ <code>cblas_dgemm</code> has this prototype:
- </p>
- <blockquote>
- <pre class="verbatim">cblas_dgemm(order, transA, transB, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc);
- </pre></blockquote>
- <p><code>A</code>, <code>B</code>, <code>C</code> are (pointers to) 2-arrays, but the routine accepts only one stride argument for each (<code>lda</code>, etc.). CBLAS also doesn’t understand <code>lda</code> as a general stride, but rather as the dimension of a larger array that you’re slicing <code>A</code> from, and some implementations will handle negative or zero <code>lda</code> in bizarre ways.
- </p>
- <p>Sometimes you can work around this by fiddling with <code>transA</code> and <code>transB</code>, but in general you need to check your array parameters and you may need to make copies.
- </p>
- <a name="index-OpenGL"></a>
- <p>OpenGL is another library that requires <a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml">contortions:</a>
- </p>
- <blockquote>
- <pre class="verbatim">void glVertexAttribPointer(GLuint index,
- GLint size,
- GLenum type,
- GLboolean normalized,
- GLsizei stride,
- const GLvoid * pointer);
- </pre>
- <p>[...]
- </p>
- <p><em>stride</em>
- </p>
- <blockquote>
- <p>Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
- </p></blockquote>
- </blockquote>
- <p>It isn’t clear whether negative strides are legal, either. So just as with CBLAS, passing general array views will require copies.
- </p>
- <hr>
- <a name="Extension"></a>
- <div class="header">
- <p>
- Next: <a href="#Functions" accesskey="n" rel="next">Functions</a>, Previous: <a href="#Compatibility" accesskey="p" rel="prev">Compatibility</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Extension-1"></a>
- <h3 class="section">2.10 Extension</h3>
- <a name="New-scalar-types"></a>
- <h4 class="subsection">2.10.1 New scalar types</h4>
- <p><code>ra::</code> will let you construct arrays of arbitrary types out of the box. This is the same functionality you get with e.g. <code>std::vector</code>.
- </p>
- <div class="example">
- <pre class="verbatim">struct W { int x; }
- ra::Big<W, 2> w = {{ {4}, {2} }, { {1}, {3} }};
- cout << W(1, 1).x << endl;
- cout << amin(map([](auto && x) { return w.x; }, w)) << endl;
- </pre><pre class="example">-| 3
- 1
- </pre></div>
- <p>However, if you want to mix arbitrary types in array operations, you’ll need to tell <code>ra::</code> that that is actually what you want. This is to avoid conflicts with other libraries.
- </p>
- <div class="example">
- <pre class="verbatim">namespace ra { template <> constexpr bool is_scalar_def<W> = true; }
- ...
- W ww {11};
- for_each([](auto && x, auto && y) { cout << (x.x + y.y) << " "; }, w, ww); // ok
- </pre><pre class="example">-| 15 13 12 14
- </pre></div>
- <p>but
- </p>
- <div class="example">
- <pre class="verbatim">struct U { int x; }
- U uu {11};
- for_each([](auto && x, auto && y) { cout << (x.x + y.y) << " "; }, w, uu); // error: can't find ra::start(U)
- </pre></div>
- <a name="x_002dnew_002darray_002doperations"></a><a name="New-array-operations"></a>
- <h4 class="subsection">2.10.2 New array operations</h4>
- <p><code>ra::</code> provides array extensions for standard operations such as <code>+</code>, <code>*</code>, <code>cos</code> <a href="#x_002dscalar_002dops">and so on</a>. You can add array extensions for your own operations in the obvious way, with <a href="#x_002dmap"><code>map</code></a> (but note the namespace qualifiers):
- </p>
- <div class="example">
- <pre class="verbatim">return_type my_fun(...) { };
- ...
- namespace ra {
- template <class ... A> inline auto
- my_fun(A && ... a)
- {
- return map(::my_fun, std::forward<A>(a) ...);
- }
- } // namespace ra
- </pre></div>
- <a name="index-Blitz_002b_002b-2"></a>
- <p>If you compare this with what Blitz++ had to do, modern C++ sure has made our lives easier.
- </p>
- <p>If <code>my_fun</code> is an overload set, you can use
- </p>
- <div class="example">
- <pre class="verbatim">namespace ra {
- template <class ... A> inline auto
- my_fun(A && ... a)
- {
- return map([](auto && ... a) { return ::my_fun(a ...); }, std::forward<A>(a) ...);
- }
- } // namespace ra
- </pre></div>
- <hr>
- <a name="Functions"></a>
- <div class="header">
- <p>
- Next: <a href="#Error-handling" accesskey="n" rel="next">Error handling</a>, Previous: <a href="#Extension" accesskey="p" rel="prev">Extension</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Functions-1"></a>
- <h3 class="section">2.11 Functions</h3>
- <p>You don’t need to use <a href="#Array-operations"><code>map</code></a> every time you want to do something with arrays in <code>ra::</code>. A number of array functions are already defined.
- </p>
- <a name="x_002dscalar_002dops"></a><a name="Standard-scalar-operations"></a>
- <h4 class="subsection">2.11.1 Standard scalar operations</h4>
- <p><code>ra::</code> defines array extensions for <code>+</code>, <code>-</code> (both unary and binary), <code>*</code>, <code>/</code>, <code>!</code>, <code>&&</code>, <code>||</code><a name="DOCF8" href="#FOOT8"><sup>8</sup></a>, <code>></code>, <code><</code>, <code>>=</code>, <code><=</code>, <code><=></code>, <code>==</code>, <code>!=</code>, <code>pow</code>, <code>sqr</code>, <code>abs</code>, <code>cos</code>, <code>sin</code>, <code>exp</code>, <code>expm1</code>, <code>sqrt</code>, <code>log</code>, <code>log1p</code>, <code>log10</code>, <code>isfinite</code>, <code>isnan</code>, <code>isinf</code>, <code>max</code>, <code>min</code>, <code>odd</code>, <code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code>, <code>cosh</code>, <code>sinh</code>, and <code>tanh</code>.
- Extending other scalar operations is straightforward; see <a href="#x_002dnew_002darray_002doperations">New array operations</a>. <code>ra::</code> also defines (and extends) the non-standard functions <a href="#x_002dsqr"><code>sqr</code></a>, <a href="#x_002dsqrm"><code>sqrm</code></a>, <a href="#x_002dconj"><code>conj</code></a>, <a href="#x_002drel_002derror"><code>rel_error</code></a>, and <a href="#x_002dxI"><code>xI</code></a>.
- </p>
- <p>For example:
- </p><div class="example">
- <pre class="verbatim">cout << exp(ra::Small<double, 3> {4, 5, 6}) << endl;
- </pre><pre class="example"> -| 54.5982 148.413 403.429
- </pre></div>
- <a name="Conditional-operations"></a>
- <h4 class="subsection">2.11.2 Conditional operations</h4>
- <p><a href="#x_002dmap"><code>map</code></a> evaluates all of its arguments before passing them along to its operator. This isn’t always what you want. The simplest example is <code>where(condition, iftrue, iffalse)</code>, which returns an expression that will evaluate <code>iftrue</code> when <code>condition</code> is true and <code>iffalse</code> otherwise.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double> x ...
- ra::Big<double> y = where(x>0, expensive_expr_1(x), expensive_expr_2(x));
- </pre></div>
- <p>Here <code>expensive_expr_1</code> and <code>expensive_expr_2</code> are array expressions. So the computation of the other arm would be wasted if one were to do instead
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<double> y = map([](auto && w, auto && t, auto && f) -> decltype(auto) { return w ? t : f; }
- x>0, expensive_expr_1(x), expensive_function_2(x));
- </pre></div>
- <p>If the expressions have side effects, then <code>map</code> won’t even give the right result.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 1> o = {};
- ra::Big<int, 1> e = {};
- ra::Big<int, 1> n = {1, 2, 7, 9, 12};
- ply(where(odd(n), map([&o](auto && x) { o.push_back(x); }, n), map([&e](auto && x) { e.push_back(x); }, n)));
- cout << "o: " << ra::noshape << o << ", e: " << ra::noshape << e << endl;
- </pre><pre class="example">-| o: 1 7 9, e: 2 12
- </pre></div>
- <p>FIXME Very artificial example.
- FIXME Do we want to expose ply(); this is the only example in the manual that uses it.
- </p>
- <p>When the choice is between more than two expressions, there’s <a href="#x_002dpick"><code>pick</code></a>, which operates similarly.
- </p>
- <a name="Special-operations"></a>
- <h4 class="subsection">2.11.3 Special operations</h4>
- <p>Some operations are essentially scalar operations, but require special syntax and would need a lambda wrapper to be used with <code>map</code>. <code>ra::</code> comes with a few of these already defined.
- </p>
- <p>FIXME
- </p>
- <a name="Elementwise-reductions"></a>
- <h4 class="subsection">2.11.4 Elementwise reductions</h4>
- <p><code>ra::</code> defines the whole-array one-argument reductions <code>any</code>, <code>every</code>, <code>amax</code>, <code>amin</code>, <code>sum</code>, <code>prod</code> and the two-argument reductions <code>dot</code> and <code>cdot</code>. Note that <code>max</code> and <code>min</code> are two-argument scalar operations with array extensions, while <code>amax</code> and <code>amin</code> are reductions. <code>any</code> and <code>every</code> are short-circuiting.
- </p>
- <p>You can define similar reductions in the same way that <code>ra::</code> does it:
- </p>
- <div class="example">
- <pre class="verbatim">template <class A>
- inline auto op_reduce(A && a)
- {
- T c = op_default;
- for_each([&c](auto && a) { c = op(c, a); }, a);
- return c;
- }
- </pre></div>
- <p>Often enough you need to reduce over particular axes. This is possible by combining assignment operators with the <a href="#Rank-extension">rank extension</a> mechanism, or using the <a href="#The-rank-conjunction">rank conjunction</a>, or iterating over <a href="#Cell-iteration">cells of higher rank</a>. For example:
- </p>
- <div class="example">
- <pre class="verbatim"> ra::Big<double, 2> a({m, n}, ...);
- ra::Big<double, 1> sum_rows({n}, 0.);
- iter<1>(sum_rows) += iter<1>(a);
- // for_each(ra::wrank<1, 1>([](auto & c, auto && a) { c += a; }), sum_rows, a) // alternative
- // sum_rows += transpose<1, 0>(a); // another
- ra::Big<double, 1> sum_cols({m}, 0.);
- sum_cols += a;
- </pre></div>
- <p>FIXME example with assignment op
- </p>
- <p>A few common operations of this type are already packaged in <code>ra::</code>.
- </p>
- <a name="Special-reductions"></a>
- <h4 class="subsection">2.11.5 Special reductions</h4>
- <p><code>ra::</code> defines the following special reductions.
- </p>
- <p>FIXME
- </p>
- <a name="Shortcut-reductions"></a>
- <h4 class="subsection">2.11.6 Shortcut reductions</h4>
- <p>Some reductions do not need to traverse the whole array if a certain condition is encountered early. The most obvious ones are the reductions of <code>&&</code> and <code>||</code>, which <code>ra::</code> defines as <code>every</code> and <code>any</code>.
- </p>
- <p>FIXME
- </p>
- <p>These operations are defined on top of another function <code>early</code>.
- </p>
- <p>FIXME early
- </p>
- <p>The following is often useful.
- </p>
- <p>FIXME lexicographical compare etc.
- </p>
- <a name="index-error"></a>
- <a name="index-assert"></a>
- <hr>
- <a name="Error-handling"></a>
- <div class="header">
- <p>
- Previous: <a href="#Functions" accesskey="p" rel="prev">Functions</a>, Up: <a href="#Usage" accesskey="u" rel="up">Usage</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Error-handling-1"></a>
- <h3 class="section">2.12 Error handling</h3>
- <p>Error handling in <code>ra::</code> is barebones. It is controlled by two macros:
- </p>
- <ul>
- <li> <code>RA_DO_CHECK</code>
- is a binary flag that controls runtime checks. The default is 1. The checks themselves are done with <code>RA_ASSERT</code>.
- </li><li> <code>RA_ASSERT(cond, ...)</code>
- is a function-like macro. <code>cond</code> an expression that evaluates to true (in the <code>ra::</code> namespace) if the check passes. The other arguments are informative and may or may not be used. The default defintion of <code>RA_ASSERT(cond, ...)</code> is <code>assert(cond)</code>, from <code><cassert></code>.
- </li></ul>
- <p><code>ra::</code> contains uses of <code>assert</code> for checking invariants or for sanity checks that are separate from uses of <code>RA_ASSERT</code>. Those can be disabled in the usual way with <code>-DNDEBUG</code>. The use of <code>-DNDEBUG</code> is untested.
- </p>
- <p>You can redefine <code>RA_ASSERT</code> to something that is more appropriate for your program. <code>examples/throw.cc</code> in the distribution shows how to throw an user-defined exception instead.
- </p>
- <hr>
- <a name="Extras"></a>
- <div class="header">
- <p>
- Next: <a href="#Hazards" accesskey="n" rel="next">Hazards</a>, Previous: <a href="#Usage" accesskey="p" rel="prev">Usage</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Extras-1"></a>
- <h2 class="chapter">3 Extras</h2>
- <hr>
- <a name="Hazards"></a>
- <div class="header">
- <p>
- Next: <a href="#Internals" accesskey="n" rel="next">Internals</a>, Previous: <a href="#Extras" accesskey="p" rel="prev">Extras</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Hazards-1"></a>
- <h2 class="chapter">4 Hazards</h2>
- <p>Some of these issues arise because <code>ra::</code> applies its principles systematically, which can have surprising results. Still others are the result of unfortunate compromises. And a few are just bugs.
- </p>
- <a name="Reuse-of-expression-objects"></a>
- <h3 class="section">4.1 Reuse of expression objects</h3>
- <p>Expression objects are meant to be used once. This applies to anything produced with <code>ra::map</code>, <code>ra::iter</code>, <code>ra::start</code>, <code>ra::vector</code>, or <code>ra::ptr</code>. Reuse errors are <em>not</em> checked. For example:
- </p>
- <div class="example">
- <pre class="verbatim"> ra::Big<int, 2> B({3, 3}, ra::_1 + ra::_0*3); // {{0 1 2} {3 4 5} {6 7 8}}
- std::array<int, 2> l = { 1, 2 };
- cout << B(ra::vector(l), ra::vector(l)) << endl; // ok => {{4 5} {7 8}}
- auto ll = ra::vector(l);
- cout << B(ll, ll) << endl; // ??
- </pre></div>
- <a name="Assignment-to-views"></a>
- <h3 class="section">4.2 Assignment to views</h3>
- <p>FIXME
- With dynamic-shape containers (e.g. <code>Big</code>), <code>operator=</code> replaces the left hand side instead of writing over its contents. This behavior is inconsistent with <code>View::operator=</code> and is there only so that istream >> container may work; do not rely on it.
- </p>
- <a name="View-of-const-vs-const-view"></a>
- <h3 class="section">4.3 View of const vs const view</h3>
- <p>FIXME
- Passing view arguments by reference
- </p>
- <a name="Rank-extension-in-assignments"></a>
- <h3 class="section">4.4 Rank extension in assignments</h3>
- <p>Assignment of an expression onto another expression of lower rank may not do what you expect. This example matches <code>a</code> and 3 [both of shape ()] with a vector of shape (3). This is equivalent to <code>{a=3+4; a=3+5; a=3+6;}</code>. You may get a different result depending on traversal order.
- </p>
- <div class="example">
- <pre class="verbatim">int a = 0;
- ra::scalar(a) = 3 + ra::Small<int, 3> {4, 5, 6}; // ?
- </pre><pre class="example"> ⇒ a = 9
- </pre></div>
- <p>Compare with
- </p>
- <div class="example">
- <pre class="verbatim">int a = 0;
- ra::scalar(a) += 3 + ra::Small<int, 3> {4, 5, 6}; // 0 + 3 + 4 + 5 + 6
- </pre><pre class="example"> ⇒ a = 18
- </pre></div>
- <a name="Performance-pitfalls-of-rank-extension"></a>
- <h3 class="section">4.5 Performance pitfalls of rank extension</h3>
- <p>In the following example where <code>b</code> has its shape extended from (3) to (3, 4), <code>f</code> is called 12 times, even though only 3 calls are needed if <code>f</code> doesn’t have side effects. In such cases it might be preferrable to write the outer loop explicitly, or to do some precomputation.
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 2> a = {{1, 2, 3, 4}, {5, 6, 7, 8} {9, 10, 11, 12}};
- ra::Big<int, 1> b = {1, 2, 3};
- ra::Big<int, 2> c = map(f, b) + a;
- </pre></div>
- <a name="Chained-assignment"></a>
- <h3 class="section">4.6 Chained assignment</h3>
- <p>FIXME
- When <code>a=b=c</code> works, it operates as <code>b=c; a=b;</code> and not as an array expression.
- </p>
- <a name="Unregistered-scalar-types"></a>
- <h3 class="section">4.7 Unregistered scalar types</h3>
- <p>FIXME
- <code>View<T, N> x; x = T()</code> fails if <code>T</code> isn’t registered as <code>is_scalar</code>.
- </p>
- <ol>
- <li> Item 0
- </li><li> Item 1
- </li><li> Item 2
- </li></ol>
- <hr>
- <a name="Internals"></a>
- <div class="header">
- <p>
- Next: <a href="#The-future" accesskey="n" rel="next">The future</a>, Previous: <a href="#Hazards" accesskey="p" rel="prev">Hazards</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Internals-1"></a>
- <h2 class="chapter">5 Internals</h2>
- <p><code>ra::</code> has two main components: a set of container classes, and the expression template mechanism. The container classes provide leaves for the expression template trees, and the container classes also make some use of the expression template mechanism internally (e.g. in the selection operator, or for initialization).
- </p>
- <table class="menu" border="0" cellspacing="0">
- <tr><td align="left" valign="top">• <a href="#Type-hierarchy" accesskey="1">Type hierarchy</a>:</td><td> </td><td align="left" valign="top">From <code>Containers</code> to <code>Flat</code>.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Term-agreement" accesskey="2">Term agreement</a>:</td><td> </td><td align="left" valign="top">Abstain or approve.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Loop-types" accesskey="3">Loop types</a>:</td><td> </td><td align="left" valign="top">Chosen for performance.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Introspection" accesskey="4">Introspection</a>:</td><td> </td><td align="left" valign="top">Speaking to myself.
- </td></tr>
- <tr><td align="left" valign="top">• <a href="#Compiling-and-running" accesskey="5">Compiling and running</a>:</td><td> </td><td align="left" valign="top">Practical matters.
- </td></tr>
- </table>
- <hr>
- <a name="Type-hierarchy"></a>
- <div class="header">
- <p>
- Next: <a href="#Term-agreement" accesskey="n" rel="next">Term agreement</a>, Up: <a href="#Internals" accesskey="u" rel="up">Internals</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Type-hierarchy-1"></a>
- <h3 class="section">5.1 Type hierarchy</h3>
- <p>This is a rough and possibly not very accurate summary. I’m hoping the planned feature of ‘C++ concepts’ will force me to be more systematic about it all.
- </p>
- <ul>
- <li> <b>Container</b> — <code>Big</code> <code>Shared</code> <code>Unique</code> <code>Small</code>
- <p>These are array types that own their data in one way or another. Creating or destroying these objects may allocate or deallocate memory, respectively.
- </p>
- </li><li> <b>View</b> — <code>View</code> <code>SmallView</code>
- <p>These are array views into data in memory. Access to their contents doesn’t involve computation and they may be writable. Any of the <b>Container</b> types can be treated as a <b>View</b>, but one may also create <b>View</b>s that aren’t associated with any <b>Container</b>, for example into memory allocated by a different library. Creating and destroying <b>View</b>s doesn’t allocate or deallocate memory for array elements.
- </p>
- </li><li> <b>RaIterator</b> — <code>Expr</code> <code>Pick</code> <code>cell_iterator</code> <code>cell_iterator_small</code> <code>Iota</code> <code>Vector</code> <code>Scalar</code>
- <p>This is a traversable object. <b>RaIterator</b>s are accepted by all the array functions such as <code>map</code>, <code>for_each</code>, etc. <code>map</code> produces an <b>RaIterator</b> itself, so most array expressions are <b>RaIterator</b>s. <b>RaIterator</b>s are created from <b>View</b>s and from certain foreign array-like types primarily through the function <code>start</code>. This is done automatically when those types are used in array expressions.
- </p>
- </li><li> <b>Ravelable</b> — <code>cell_iterator</code> <code>cell_iterator_small</code> <code>Iota</code> <code>Vector</code> <code>Scalar</code> <code>TensorIndex</code>
- <p>This is a kind of <b>RaIterator</b> that provides a <code>flat()</code> method to obtain a linearized view of a section of the array. Together with the methods <code>size()</code>, <code>stride()</code>, <code>keep_stride()</code> and <code>adv()</code>, a loop involving only <b>Ravelable</b>s can have its inner loop unfolded and traversed using <b>Flat</b> objects. This is faster than a multidimensional loop, especially if the inner dimensions of the loop are small.
- </p>
- </li><li> <b>Indexable</b> <code>cell_iterator</code> <code>cell_iterator_small</code> <code>Iota</code> <code>Vector</code> <code>Scalar</code> <code>TensorIndex</code>
- <p>This is a kind of <b>RaIterator</b> that provides an <code>at(i ...)</code> method for random access to any element of the array. In the current version of <code>ra::</code>, every <b>RaIterator</b> is both <b>Ravelable</b> and <b>Indexable</b>.
- </p>
- </li><li> <b>Flat</b> <code>Flat</code> <code>PickFlat</code> <code>CellFlat</code> <code>IotaFlat</code> <code>ScalarFlat</code>
- <p>These are types that support ‘forward iterator’ traversal. They have methods <code>operator+=</code> (to advance) and <code>operator*</code> (to derreference). <b>Flat</b> objects are obtained from <b>Ravelable</b> objects through a method <code>flat</code>.
- </p>
- </li></ul>
- <hr>
- <a name="Term-agreement"></a>
- <div class="header">
- <p>
- Next: <a href="#Loop-types" accesskey="n" rel="next">Loop types</a>, Previous: <a href="#Type-hierarchy" accesskey="p" rel="prev">Type hierarchy</a>, Up: <a href="#Internals" accesskey="u" rel="up">Internals</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Term-agreement-1"></a>
- <h3 class="section">5.2 Term agreement</h3>
- <p>The execution of an expression template begins with the determination of its shape — the size of each of its dimensions. This is done recursively by traversing the terms of the expression. For a given dimension <code>k</code>≥0, terms that have rank less or equal than <code>k</code> are ignored, following the prefix matching principle. Likewise terms where dimension <code>k</code> has undefined size (such as <code>TensorIndex</code> or view axes created with <code>insert</code>) are ignored. All the other terms must match.
- </p>
- <p>Then we select a traversal method depending on the types of the arguments. <code>ra::</code> has two traversal methods, both based on pointer-like iterators. <code>ply_ravel</code> is used for dynamic-size expressions and <code>plyf</code> for static-size expressions.
- </p>
- <p>Finally we select an order of traversal. <code>ra::</code> supports ‘array’ orders, meaning that the dimensions are sorted in a certain way from outermost to innermost and a full dimension is traversed before one advances on the dimension outside. However, currently (v14) there is no heuristic to choose a dimension order, so traversal always happens in row-major order (which shouldn’t be relied upon). <code>ply_ravel</code> will unroll as many innermost dimensions as it can, and in some cases traversal will be executed as a single 1D loop.
- </p>
- <hr>
- <a name="Loop-types"></a>
- <div class="header">
- <p>
- Next: <a href="#Introspection" accesskey="n" rel="next">Introspection</a>, Previous: <a href="#Term-agreement" accesskey="p" rel="prev">Term agreement</a>, Up: <a href="#Internals" accesskey="u" rel="up">Internals</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Loop-types-1"></a>
- <h3 class="section">5.3 Loop types</h3>
- <p>TODO
- </p>
- <hr>
- <a name="Introspection"></a>
- <div class="header">
- <p>
- Next: <a href="#Compiling-and-running" accesskey="n" rel="next">Compiling and running</a>, Previous: <a href="#Loop-types" accesskey="p" rel="prev">Loop types</a>, Up: <a href="#Internals" accesskey="u" rel="up">Internals</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Introspection-1"></a>
- <h3 class="section">5.4 Introspection</h3>
- <hr>
- <a name="Compiling-and-running"></a>
- <div class="header">
- <p>
- Previous: <a href="#Introspection" accesskey="p" rel="prev">Introspection</a>, Up: <a href="#Internals" accesskey="u" rel="up">Internals</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Compiling-and-running-1"></a>
- <h3 class="section">5.5 Compiling and running</h3>
- <p>The following boolean <code>#define</code>s affect the behavior of <code>ra::</code>.
- </p>
- <ul>
- <li> <code>RA_DO_CHECK</code> (default 1): Check bounds on dimension agreement (e.g. <code>Big<int, 1> {2, 3} + Big<int, 1> {1, 2, 3}</code>) and random array accesses (e.g. <code>Small<int, 2> a = 0; int i = 10; a[i] = 0;</code>).
- </li><li> <code>RA_USE_BLAS</code> (default 0): Try to use BLAS for certain rank 1 and rank 2 operations. Currently this is only used by some of the benchmarks and not by the library itself.
- </li><li> <code>RA_DO_OPT</code> (default 1): Replace certain expressions by others that are expected to perform better. This acts as a global mask on other <code>RA_DO_OPT_xxx</code> flags.
- </li><li> <code>RA_DO_OPT_IOTA</code> (default 1): Perform immediately (beat) certain operations on <code>ra::Iota</code> objects. For example, <code>ra::Iota(3, 0) + 1</code> becomes <code>ra::Iota(3, 1)</code> instead of a two-operand expression template.
- </li><li> <code>RA_DO_OPT_SMALLVECTOR</code> (default 0): Perform immediately certain operations on <code>ra::Small</code> objects, using small vector intrinsics. Currently this only works on <b>gcc</b> and doesn’t necessarily result in improved performance.
- </li></ul>
- <p><code>ra::</code> comes with three kinds of tests: examples, proper tests, and benchmarks. <code>ra::</code> uses its own crude test and benchmark suites. Run <code>CXXFLAGS=-O3 scons</code> from the top directory of the distribution to build and run them all. Alternatively, you can use <code>CXXFLAGS=-O3 cmake . && make && make test</code>.
- </p>
- <p>TODO Flags and notes about different compilers
- </p>
- <hr>
- <a name="The-future"></a>
- <div class="header">
- <p>
- Next: <a href="#Reference" accesskey="n" rel="next">Reference</a>, Previous: <a href="#Internals" accesskey="p" rel="prev">Internals</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="The-future-1"></a>
- <h2 class="chapter">6 The future</h2>
- <a name="Error-messages"></a>
- <h3 class="section">6.1 Error messages</h3>
- <p>FIXME
- </p>
- <a name="Reductions"></a>
- <h3 class="section">6.2 Reductions</h3>
- <p>FIXME
- </p>
- <a name="Etc"></a>
- <h3 class="section">6.3 Etc</h3>
- <p>FIXME
- </p>
- <hr>
- <a name="Reference"></a>
- <div class="header">
- <p>
- Next: <a href="#Sources" accesskey="n" rel="next">Sources</a>, Previous: <a href="#The-future" accesskey="p" rel="prev">The future</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Reference-1"></a>
- <h2 class="chapter">7 Reference</h2>
- <a name="x_002dmap"></a><dl>
- <dt><a name="index-map"></a>Function: <strong>map</strong> <em>op expr ...</em></dt>
- <dd><p>Create an array expression that applies <var>op</var> to <var>expr</var> ...
- </p></dd></dl>
- <p>For example:
- </p><div class="example">
- <pre class="verbatim">ra::Big<double, 1> x = map(cos, ra::Small<double, 1> {0.});
- </pre><pre class="example">⇒ x = { 1. }
- </pre></div>
- <p><var>op</var> can return a reference. A typical use is subscripting. For example (TODO better example, e.g. using STL types):
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 2> x = {{3, 3}, 0.};
- map([](auto && i, auto && j) -> int & { return x(i, j); },
- ra::Big<int, 1> {0, 1, 1, 2}, ra::Big<int, 1> {1, 0, 2, 1})
- = 1;
- </pre><pre class="example">⇒ x = {{0, 1, 0}, {1, 0, 1}, {0, 1, 0}}
- </pre></div>
- <p>Here the anonymous function can be replaced by simply <code>x</code>. Remember that unspecified return type defaults to (value) <code>auto</code>, so either a explicit type or <code>decltype(auto)</code> should be used if you want to return a reference.
- </p>
- <a name="index-for_005feach"></a>
- <a name="x_002dfor_005feach"></a><dl>
- <dt><a name="index-for_005feach-1"></a>Function: <strong>for_each</strong> <em>op expr ...</em></dt>
- <dd><p>Create an array expression that applies <var>op</var> to <var>expr</var> ..., and traverse it.
- </p></dd></dl>
- <p><var>op</var> is run for effect; whatever it returns is discarded. For example:
- </p><div class="example">
- <pre class="verbatim">double s = 0.;
- for_each([&s](auto && a) { s+=a; }, ra::Small<double, 1> {1., 2., 3})
- </pre><pre class="example">⇒ s = 6.
- </pre></div>
- <a name="index-ply"></a>
- <a name="x_002dply"></a><dl>
- <dt><a name="index-ply-1"></a>Function: <strong>ply</strong> <em>expr</em></dt>
- <dd><p>Traverse <var>expr</var>. <code>ply</code> returns <code>void</code> so <var>expr</var> should be run for effect.
- </p></dd></dl>
- <p>It is rarely necessary to use <code>ply</code>. Expressions are traversed automatically when they are assigned to views, for example, or printed out. <a href="#x_002dfor_005feach"><code>for_each</code></a><code>(...)</code> (which is actually <code>ply(map(...))</code> should cover most other uses.
- </p>
- <div class="example">
- <pre class="verbatim">double s = 0.;
- ply(map([&s](auto && a) { s+=a; }, ra::Small<double, 1> {1., 2., 3})) // same as for_each
- </pre><pre class="example">⇒ s = 6.
- </pre></div>
- <a name="index-pack"></a>
- <a name="x_002dpack"></a><dl>
- <dt><a name="index-pack-1"></a>Function: <strong>pack</strong> <em><type> expr ...</em></dt>
- <dd><p>Create an array expression that brace-constructs <var>type</var> from <var>expr</var> ...
- </p></dd></dl>
- <a name="index-cast"></a>
- <a name="x_002dcast"></a><dl>
- <dt><a name="index-cast-1"></a>Function: <strong>cast</strong> <em><type> expr</em></dt>
- <dd><p>Create an array expression that casts <var>expr</var> into <var>type</var>.
- </p></dd></dl>
- <a name="index-pick"></a>
- <a name="x_002dpick"></a><dl>
- <dt><a name="index-pick-1"></a>Function: <strong>pick</strong> <em>select_expr expr ...</em></dt>
- <dd><p>Create an array expression that selects the first of <var>expr</var> ... if <var>select_expr</var> is 0, the second if <var>select_expr</var> is 1, and so on. The expressions that are not selected are not looked up.
- </p></dd></dl>
- <p>This function cannot be defined using <a href="#x_002dmap"><code>map</code></a>, because <code>map</code> looks up each one of its argument expressions before calling <var>op</var>.
- </p>
- <p>For example:
- </p><div class="example">
- <pre class="verbatim"> ra::Small<int, 3> s {2, 1, 0};
- ra::Small<double, 3> z = pick(s, s*s, s+s, sqrt(s));
- </pre><pre class="example"> ⇒ z = {1.41421, 2, 0}
- </pre></div>
- <a name="index-where"></a>
- <a name="x_002dwhere"></a><dl>
- <dt><a name="index-where-1"></a>Function: <strong>where</strong> <em>pred_expr true_expr false_expr</em></dt>
- <dd><p>Create an array expression that selects <var>true_expr</var> if <var>pred_expr</var> is <code>true</code>, and <var>false_expr</var> if <var>pred_expr</var> is <code>false</code>. The expression that is not selected is not looked up.
- </p></dd></dl>
- <p>For example:
- </p><div class="example">
- <pre class="verbatim"> ra::Big<double, 1> s {1, -1, 3, 2};
- s = where(s>=2, 2, s); // saturate s
- </pre><pre class="example"> ⇒ s = {1, -1, 2, 2}
- </pre></div>
- <a name="index-from"></a>
- <a name="x_002dfrom"></a><dl>
- <dt><a name="index-from-1"></a>Function: <strong>from</strong> <em>op ... expr</em></dt>
- <dd><p>Create outer product expression. This is defined as <em>E = from(op, e₀, e₁ ...)</em> ⇒ <em>E(i₀₀, i₀₁ ..., i₁₀, i₁₁, ..., ...) = op[e₀(i₀₀, i₀₁, ...), e₁(i₁₀, i₁₁, ...), ...]</em>.
- </p></dd></dl>
- <p>For example:
- </p><div class="example">
- <pre class="verbatim"> ra::Big<double, 1> a {1, 2, 3};
- ra::Big<double, 1> b {10, 20, 30};
- ra::Big<double, 2> axb = from([](auto && a, auto && b) { return a*b; }, a, b)
- </pre><pre class="example"> ⇒ axb = {{10, 20, 30}, {20, 40, 60}, {30, 60, 90}}
- </pre></div>
- <div class="example">
- <pre class="verbatim"> ra::Big<int, 1> i {2, 1};
- ra::Big<int, 1> j {0, 1};
- ra::Big<double, 2> A = {{1, 2}, {3, 4}, {5, 6}};
- ra::Big<double, 2> Aij = from(A, i, j)
- </pre><pre class="example"> ⇒ Aij = {{6, 5}, {4, 3}}
- </pre></div>
- <p>The last example is more or less how <code>A(i, j)</code> is actually implemented (see <a href="#The-rank-conjunction">The rank conjunction</a>).
- </p>
- <a name="index-at"></a>
- <a name="x_002dat"></a><dl>
- <dt><a name="index-at-1"></a>Function: <strong>at</strong> <em>expr indices</em></dt>
- <dd><p>Look up <var>expr</var> at each element of <var>indices</var>, which shall be a multi-index into <var>expr</var>.
- </p></dd></dl>
- <p>This can be used for sparse subscripting. For example:
- </p><div class="example">
- <pre class="verbatim"> ra::Big<int, 2> A = {{100, 101}, {110, 111}, {120, 121}};
- ra::Big<ra::Small<int, 2>, 2> i = {{{0, 1}, {2, 0}}, {{1, 0}, {2, 1}}};
- ra::Big<int, 2> B = at(A, i);
- </pre><pre class="example"> ⇒ B = {{101, 120}, {110, 121}}
- </pre></div>
- <a name="index-shape"></a>
- <a name="x_002dshape"></a><dl>
- <dt><a name="index-shape-1"></a>Function: <strong>shape</strong> <em>a</em></dt>
- <dd><p>Get the shape of an <code>ra::</code> object.
- </p></dd></dl>
- <p>The shape of a dynamic rank array is a rank-1 object with dynamic size, and the shape of a static rank array is a rank-1 object with static size.
- </p>
- <p>This function may return an expression object or an array object. If you need to operate on the result, it might be necessary to use <code>concrete</code>.
- </p>
- <a name="index-size"></a>
- <a name="x_002dsize"></a><dl>
- <dt><a name="index-size-1"></a>Function: <strong>size</strong> <em>a</em></dt>
- <dd><p>Get the total size of an <code>ra::</code> object: the product of all its sizes.
- </p></dd></dl>
- <a name="index-concrete"></a>
- <a name="x_002dconcrete"></a><dl>
- <dt><a name="index-concrete-1"></a>Function: <strong>concrete</strong> <em>a</em></dt>
- <dd><p>Convert the argument to a container of the same rank and size as <code>a</code>.
- </p></dd></dl>
- <p>If the argument has dynamic or static shape, it is the same for the result. The main use of this function is to obtain modifiable copy of an array expression without having to prepare a container beforehand, or compute the appropiate type.
- </p>
- <a name="index-wrank"></a>
- <a name="x_002dwrank"></a><dl>
- <dt><a name="index-wrank-1"></a>Function: <strong>wrank</strong> <em><input_rank ...> op</em></dt>
- <dd><p>Wrap op using a rank conjunction (see <a href="#The-rank-conjunction">The rank conjunction</a>).
- </p></dd></dl>
- <p>For example: TODO
- </p><div class="example">
- <pre class="verbatim"></pre><pre class="example"> ⇒ x = 0
- </pre></div>
- <a name="index-transpose"></a>
- <a name="x_002dtranspose"></a><dl>
- <dt><a name="index-transpose-1"></a>Function: <strong>transpose</strong> <em><axes ...> (view) | (axes, view)</em></dt>
- <dd><p>Create a new view by transposing the axes of <var>view</var>. The number of <var>axes</var> must match the rank of <var>view</var>.
- </p></dd></dl>
- <p>For example:
- </p>
- <div class="example">
- <pre class="verbatim"> ra::Unique<double, 2> a = {{1, 2, 3}, {4, 5, 6}};
- cout << transpose<1, 0>(a) << endl;
- </pre><pre class="example"> -|
- 3 2
- 1 4
- 2 5
- 3 6
- </pre></div>
- <p>The rank of the result is <code>maxᵢ(axesᵢ)+1</code> and it may be smaller or larger than that of <var>view</var>. If an axis is repeated, the smallest of the dimensions of <var>view</var> is used. For example:
- </p>
- <div class="example">
- <pre class="verbatim"> ra::Unique<double, 2> a = {{1, 2, 3}, {4, 5, 6}};
- cout << transpose<0, 0>(a) << endl; // { a(0, 0), a(1, 1) }
- </pre><pre class="example"> -|
- 2
- 1 5
- </pre></div>
- <p>If one of the destination axes isn’t mentioned in <var>axes</var>, then is a ‘dead’ axis similar to those produced by <a href="#x_002dinsert"><code>insert</code></a>. For example:
- </p>
- <div class="example">
- <pre class="verbatim"> ra::Unique<double, 1> a = {1, 2, 3};
- cout << ((a*10) + transpose<1>(a)) << endl;
- </pre><pre class="example"> -|
- 3 3
- 11 21 31
- 12 22 32
- 13 23 33
- </pre></div>
- <p>The two argument form lets you specify the axis list dynamically. In that case the result will have dynamic rank as well. For example: </p>
- <div class="example">
- <pre class="verbatim"> ra::Small<int, 2> axes = {0, 1};
- ra::Unique<double, 2> a = {{1, 2, 3}, {4, 5, 6}};
- cout << "A: " << transpose(axes, a) << endl;
- axes = {1, 0};
- cout << "B: " << transpose(axes, a) << endl;
- </pre><pre class="example"> -|
- A: 2
- 2 3
- 1 2 3
- 4 5 6
- B: 2
- 3 2
- 1 4
- 2 5
- 3 6
- </pre></div>
- <p>This operation does not work on arbitrary array expressions yet. TODO FILL
- </p>
- <a name="index-diag"></a>
- <a name="x_002ddiag"></a><dl>
- <dt><a name="index-diag-1"></a>Function: <strong>diag</strong> <em>view</em></dt>
- <dd><p>Equivalent to <code>transpose<0, 0>(view)</code>.
- </p></dd></dl>
- <a name="index-reverse"></a>
- <a name="x_002dreverse"></a><dl>
- <dt><a name="index-reverse-1"></a>Function: <strong>reverse</strong> <em>view axis</em></dt>
- <dd><p>Create a new view by reversing axis <var>k</var> of <var>view</var>.
- </p></dd></dl>
- <p>This is equivalent to <code>view(ra::dots<k>, ra::iota(view.size(k), view.size(k)-1, -1))</code>.
- </p>
- <p>This operation does not work on arbitrary array expressions yet. TODO FILL
- </p>
- <a name="index-stencil"></a>
- <a name="x_002dstencil"></a><dl>
- <dt><a name="index-stencil-1"></a>Function: <strong>stencil</strong> <em>view lo hi</em></dt>
- <dd><p>Create a stencil on <var>view</var> with lower bounds <var>lo</var> and higher bounds <var>hi</var>.
- </p></dd></dl>
- <p><var>lo</var> and <var>hi</var> are expressions of rank 1 indicating the extent of the stencil on each dimension. Scalars are rank extended, that is, <var>lo</var>=0 is equivalent to <var>lo</var>=(0, 0, ..., 0) with length equal to the rank <code>r</code> of <var>view</var>. The stencil view has twice as many axes as <var>view</var>. The first <code>r</code> dimensions are the same as those of <var>view</var> except that they have their sizes reduced by <var>lo</var>+<var>hi</var>. The last <code>r</code> dimensions correspond to the stencil around each element of <var>view</var>; the center element is at <code>s(i0, i1, ..., lo(0), lo(1), ...)</code>.
- </p>
- <p>This operation does not work on arbitrary array expressions yet. TODO FILL
- </p>
- <a name="index-collapse"></a>
- <a name="x_002dcollapse"></a><dl>
- <dt><a name="index-collapse-1"></a>Function: <strong>collapse</strong></dt>
- <dd><p>TODO
- </p></dd></dl>
- <a name="index-explode"></a>
- <a name="x_002dexplode"></a><dl>
- <dt><a name="index-explode-1"></a>Function: <strong>explode</strong></dt>
- <dd><p>TODO
- </p></dd></dl>
- <a name="index-real_005fpart"></a>
- <a name="x_002dreal_005fpart"></a><dl>
- <dt><a name="index-real_005fpart-1"></a>Function: <strong>real_part</strong></dt>
- <dd><p>Take real part of a complex number. This can be used as reference.
- </p>
- <p>See also <a href="#x_002dimag_005fpart"><code>imag_part</code></a>.
- </p></dd></dl>
- <a name="index-imag_005fpart"></a>
- <a name="x_002dimag_005fpart"></a><dl>
- <dt><a name="index-imag_005fpart-1"></a>Function: <strong>imag_part</strong></dt>
- <dd><p>Take imaginary part of a complex number. This can be used as reference.
- </p>
- <p>For example: </p>
- <div class="example">
- <pre class="verbatim">ra::Small<std::complex<double>, 2, 2> A = {{1., 2.}, {3., 4.}};
- imag_part(A) = -2*real_part(A);
- cout << A << endl;
- </pre><pre class="example">-|
- (1, -2) (2, -4)
- (3, -6) (4, -8)
- </pre></div>
- <p>See also <a href="#x_002dreal_005fpart"><code>real_part</code></a>.
- </p></dd></dl>
- <a name="index-format_005farray"></a>
- <a name="x_002dformat_005farray"></a><dl>
- <dt><a name="index-format_005farray-1"></a>Function: <strong>format_array</strong> <em>expr [last_axis_separator [second_last_axis_separator ...]]</em></dt>
- <dd><p>Formats an array for character output.
- </p>
- <p>For example:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Small<int, 2, 2> A = {{1, 2}, {3, 4}};
- cout << "case a:\n" << A << endl;
- cout << "case b:\n" << format_array(A) << endl;
- cout << "case c:\n" << format_array(A, "|", "-") << endl;
- </pre><pre class="example">-| case a:
- 1 2
- 3 4
- case b:
- 1 2
- 3 4
- case c:
- 1|2-3|4
- </pre></div>
- </dd></dl>
- <p>The shape that might be printed before the expression itself (depending on its type) is not subject to these separators. See <a href="#x_002dnoshape"><code>noshape</code></a>, <a href="#x_002dwithshape"><code>withshape</code></a>.
- </p>
- <a name="index-noshape"></a>
- <a name="index-withshape"></a>
- <a name="x_002dnoshape"></a><a name="x_002dwithshape"></a><dl>
- <dt><a name="index-withshape-noshape"></a>Special object<!-- /@w -->: <strong>withshape noshape</strong></dt>
- <dd><p>If either of these objects is sent to <code>std::ostream</code> before an expression object, the shape of that object will or won’t be printed.
- </p></dd></dl>
- <p>If the object has static (compile time) shape, the default is not to print the shape, so <code>noshape</code> isn’t necessary, and conversely for <code>withshape</code> if the object has dynamic (runtime) shape. Note that the array readers [<code>operator>>(std::istream &, ...)</code>] expect the shape to be present or not according to the default.
- </p>
- <p>For example:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Small<int, 2, 2> A = {77, 99};
- cout << "case a:\n" << A << endl;
- cout << "case b:\n" << ra::noshape << A << endl;
- cout << "case c:\n" << ra::withshape << A << endl;
- </pre><pre class="example">-| case a:
- 77 99
- case b:
- 77 99
- case c:
- 2
- 77 99
- </pre></div>
- <p>but:
- </p>
- <div class="example">
- <pre class="verbatim">ra::Big<int> A = {77, 99};
- cout << "case a:\n" << A << endl;
- cout << "case b:\n" << ra::noshape << A << endl;
- cout << "case c:\n" << ra::withshape << A << endl;
- </pre><pre class="example">-| case a:
- 1
- 2
- 77 99
- case b:
- 77 99
- case c:
- 1
- 2
- 77 99
- </pre></div>
- <p>Note that in the last example the very shape of <code>ra::Big<int></code> has runtime size, so that size (the rank of <code>A</code>, that is 1) is printed as part of the shape of <code>A</code>.
- </p>
- <p>See also <a href="#x_002dformat_005farray"><code>format_array</code></a>.
- </p>
- <a name="index-start-1"></a>
- <a name="x_002dstart"></a><dl>
- <dt><a name="index-start-2"></a>Function: <strong>start</strong> <em>foreign_object</em></dt>
- <dd><p>Create a array expression from <var>foreign_object</var>.
- </p></dd></dl>
- <p><var>foreign_object</var> can be of type <code>std::vector</code> or <code>std::array</code>, a built-in array (<code>int[3]</code>, etc.) or an initializer list, or any object that <code>ra::</code> accepts as scalar (see <a href="#x_002dis_002dscalar"><code>here</code></a>). The resulting expresion has rank and size according to the original object. Compare this with <a href="#x_002dscalar"><code>scalar</code></a>, which will always produce an expression of rank 0.
- </p>
- <p>Generally one can mix these types with <code>ra::</code> expressions without needing <code>ra::start</code>, but sometimes this isn’t possible, for example for operators that must be class members.
- </p>
- <div class="example">
- <pre class="verbatim">std::vector<int> x = {1, 2, 3};
- ra::Big<int, 1> y = {10, 20, 30};
- cout << (x+y) << endl; // same as ra::start(x)+y
- // x += y; // error: no match for operator+=
- ra::start(x) += y; // ok
- </pre><pre class="example">-| 3
- 11 22 33
- ⇒ x = { 11, 22, 33 }
- </pre></div>
- <a name="index-ptr"></a>
- <a name="x_002dptr"></a><dl>
- <dt><a name="index-ptr-1"></a>Function: <strong>ptr</strong> <em>pointer [size]</em></dt>
- <dd><p>Create vector expression from raw <var>pointer</var>.
- </p></dd></dl>
- <p>The resulting expression has rank 1 and the size given. If <code>size</code> is not given, the expression has undefined size, and it will need to be matched with other expressions whose size <em>is</em> defined.
- </p>
- <p><code>ra::</code> doesn’t know what is actually accessible through the pointer, so be careful. For instance:
- </p>
- <div class="example">
- <pre class="verbatim">int p[] = {1, 2, 3};
- ra::Big<int, 1> v3 {1, 2, 3};
- ra::Big<int, 1> v4 {1, 2, 3, 4};
- v3 += ra::ptr(p); // ok, shape (3): v3 = {2, 4, 6}
- v4 += ra::ptr(p); // undefined, shape (4): bad access to p[3]
- // cout << (ra::ptr(p)+ra::TensorIndex<0>{}) << endl; // ct error, expression has undefined shape
- cout << (ra::ptr(p, 3)+ra::TensorIndex<0>{}) << endl; // ok, prints { 1, 3, 5 }
- cout << (ra::ptr(p, 4)+ra::TensorIndex<0>{}) << endl; // undefined, bad access at p[4]
- </pre></div>
- <p>Of course in this example one could simply have used <code>p</code> instead of <code>ra::ptr(p)</code>, since the array type retains size information.
- </p>
- <div class="example">
- <pre class="verbatim">v3 += p; // ok
- v4 += p; // error checked by ra::, shape clash (4) += (3)
- cout << (p + ra::TensorIndex<0>{}) << endl; // ok
- </pre></div>
- <a name="index-scalar"></a>
- <a name="x_002dscalar"></a><dl>
- <dt><a name="index-scalar-1"></a>Function: <strong>scalar</strong> <em>expr</em></dt>
- <dd><p>Create scalar expression from <var>expr</var>.
- </p></dd></dl>
- <p>The primary use of this function is to bring a scalar object into the <code>ra::</code> namespace. A somewhat artificial example:
- </p>
- <div class="example">
- <pre class="verbatim">struct W { int x; }
- ra::Big<W, 1> w { {1}, {2}, {3} };
- // error: no matching function for call to start(W)
- // for_each([](auto && a, auto && b) { cout << (a.x + b.x) << endl; }, w, W {7});
- // bring W into ra:: with ra::scalar
- for_each([](auto && a, auto && b) { cout << (a.x + b.x) << endl; }, w, ra::scalar(W {7}));
- </pre><pre class="example">-| 8
- 9
- 10
- </pre></div>
- <p>See also <a href="#x_002dscalar_002dchar_002dstar"><code>this example</code></a>.
- </p>
- <p>Since <code>scalar</code> produces an object with rank 0, it’s also useful when dealing with nested arrays, even for objects that are already in <code>ra::</code>. Consider:
- </p><div class="example">
- <pre class="verbatim">using Vec2 = ra::Small<double, 2>;
- Vec2 x {-1, 1};
- ra::Big<Vec2, 1> c { {1, 2}, {2, 3}, {3, 4} };
- // c += x // error: x has shape (2) and c has shape (3)
- c += ra::scalar(x); // ok: scalar(x) has shape () and matches c.
- </pre><pre class="example"> ⇒ c = { {0, 3}, {1, 4}, {2, 5} }
- </pre></div>
- <p>The result is {c(0)+x, c(1)+x, c(2)+x}. Compare this with
- </p><div class="example">
- <pre class="verbatim">c(ra::iota(2)) += x; // c(ra::iota(2)) with shape (2) matches x with shape (2)
- </pre><pre class="example"> ⇒ c = { {-1, 2}, {2, 5}, {2, 5} }
- </pre></div>
- <p>where the result is {c(0)+x(0), c(1)+x(1), c(2)}.
- </p>
- <a name="index-iter"></a>
- <a name="x_002diter"></a><dl>
- <dt><a name="index-iter-1"></a>Function: <strong>iter</strong> <em><k> (view)</em></dt>
- <dd><p>Create iterator over the <var>k</var>-cells of <var>view</var>. If <var>k</var> is negative, it is interpreted as the negative of the frame rank. In the current version of <code>ra::</code>, <var>view</var> may have dynamic or static shape.
- </p></dd></dl>
- <div class="example">
- <pre class="verbatim">ra::Big<int, 2> c {{1, 3, 2}, {7, 1, 3}};
- cout << "max of each row: " << map([](auto && a) { return amax(a); }, iter<1>(c)) << endl;
- ra::Big<int, 1> m({3}, 0);
- scalar(m) = max(scalar(m), iter<1>(c));
- cout << "max of each column: " << m << endl;
- m = 0;
- for_each([&m](auto && a) { m = max(m, a); }, iter<1>(c));
- cout << "max of each column again: " << m << endl;
- </pre><pre class="example">-| max of each row: 2
- 3 7
- max of each column: 3
- 7 3 3
- max of each column again: 3
- 7 3 3
- </pre></div>
- <p>In the following example, <code>iter</code> emulates <code>scalar</code>. Note that the shape () of <code>iter<1>(m)</code> matches the shape (3) of <code>iter<1>(c)</code>. Thus, each of the 1-cells of <code>c</code> matches against the single 1-cell of <code>m</code>.
- </p>
- <div class="example">
- <pre class="verbatim">m = 0;
- iter<1>(m) = max(iter<1>(m), iter<1>(c));
- cout << "max of each column yet again: " << m << endl;
- </pre><pre class="example">-| max of each column again: 3
- 7 3 3
- </pre></div>
- <p>The following example computes the trace of each of the items [(-1)-cells] of <code>c</code>. </p>
- <div class="example">
- <pre class="verbatim">ra::Small<int, 3, 2, 2> c = ra::_0 - ra::_1 - 2*ra::_2;
- cout << "c: " << c << endl;
- cout << "s: " << map([](auto && a) { return sum(diag(a)); }, iter<-1>(c)) << endl;
- </pre><pre class="example">-| c: 0 -2
- -1 -3
- 1 -1
- 0 -2
- 2 0
- 1 -1
- s: -3 -1 -1
- </pre></div>
- <a name="index-sum"></a>
- <a name="x_002dsum"></a><dl>
- <dt><a name="index-sum-1"></a>Function: <strong>sum</strong> <em>expr</em></dt>
- <dd><p>Return the sum (+) of the elements of <var>expr</var>, or 0 if expr is empty. This sum is performed in unspecified order.
- </p></dd></dl>
- <a name="index-prod"></a>
- <a name="x_002dprod"></a><dl>
- <dt><a name="index-prod-1"></a>Function: <strong>prod</strong> <em>expr</em></dt>
- <dd><p>Return the product (*) of the elements of <var>expr</var>, or 1 if expr is empty. This product is performed in unspecified order.
- </p></dd></dl>
- <a name="index-amax"></a>
- <a name="x_002damax"></a><dl>
- <dt><a name="index-amax-1"></a>Function: <strong>amax</strong> <em>expr</em></dt>
- <dd><p>Return the maximum of the elements of <var>expr</var>. If <var>expr</var> is empty, return <code>-std::numeric_limits<T>::infinity()</code> if the type supports it, otherwise <code>std::numeric_limits<T>::lowest()</code>, where <code>T</code> is the value type of the elements of <var>expr</var>.
- </p></dd></dl>
- <a name="index-amin"></a>
- <a name="x_002damin"></a><dl>
- <dt><a name="index-amin-1"></a>Function: <strong>amin</strong> <em>expr</em></dt>
- <dd><p>Return the minimum of the elements of <var>expr</var>. If <var>expr</var> is empty, return <code>+std::numeric_limits<T>::infinity()</code> if the type supports it, otherwise <code>std::numeric_limits<T>::max()</code>, where <code>T</code> is the value type of the elements of <var>expr</var>.
- </p></dd></dl>
- <a name="index-early"></a>
- <a name="x_002dearly"></a><dl>
- <dt><a name="index-early-1"></a>Function: <strong>early</strong> <em>expr default</em></dt>
- <dd><p><var>expr</var> shall be an array expression that returns <code>std::tuple<bool, T></code>. <var>expr</var> is traversed as by <code>for_each</code>; if the expression ever returns <code>true</code> in the first element of the tuple, traversal stops and the second element is returned. If this never happens, <var>default</var> is returned instead.
- </p></dd></dl>
- <p>The following definition of elementwise <code>lexicographical_compare</code> relies on <code>early</code>.
- </p>
- <div class="example">
- <pre class="verbatim">template <class A, class B>
- inline bool lexicographical_compare(A && a, B && b)
- {
- return early(map([](auto && a, auto && b)
- { return a==b ? std::make_tuple(false, true) : std::make_tuple(true, a<b); },
- a, b),
- false);
- }
- </pre></div>
- <a name="index-any"></a>
- <a name="x_002dany"></a><dl>
- <dt><a name="index-any-1"></a>Function: <strong>any</strong> <em>expr</em></dt>
- <dd><p>Return <code>true</code> if any element of <var>expr</var> is true, <code>false</code> otherwise. The traversal of the array expression will stop as soon as possible, but the traversal order is not specified.
- </p></dd></dl>
- <a name="index-every"></a>
- <a name="x_002devery"></a><dl>
- <dt><a name="index-every-1"></a>Function: <strong>every</strong> <em>expr</em></dt>
- <dd><p>Return <code>true</code> if every element of <var>expr</var> is true, <code>false</code> otherwise. The traversal of the array expression will stop as soon as possible, but the traversal order is not specified.
- </p></dd></dl>
- <a name="index-sqr"></a>
- <a name="x_002dsqr"></a><dl>
- <dt><a name="index-sqr-1"></a>Function: <strong>sqr</strong> <em>expr</em></dt>
- <dd><p>Compute the square of <var>expr</var>.
- </p></dd></dl>
- <a name="index-sqrm"></a>
- <a name="x_002dsqrm"></a><dl>
- <dt><a name="index-sqrm-1"></a>Function: <strong>sqrm</strong> <em>expr</em></dt>
- <dd><p>Compute the square of the norm-2 of <var>expr</var>, that is, <code>conj(expr)*expr</code>.
- </p></dd></dl>
- <a name="index-conj"></a>
- <a name="x_002dconj"></a><dl>
- <dt><a name="index-conj-1"></a>Function: <strong>conj</strong> <em>expr</em></dt>
- <dd><p>Compute the complex conjugate of <var>expr</var>.
- </p></dd></dl>
- <a name="index-xI"></a>
- <a name="x_002dxI"></a><dl>
- <dt><a name="index-xI-1"></a>Function: <strong>xI</strong> <em>expr</em></dt>
- <dd><p>Compute <code>(0+1j)</code> times <var>expr</var>.
- </p></dd></dl>
- <a name="index-rel_005ferror"></a>
- <a name="x_002drel_002derror"></a><dl>
- <dt><a name="index-rel_005ferror-1"></a>Function: <strong>rel_error</strong> <em>a b</em></dt>
- <dd><p><var>a</var> and <var>b</var> are arbitrary array expressions. Compute the error of <var>a</var> relative to <var>b</var> as
- </p>
- <p><code>(a==0. && b==0.) ? 0. : 2.*abs(a, b)/(abs(a)+abs(b))</code>
- </p>
- </dd></dl>
- <a name="index-none-1"></a>
- <a name="x_002dnone"></a><dl>
- <dt><a name="index-none-2"></a>Special object<!-- /@w -->: <strong>none</strong></dt>
- <dd><p>Pass <code>none</code> to container constructors to indicate that the contents shouldn’t be initialized. This is appropriate when the initialization you have in mind wouldn’t fit in a constructor argument. For example:
- </p>
- <div class="example">
- <pre class="verbatim">void old_style_initializer(int m, int n, double *);
- ra::Big<double> b({2, 3}, ra::none);
- old_style_initializer(2, 3, b.data());
- </pre></div>
- </dd></dl>
- <hr>
- <a name="Sources"></a>
- <div class="header">
- <p>
- Next: <a href="#Indices" accesskey="n" rel="next">Indices</a>, Previous: <a href="#Reference" accesskey="p" rel="prev">Reference</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Sources-1"></a>
- <h2 class="chapter">8 Sources</h2>
- <table>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Abr70"></a>[Abr70]</td><td width="90%">Philip S. Abrams. An APL machine. Technical report SLAC-114 UC-32 (MISC), Stanford Linear Accelerator Center, Stanford University, Stanford, CA, USA, February 1970.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Ber87"></a>[Ber87]</td><td width="90%">Robert Bernecky. An introduction to function rank. ACM SIGAPL APL Quote Quad, 18(2):39–43, December 1987.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="bli17"></a>[bli17]</td><td width="90%">The Blitz++ meta-template library. <a href="http://blitz.sourceforge.net">http://blitz.sourceforge.net</a>, November 2017.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Cha86"></a>[Cha86]</td><td width="90%">Gregory J. Chaitin. Physics in APL2, June 1986.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="FI68"></a>[FI68]</td><td width="90%">Adin D. Falkoff and Kenneth Eugene Iverson. APL\360 User’s manual. IBM Thomas J. Watson Research Center, August 1968.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="FI73"></a>[FI73]</td><td width="90%">Adin D. Falkoff and Kenneth Eugene Iverson. The design of APL. IBM Journal of Research and Development, 17(4):5–14, July 1973.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="FI78"></a>[FI78]</td><td width="90%">Adin D. Falkoff and Kenneth Eugene Iverson. The evolution of APL. ACM SIGAPL APL, 9(1):30– 44, 1978.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="J-S"></a>[J S]</td><td width="90%">J Primer. J Software, <a href="https://www.jsoftware.com/help/primer/contents.htm">https://www.jsoftware.com/help/primer/contents.htm</a>, November 2017.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Mat"></a>[Mat]</td><td width="90%">MathWorks. MATLAB documentation, <a href="https://www.mathworks.com/help/matlab/">https://www.mathworks.com/help/matlab/</a>, November 2017.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="num17"></a>[num17]</td><td width="90%">NumPy. <a href="http://www.numpy.org">http://www.numpy.org</a>, November 2017.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Ric08"></a>[Ric08]</td><td width="90%">Henry Rich. J for C programmers, February 2008.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="SSM14"></a>[SSM14]</td><td width="90%">Justin Slepak, Olin Shivers, and Panagiotis Manolios. An array-oriented language with static rank polymorphism. In Z. Shao, editor, ESOP 2014, LNCS 8410, pages 27–46, 2014.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Vel01"></a>[Vel01]</td><td width="90%">Todd Veldhuizen. Blitz++ user’s guide, February 2001.</td></tr>
- <tr><td width="10%"></td></tr>
- <tr><td width="10%"><a name="Wad90"></a>[Wad90]</td><td width="90%">Philip Wadler. Deforestation: transforming programs to eliminate trees. Theoretical Computer Science, 73(2): 231–248, June 1990. <a href="https://doi.org/10.1016/0304-3975%2890%2990147-A">https://doi.org/10.1016/0304-3975%2890%2990147-A</a></td></tr>
- </table>
- <hr>
- <a name="Indices"></a>
- <div class="header">
- <p>
- Next: <a href="#Notes" accesskey="n" rel="next">Notes</a>, Previous: <a href="#Sources" accesskey="p" rel="prev">Sources</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Indices-1"></a>
- <h2 class="unnumbered">Indices</h2>
- <table><tr><th valign="top">Jump to: </th><td><a class="summary-letter" href="#Indices_cp_letter-A"><b>A</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-B"><b>B</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-C"><b>C</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-D"><b>D</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-E"><b>E</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-F"><b>F</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-G"><b>G</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-I"><b>I</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-J"><b>J</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-N"><b>N</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-O"><b>O</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-P"><b>P</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-R"><b>R</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-S"><b>S</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-T"><b>T</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-U"><b>U</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-V"><b>V</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-W"><b>W</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-X"><b>X</b></a>
-
- </td></tr></table>
- <table class="index-cp" border="0">
- <tr><td></td><th align="left">Index Entry</th><td> </td><th align="left"> Section</th></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-A">A</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-amax"><code>amax</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-amin"><code>amin</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-any"><code>any</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-APL">APL</a>:</td><td> </td><td valign="top"><a href="#Why-C_002b_002b">Why C++</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-assert">assert</a>:</td><td> </td><td valign="top"><a href="#Functions">Functions</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-at"><code>at</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-B">B</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-BLIS">BLIS</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Blitz_002b_002b">Blitz++</a>:</td><td> </td><td valign="top"><a href="#Overview">Overview</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Blitz_002b_002b-1">Blitz++</a>:</td><td> </td><td valign="top"><a href="#Other-libraries">Other libraries</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Blitz_002b_002b-2">Blitz++</a>:</td><td> </td><td valign="top"><a href="#Extension">Extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-broadcasting_002c-singleton_002c-newaxis">broadcasting, singleton, newaxis</a>:</td><td> </td><td valign="top"><a href="#Rank-extension">Rank extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-broadcasting_002c-singleton_002c-Numpy">broadcasting, singleton, Numpy</a>:</td><td> </td><td valign="top"><a href="#Slicing">Slicing</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-built_002din-array">built-in array</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-C">C</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-cast"><code>cast</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-cell">cell</a>:</td><td> </td><td valign="top"><a href="#Rank-polymorphism">Rank polymorphism</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-collapse"><code>collapse</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-concrete"><code>concrete</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-conj"><code>conj</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-container">container</a>:</td><td> </td><td valign="top"><a href="#Using-the-library">Using the library</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-D">D</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-diag"><code>diag</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-E">E</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-early"><code>early</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-error">error</a>:</td><td> </td><td valign="top"><a href="#Functions">Functions</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-every"><code>every</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-explode"><code>explode</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-F">F</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-FFTW">FFTW</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-foreign-type">foreign type</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-format_005farray"><code>format_array</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-for_005feach"><code>for_each</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-frame">frame</a>:</td><td> </td><td valign="top"><a href="#Rank-polymorphism">Rank polymorphism</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-from"><code>from</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-G">G</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Guile">Guile</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-I">I</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-imag_005fpart"><code>imag_part</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-iter"><code>iter</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-J">J</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-J">J</a>:</td><td> </td><td valign="top"><a href="#Why-C_002b_002b">Why C++</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-N">N</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-none"><code>none</code></a>:</td><td> </td><td valign="top"><a href="#Containers-and-views">Containers and views</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-none-1"><code>none</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-noshape"><code>noshape</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Numpy">Numpy</a>:</td><td> </td><td valign="top"><a href="#Rank-extension">Rank extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Numpy-1">Numpy</a>:</td><td> </td><td valign="top"><a href="#Rank-extension">Rank extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Numpy-2">Numpy</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-O">O</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-OpenGL">OpenGL</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-order_002c-column_002dmajor">order, column-major</a>:</td><td> </td><td valign="top"><a href="#Containers-and-views">Containers and views</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-order_002c-row_002dmajor">order, row-major</a>:</td><td> </td><td valign="top"><a href="#Rank-polymorphism">Rank polymorphism</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-other-libraries_002c-interfacing-with">other libraries, interfacing with</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-P">P</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-pack"><code>pack</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-pick"><code>pick</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-ply"><code>ply</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-prod"><code>prod</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-ptr"><code>ptr</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-Python">Python</a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-R">R</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-rank_002c-dynamic">rank, dynamic</a>:</td><td> </td><td valign="top"><a href="#Slicing">Slicing</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-rank_002c-static">rank, static</a>:</td><td> </td><td valign="top"><a href="#Slicing">Slicing</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-real_005fpart"><code>real_part</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-rel_005ferror"><code>rel_error</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-reverse"><code>reverse</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-S">S</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-scalar"><code>scalar</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-shape"><code>shape</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-shape-agreement_002c-prefix">shape agreement, prefix</a>:</td><td> </td><td valign="top"><a href="#Rank-extension">Rank extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-shape-agreement_002c-suffix">shape agreement, suffix</a>:</td><td> </td><td valign="top"><a href="#Rank-extension">Rank extension</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-size"><code>size</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-sqr"><code>sqr</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-sqrm"><code>sqrm</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-start"><code>start</code></a>:</td><td> </td><td valign="top"><a href="#Compatibility">Compatibility</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-start-1"><code>start</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-stencil"><code>stencil</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-sum"><code>sum</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-T">T</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-transpose"><code>transpose</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-U">U</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-uninitialized-container">uninitialized container</a>:</td><td> </td><td valign="top"><a href="#Containers-and-views">Containers and views</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-V">V</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-view">view</a>:</td><td> </td><td valign="top"><a href="#Containers-and-views">Containers and views</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-view_002c-rank-0">view, rank 0</a>:</td><td> </td><td valign="top"><a href="#Slicing">Slicing</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-W">W</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-where"><code>where</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-withshape"><code>withshape</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td></td><td valign="top"><a href="#index-wrank"><code>wrank</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- <tr><th><a name="Indices_cp_letter-X">X</a></th><td></td><td></td></tr>
- <tr><td></td><td valign="top"><a href="#index-xI"><code>xI</code></a>:</td><td> </td><td valign="top"><a href="#Reference">Reference</a></td></tr>
- <tr><td colspan="4"> <hr></td></tr>
- </table>
- <table><tr><th valign="top">Jump to: </th><td><a class="summary-letter" href="#Indices_cp_letter-A"><b>A</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-B"><b>B</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-C"><b>C</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-D"><b>D</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-E"><b>E</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-F"><b>F</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-G"><b>G</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-I"><b>I</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-J"><b>J</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-N"><b>N</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-O"><b>O</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-P"><b>P</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-R"><b>R</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-S"><b>S</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-T"><b>T</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-U"><b>U</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-V"><b>V</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-W"><b>W</b></a>
-
- <a class="summary-letter" href="#Indices_cp_letter-X"><b>X</b></a>
-
- </td></tr></table>
- <hr>
- <a name="Notes"></a>
- <div class="header">
- <p>
- Previous: <a href="#Indices" accesskey="p" rel="prev">Indices</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> [<a href="#Indices" title="Index" rel="index">Index</a>]</p>
- </div>
- <a name="Notes-1"></a>
- <h2 class="unnumbered">Notes</h2>
- <ol>
- <li> <code>ra::</code> uses the following features that are not standard (but that all major compilers support): <code>#pragma once</code>, and <code>__COUNTER__</code>.
- </li></ol>
- <div class="footnote">
- <hr>
- <h4 class="footnotes-heading">Footnotes</h4>
- <h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
- <p>/ə’ɹ-eɪ/, I guess.</p>
- <h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
- <p>Cf. <a href="https://en.wikipedia.org/wiki/Dope_vector"><em>dope vector</em></a></p>
- <h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
- <p>Examples given without context assume that one has declared <code>using std::cout;</code>, etc.</p>
- <h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
- <p>The brace-list constructors of rank 2 and higher aren’t supported on types of runtime rank, because in the C++ grammar, a nested initializer list doesn’t always define a rank unambiguously.</p>
- <h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
- <p>You can still use pointers or <code>std::initializer_list</code>s for shape by wrapping them in the functions <code>ptr</code> or <code>vector</code>, respectively.</p>
- <h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>
- <p>The brace-list constructors aren’t rank extending, because giving the ravel is incompatible with rank extension. They are size-strict —you must give every element.</p>
- <h3><a name="FOOT7" href="#DOCF7">(7)</a></h3>
- <p>Prefix agreement is chosen for <code>ra::</code> because of the availability of a <a href="#The-rank-conjunction">rank conjunction</a> [<a href="#Sources">Ber87</a>]
- and <a href="#Cell-iteration">cell iterators of arbitrary rank</a>. This allows rank extension to be performed at multiple axes of an array expression.</p>
- <h3><a name="FOOT8" href="#DOCF8">(8)</a></h3>
- <p><code>&&</code>, <code>||</code> are short-circuiting as array operations; the elements of the second operand won’t be evaluated if the elements of the first one evaluate to <code>false</code> or <code>true</code>, respectively.
- Note that if both operands are of rank 0 and at least one of them is an <code>ra::</code> object, they is no way to preserve the behavior of <code>&&</code> and <code>||</code> with built in types and avoid evaluating both, since the overloaded operators <a href="http://en.cppreference.com/w/cpp/language/operators">are normal functions</a>.</p>
- </div>
- <hr>
- </body>
- </html>
|