File: math-array.scrbl

package info (click to toggle)
racket 7.2%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 125,432 kB
  • sloc: ansic: 258,980; pascal: 59,975; sh: 33,650; asm: 13,558; lisp: 7,124; makefile: 3,329; cpp: 2,889; exp: 499; python: 274; xml: 11
file content (2054 lines) | stat: -rw-r--r-- 96,093 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
#lang scribble/manual

@(require scribble/eval
          racket/sandbox
          (for-label racket/base racket/vector racket/match racket/unsafe/ops racket/string
                     (except-in racket/list permutations) ; FIXME
                     math plot
                     (only-in typed/racket/base
                              ann inst : λ: define: make-predicate ->
                              Flonum Real Boolean Any Integer Index Natural Exact-Positive-Integer
                              Nonnegative-Real Sequenceof Fixnum Values Number Float-Complex
                              All U List Vector Listof Vectorof Struct FlVector
                              Symbol Output-Port))
          "utils.rkt")

@(define typed-eval (make-math-eval))
@interaction-eval[#:eval typed-eval
                         (require racket/match
                                  racket/vector
                                  racket/string
                                  racket/sequence
                                  racket/list)]

@title[#:tag "array" #:style 'toc]{Arrays}
@(author-neil)

@bold{Performance Warning:} Indexing the elements of arrays created in untyped Racket
is currently 25-50 times slower than doing the same in Typed Racket, due to the overhead
of checking higher-order contracts. We are working on it.

For now, if you need speed, use the @racketmodname[typed/racket] language.

@defmodule[math/array]

One of the most common ways to structure data is with an array: a rectangular grid of
homogeneous, independent elements. But an array data type
is usually absent from functional languages' libraries. This is probably because arrays
are perceived as requiring users to operate on them using destructive updates, write
loops that micromanage array elements, and in general, stray far from the declarative
ideal.

Normally, they do. However, experience in Python, and more recently Data-Parallel Haskell,
has shown that providing the right data types and a rich collection of whole-array operations
allows working effectively with arrays in a functional, declarative style. As a bonus,
doing so opens the possibility of parallelizing nearly every operation.

@local-table-of-contents[]


@;{==================================================================================================}


@section[#:tag "array:quick"]{Quick Start}

Arrays can be created from expressions denoting each element's value using the @racket[array]
macro:
@interaction[#:eval typed-eval
                    (array #[0 1 2 3 4])
                    (array #[#['first 'row 'data] #['second 'row 'data]])
                    (array "This array has zero axes and one element")]
They can also be created using @racket[build-array] to specify a @tech{shape} and @tech{procedure}:
@interaction[#:eval typed-eval
                    (define arr
                      (build-array #(4 5) (λ: ([js : Indexes])
                                            (match-define (vector j0 j1) js)
                                            (+ j0 j1))))
                    arr]
Other ways to create arrays are to convert them from lists and vectors using
@racket[list->array], @racket[list*->array], @racket[vector->array] and @racket[vector*->array],
and to generate them in a loop using @racket[for/array:] and @racket[for*/array:].

Arrays can be indexed using @racket[array-ref], and settable arrays can be mutated using
@racket[array-set!]:
@interaction[#:eval typed-eval
                    (array-ref arr #(2 3))
                    (define brr (array->mutable-array arr))
                    (array-set! brr #(2 3) -1000)
                    brr]
However, both of these activities are discouraged in favor of functional, whole-array operations.

Arrays can be mapped over and otherwise operated on @tech{pointwise}:
@interaction[#:eval typed-eval
                    (array-map (λ: ([n : Natural]) (* 2 n)) arr)
                    (array+ arr arr)]
When arrays have different shapes, they can often be @tech{broadcast}, or stretched, to be the same
shape before applying the pointwise operation:
@interaction[#:eval typed-eval
                    (array* arr (array 2))
                    (array* arr (array #[0 2 0 2 0]))]
By default, zero-dimensional arrays like @racket[(array 2)] can be broadcast to any shape.
See @secref{array:broadcasting} for details.

Arrays can be @tech[#:key "slicing"]{sliced} to yield sub-arrays, using a list of slice specifications
that correspond to array axes.
For example, keeping every row of @racket[arr] and every even-numbered column:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (:: 0 5 2)))]
Here, @racket[::] has semantics almost, but not quite, entirely unlike @racket[in-range].
See @secref{array:slicing} for details.

Functional code that uses whole-array operations often creates many short-lived, intermediate arrays
whose elements are referred to only once.
The overhead of allocating and filling storage for these arrays can be removed entirely by using
@tech{nonstrict} arrays, sometimes at the cost of making the code's performance more difficult to
reason about.
Another bonus is that computations with nonstrict arrays have fewer synchronization points, meaning
that they will be easier to parallelize as Racket's support for parallel computation improves.
See @secref{array:nonstrict} for details.


@;{==================================================================================================}


@section[#:tag "array:defs"]{Definitions}

An array's domain is determined by its @deftech{shape}, a vector of nonnegative integers such as
@racket[#(4 5)], @racket[#(10 1 5 8)] or @racket[#()].
The shape's length is the number of array dimensions, or @deftech{axes}.
The shape's contents are the length of each axis.

The product of the axis lengths is the array's size. In particular, an array with shape
@racket[#()] has one element.

@deftech{Indexes} are a vector of nonnegative integers that identify a particular element.
Indexes are in-bounds when there are the same number of them as axes, and each is
@italic{less than} its corresponding axis length.

An array's contents are determined by its @deftech{procedure}, which returns an element when applied
to in-bounds @tech{indexes}.
By default, most arrays' procedures look up elements in memory.
Others, such as those returned by @racket[make-array], return computed values.

A @deftech{pointwise} operation is one that operates on each array element independently, on each
corresponding pair of elements from two arrays independently, or on a corresponding collection
of elements from many arrays independently. This is usually done using @racket[array-map].

When a pointwise operation is performed on arrays with different shapes, the arrays are
@deftech{broadcast} so that their shapes match. See @secref{array:broadcasting} for details.


@;{==================================================================================================}


@section[#:tag "array:broadcasting"]{Broadcasting}

It is often useful to apply a @tech{pointwise} operation to two or more arrays in a many-to-one
manner. Library support for this, which @racketmodname[math/array] provides, is called
@tech[#:key "broadcast"]{broadcasting}.

Creating a 6×6 identity matrix:
@interaction[#:eval typed-eval
                    (define diag (diagonal-array 2 6 1 0))
                    (array-shape diag)
                    diag]
Multiplying each element by @racket[10]:
@interaction[#:eval typed-eval
                    (array-shape (array 10))
                    (array* diag (array 10))]
Adding @racket[(array #[0 1 2 3 4 5])] pointwise to every row:
@interaction[#:eval typed-eval
                    (array+ (array* diag (array 10))
                            (array #[0 1 2 3 4 5]))]

@subsection[#:tag "array:broadcasting:rules"]{Broadcasting Rules}

Suppose we have two array shapes @racket[ds = (vector d0 d1 ...)] and
@racket[es = (vector e0 e1 ...)]. Broadcasting proceeds as follows:
@itemlist[#:style 'ordered
  @item{The shorter shape is padded on the left with @racket[1] until it is the same length
        as the longer shape.}
  @item{For each axis @racket[k], @racket[dk] and @racket[ek] are compared. If @racket[dk = ek],
        the result axis is @racket[dk]; if one axis is length @racket[1], the result axis
        is the length of the other; otherwise fail.}
  @item{Both arrays' axes are stretched by (conceptually) copying the rows of axes with length
        @racket[1].}
  ]

Example: Suppose we have an array @racket[drr] with shape @racket[ds = #(4 1 3)] and another array
@racket[err] with shape @racket[es = #(3 3)]. Following the rules:
@itemlist[#:style 'ordered
  @item{@racket[es] is padded to get @racket[#(1 3 3)].}
  @item{The result axis is derived from @racket[#(4 1 3)] and @racket[#(1 3 3)] to get
        @racket[#(4 3 3)].}
  @item{@racket[drr]'s second axis is stretched to length @racket[3], and @racket[err]'s new first
        axis (which is length @racket[1] by rule 1) is stretched to length @racket[4].}
  ]

The same example, but more concrete:
@interaction[#:eval typed-eval
                    (define drr
                      (array #[#[#["00" "01" "02"]]
                               #[#["10" "11" "12"]]
                               #[#["20" "21" "22"]]
                               #[#["30" "31" "32"]]]))
                    (array-shape drr)
                    (define err
                      (array #[#["aa" "ab" "ac"]
                               #["ba" "bb" "bc"]
                               #["ca" "cb" "cc"]]))
                    (array-shape err)
                    (define drr+err (array-map string-append drr err))
                    (array-shape drr+err)
                    drr+err]
Notice how the row @racket[#["00" "01" "02"]] in @racket[drr] is repeated in the result
because @racket[drr]'s second axis was stretched during broadcasting. Also, the column
@racket[#[#["aa"] #["ba"] #["ca"]]] in @racket[err] is repeated because @racket[err]'s first
axis was stretched.

For the above example, @racket[array-map] does this before operating on @racket[drr] and @racket[err]:
@interaction[#:eval typed-eval
                    (define ds (array-shape-broadcast (list (array-shape drr)
                                                            (array-shape err))))
                    ds
                    (array-broadcast drr ds)
                    (array-broadcast err ds)]

@subsection[#:tag "array:broadcasting:control"]{Broadcasting Control}

The parameter @racket[array-broadcasting] controls how pointwise operations @tech{broadcast}
arrays. Its default value is @racket[#t], which means that broadcasting proceeds as described
in @secref{array:broadcasting:rules}. Another possible value is @racket[#f], which allows pointwise
operations to succeed only if array shapes match exactly:
@interaction[#:eval typed-eval
                    (parameterize ([array-broadcasting #f])
                      (array* (index-array #(3 3)) (array 10)))]

Another option is @hyperlink["http://www.r-project.org"]{R}-style permissive broadcasting,
which allows pointwise operations to @italic{always} succeed, by repeating shorter axes' rows
instead of repeating just singleton axes' rows:
@interaction[#:eval typed-eval
                    (define arr10 (array-map number->string (index-array #(10))))
                    (define arr3 (array-map number->string (index-array #(3))))
                    arr10
                    arr3
                    (array-map string-append arr10 (array #["+" "-"]) arr3)
                    (parameterize ([array-broadcasting 'permissive])
                      (array-map string-append arr10 (array #["+" "-"]) arr3))]
Notice that @racket[(array #["+" "-"])] was repeated five times, and that
@racket[arr3] was repeated three full times and once partially.


@;{==================================================================================================}


@section[#:tag "array:slicing"]{Slicing}

One common array transformation is @deftech{slicing}: extracting sub-arrays by picking rows from
each axis independently.

Slicing is done by applying @racket[array-slice-ref] or @racket[array-slice-set!] to an array and a
list of @deftech{slice specifications} corresponding to array @tech{axes}.
There are five types of slice specification:
@itemlist[@item{@racket[(Sequenceof Integer)]: pick rows from an axis by index.}
          @item{@racket[Slice]: pick rows from an axis as with an @racket[in-range] sequence.}
          @item{@racket[Slice-Dots]: preserve remaining adjacent axes}
          @item{@racket[Integer]: remove an axis by replacing it with one of its rows.}
          @item{@racket[Slice-New-Axis]: insert an axis of a given length.}]

Create @racket[Slice] objects using @racket[::] and @racket[Slice-New-Axis] objects using
@racket[::new]. There is only one @racket[Slice-Dots] object, namely @racket[::...].

When slicing an array with @racket[n] axes, unless a list of slice specifications contains
@racket[::...], it must contain exactly @racket[n] slice specifications.

The remainder of this section uses the following example array:
@interaction[#:eval typed-eval
                    (define arr
                      (build-array
                       #(2 3 4)
                       (λ: ([js : Indexes])
                         (string-append* (map number->string (vector->list js))))))
                    arr]

@subsection{@racket[(Sequenceof Integer)]: pick rows}

Using a sequence of integers as a slice specification picks rows from the corresponding axis. For
example, we might use lists of integers to pick @italic{every} row from every axis:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(0 1) '(0 1 2) '(0 1 2 3)))]
This simply copies the array.

More usefully, we can use sequences to swap rows on the same axis:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(1 0) '(0 1 2) '(0 1 2 3)))]
We can also remove rows:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(0 1) '(0 2) '(0 2)))
                    (array-slice-ref arr (list '(0 1) '(0 1 2) '()))]
Or duplicate rows:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(0 1) '(0 1 2) '(0 0 1 2 2 3)))]
However, a sequence slice specification cannot alter the number of axes.

Using sequence constructors like @racket[in-range], we can pick every even-indexed row in an axis:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(1 0) '(0 1 2) (in-range 0 4 2)))]
We could also use @racket[in-range] to pick every row instead of enumerating their indexes in a
list, but that would require another kind of tedium:
@interaction[#:eval typed-eval
                    (define ds (array-shape arr))
                    (array-slice-ref arr (list (in-range (vector-ref ds 0))
                                               (in-range (vector-ref ds 1))
                                               (in-range (vector-ref ds 2))))]
The situation calls for an @racket[in-range]-like slice specification that is aware of the lengths
of the axes it is applied to.

@subsection{@racket[Slice]: pick rows in a length-aware way}

As a slice specification, a @racket[Slice] object acts like the sequence object returned
by @racket[in-range], but either @racket[start] or @racket[end] may be @racket[#f].

If @racket[start] is @racket[#f], it is interpreted as the first valid axis index in the direction
of @racket[step]. If @racket[end] is @racket[#f], it is interpreted as the last valid axis index
in the direction of @racket[step].

Possibly the most common slice is @racket[(::)], equivalent to @racket[(:: #f #f 1)]. With a
positive @racket[step = 1], @racket[start] is interpreted as @racket[0] and @racket[end] as
the length of the axis. Thus, @racket[(::)] picks all rows from any axis:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (::) (::)))]
The slice @racket[(:: #f #f -1)] reverses an axis:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (::) (:: #f #f -1)))]
The slice @racket[(:: 2 #f 1)] picks every row starting from index @racket[2]:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (::) (:: 2 #f 1)))]
The slice @racket[(:: 1 #f 2)] picks every odd-indexed row:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (::) (:: 1 #f 2)))]
Notice that every example starts with two @racket[(::)]. In fact, slicing only one axis is so
common that there is a slice specification object that represents any number of @racket[(::)].

@subsection{@racket[Slice-Dots]: preserve remaining axes}

As a slice specification, a @racket[Slice-Dots] object represents any number of leftover, adjacent
axes, and preserves them all.

For example, picking every odd-indexed row of the last axis can be done by
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list ::... (:: 1 #f 2)))]
For @racket[arr] specifically, @racket[::...] represents two @racket[(::)].

Slicing only the first axis while preserving the rest can be done by
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list '(0) ::...))]
If more than one @racket[::...] appears in the list, only the first is expanded:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list ::... '(1) ::...))
                    (array-slice-ref arr (list ::... '(1)))]
If there are no leftover axes, @racket[::...] does nothing when placed in any position:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list ::... '(1) '(1) '(1)))
                    (array-slice-ref arr (list '(1) ::... '(1) '(1)))
                    (array-slice-ref arr (list '(1) '(1) ::... '(1)))
                    (array-slice-ref arr (list '(1) '(1) '(1) ::...))]

@subsection{@racket[Integer]: remove an axis}

All of the slice specifications so far preserve the dimensions of the array. Removing an axis
can be done by using an integer as a slice specification.

This example removes the first axis by collapsing it to its first row:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list 0 ::...))]
Removing the second axis by collapsing it to the row with index @racket[1]:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) 1 ::...))]
Removing the second-to-last axis (which for @racket[arr] is the same as the second):
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list ::... 1 (::)))]
All of these examples can be done using @racket[array-axis-ref]. However, removing an axis
relative to the dimension of the array (e.g. the second-to-last axis) is easier to do
using @racket[array-slice-ref], and it is sometimes convenient to combine axis removal with
other slice operations.

@subsection{@racket[Slice-New-Axis]: add an axis}

As a slice specification, @racket[(::new dk)] inserts @racket[dk] into the resulting array's
shape, in the corresponding axis position. The new axis has length @racket[dk], which must be
nonnegative.

For example, we might conceptually wrap another @racket[#[]] around an array's data:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::new) ::...))]
Or duplicate the array twice, within two new outer rows:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::new 2) ::...))]
Of course, @racket[dk = 0] is a valid new axis length, but is usually not very useful:
@interaction[#:eval typed-eval
                    (array-slice-ref arr (list (::) (::new 0) ::...))]
Inserting axes can also be done using @racket[array-axis-insert].


@;{==================================================================================================}


@section[#:tag "array:nonstrict"]{Nonstrict Arrays}

With few exceptions, by default, the functions exported by @racketmodname[math/array] return
@deftech{strict} arrays, which are arrays whose @tech{procedures} compute elements by looking them
up in a vector.

This conservative default often wastes time and space. In functional code that operates on arrays,
the elements in most intermediate arrays are referred to exactly once, so allocating and filling
storage for them should be unnecessary. For example, consider the following array:
@interaction[#:eval typed-eval
                    (define (make-hellos)
                      (array-map string-append
                                 (array-map string-append
                                            (array #["Hello " "Hallo " "Jó napot "])
                                            (array #["Ada" "Edsger" "John"]))
                                 (make-array #(3) "!")))
                    (define arr (make-hellos))
                    (array-strict? arr)
                    arr]
By default, the result of the inner @racket[array-map] has storage allocated for it and filled with
strings such as @racket["Hello Ada"], even though its storage will be thrown away at the next garbage
collection cycle.

An additional concern becomes even more important as Racket's support for parallel computation
improves. Allocating storage for intermediate arrays is a synchronization point in long computations,
which divides them into many short computations, making them difficult to parallelize.

@(define array-pdf
   "http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/RArrays.pdf")

@margin-note*{* @bold{Regular, shape-polymorphic, parallel arrays in Haskell},
               Gabriele Keller, Manuel Chakravarty, Roman Leshchinskiy, Simon Peyton Jones,
               and Ben Lippmeier. ICFP 2010. @hyperlink[array-pdf]{(PDF)}}

A solution is to construct @deftech{nonstrict} arrays*, which are arrays whose procedures can do more
than simply look up elements. Setting the parameter @racket[array-strictness] to @racket[#f] causes
almost all @racketmodname[math/array] functions to return nonstrict arrays:
@interaction[#:eval typed-eval
                    (define arr (parameterize ([array-strictness #f])
                                  (make-hellos)))
                    (array-strict? arr)
                    arr]
In @racket[arr], the first element is the @italic{computation}
@racket[(string-append (string-append "Hello " "Ada") "!")], not the value @racket["Hello Ada!"].
The value @racket["Hello Ada!"] is recomputed every time the first element is referred to.

To use nonstrict arrays effectively, think of every array as if it were the array's
@tech{procedure} itself. In other words,

@nested[#:style 'inset]{@bold{An @italic{array} is just a function with a finite,
                                 rectangular domain.}}

Some arrays are mutable, some are lazy, some are strict, some are sparse, and most
do not even allocate contiguous space to store their elements. All are functions that can be
applied to indexes to retrieve elements.

The two most common kinds of operations, mapping over and transforming arrays, are compositions.
Mapping @racket[f] over array @racket[arr] is nothing more than composing @racket[f] with
@racket[arr]'s procedure.
Transforming @racket[arr] using @racket[g], a function from new indexes to old indexes, is nothing
more than composing @racket[arr]'s procedure with @racket[g].

@subsection{Caching Nonstrict Elements}

@bold{Nonstrict arrays are not lazy.} Very few nonstrict arrays cache computed elements,
but like functions, recompute them every time they are referred to. Unlike functions, they can have
every element computed and cached at once, by making them @tech{strict}.

To compute and store an array's elements, use @racket[array-strict!] or @racket[array-strict]:
@interaction[#:eval typed-eval
                    (array-strict? arr)
                    (array-strict! arr)
                    (array-strict? arr)
                    (array-strict arr)]
If the array is already strict, as in the last example above, @racket[array-strict!] and
@racket[array-strict] do nothing.

To make a strict @italic{copy} of an array without making the original array strict, use
@racket[array->mutable-array].

@subsection{Performance Considerations}

One downside to nonstrict arrays is that it is more difficult to reason about the performance of
operations on them. Another is that the user must decide which arrays to make strict. Fortunately,
there is a simple rule of thumb:

@nested[#:style 'inset]{@bold{Make arrays strict when you must refer to most of their elements
                              more than once or twice.}}

Having to name an array is a good indicator that it should be strict. In the
following example, which computes @racket[(+ (expt x x) (expt x x))] for @racket[x] from @racket[0]
to @racket[2499], each element in @racket[xrr] is computed twice whenever its corresponding element
in @racket[res] is referred to:
@racketblock[(define xrr (array-map expt
                                    (index-array #(50 50))
                                    (index-array #(50 50))))
             (define res (array+ xrr xrr))]
Having to name @racket[xrr] means we should make it strict:
@racketblock[(define xrr (array-strict
                          (array-map expt
                                     (index-array #(50 50))
                                     (index-array #(50 50)))))
             (define res (array+ xrr xrr))]
Doing so halves the time it takes to compute @racket[res]'s elements.

When returning an array from a function, return nonstrict arrays as they are, to allow the caller to
decide whether the result should be strict.

When writing library functions that may be called with either @racket[(array-strictness #t)] or
@racket[(array-strictness #f)], operate on nonstrict arrays and wrap the result with
@racket[array-default-strict] to return what the user is expecting.
For example, if @racket[make-hellos] is a library function, it should be written as
@racketblock[(define (make-hellos)
               (array-default-strict
                (parameterize ([array-strictness #f])
                  (array-map string-append
                             (array-map string-append
                                        (array #["Hello " "Hallo " "Jó napot "])
                                        (array #["Ada" "Edsger" "John"]))
                             (make-array #(3) "!")))))]

If you cannot determine whether to make arrays strict, or are using arrays for so-called
``dynamic programming,'' you can make them lazy using @racket[array-lazy].


@;{==================================================================================================}


@section[#:tag "array:types"]{Types, Predicates and Accessors}

@defform[(Array A)]{
The parent array type. Its type parameter is the type of the array's elements.

The polymorphic @racket[Array] type is @italic{covariant}, meaning that @racket[(Array A)] is a
subtype of @racket[(Array B)] if @racket[A] is a subtype of @racket[B]:
@interaction[#:eval typed-eval
                    (define arr (array #[1 2 3 4 5]))
                    arr
                    (ann arr (Array Real))
                    (ann arr (Array Any))]
Because subtyping is transitive, the @racket[(Array A)] in the preceeding subtyping rule can be
replaced with any of @racket[(Array A)]'s subtypes, including descendant types of @racket[Array].
For example, @racket[(Mutable-Array A)] is a subtype of @racket[(Array B)] if @racket[A] is a
subtype of @racket[B]:
@interaction[#:eval typed-eval
                    (define arr (mutable-array #[1 2 3 4 5]))
                    arr
                    (ann arr (Array Real))
                    (ann arr (Array Any))]
}

@defform[(Settable-Array A)]{
The parent type of arrays whose elements can be mutated. Functions like @racket[array-set!] and
@racket[array-slice-set!] accept arguments of this type. Examples of subtypes are
@racket[Mutable-Array], @racket[FlArray] and @racket[FCArray].

This type is @italic{invariant}, meaning that @racket[(Settable-Array A)] is @bold{not} a subtype
of @racket[(Settable-Array B)] if @racket[A] and @racket[B] are different types, even if @racket[A]
is a subtype of @racket[B]:
@interaction[#:eval typed-eval
                    (define arr (mutable-array #[1 2 3 4 5]))
                    arr
                    (ann arr (Settable-Array Integer))
                    (ann arr (Settable-Array Real))]
}

@defform[(Mutable-Array A)]{
The type of mutable arrays. Its type parameter is the type of the array's elements.

Arrays of this type store their elements in a @racket[(Vectorof A)]:
@interaction[#:eval typed-eval
                    (define arr (mutable-array #[#[1 2] #[3 4]]))
                    (vector-set! (mutable-array-data arr) 0 -10)
                    arr]
Mutable arrays are always @tech{strict}.
}

@defidform[Indexes]{
The type of array shapes and array indexes @italic{produced} by @racketmodname[math/array] functions.
Defined as @racket[(Vectorof Index)].
@examples[#:eval typed-eval
                 (array-shape (array #[#[#[0]]]))]
}

@defidform[In-Indexes]{
The type of array shapes and array indexes @italic{accepted} by @racketmodname[math/array] functions.
Defined as @racket[(U Indexes (Vectorof Integer))].

@examples[#:eval typed-eval
                 (define ds #(3 2))
                 ds
                 (make-array ds (void))]

This makes indexes-accepting functions easier to use, because it is easier to convince Typed
Racket that a vector contains @racket[Integer] elements than that a vector contains @racket[Index]
elements.

@racket[In-Indexes] is not defined as @racket[(Vectorof Integer)] because mutable container types
like @racket[Vector] and @racket[Vectorof] are invariant.
In particular, @racket[(Vectorof Index)] is not a subtype of @racket[(Vectorof Integer)]:
@interaction[#:eval typed-eval
                    (define js ((inst vector Index) 3 4 5))
                    js
                    (ann js (Vectorof Integer))
                    (ann js In-Indexes)]
}

@deftogether[(@defproc[(array? [v Any]) Boolean]
              @defproc[(settable-array? [v Any]) Boolean]
              @defproc[(mutable-array? [v Any]) Boolean])]{
Predicates for the types @racket[Array], @racket[Settable-Array], and @racket[Mutable-Array].

Because @racket[Settable-Array] and its descendants are invariant, @racket[settable-array?] and
its descendants' predicates are generally not useful in occurrence typing. For example, if
we know we have an @racket[Array] but would like to treat it differently if it happens to be 
a @racket[Mutable-Array], we are basically out of luck:
@interaction[#:eval typed-eval
                    (: maybe-array-data (All (A) ((Array A) -> (U #f (Vectorof A)))))
                    (define (maybe-array-data arr)
                      (cond [(mutable-array? arr)  (mutable-array-data arr)]
                            [else  #f]))]
In general, predicates with a @racket[Struct] filter do not give conditional branches access
to a struct's accessors. Because @racket[Settable-Array] and its descendants are invariant,
their predicates have @racket[Struct] filters:
@interaction[#:eval typed-eval
                    array?
                    settable-array?
                    mutable-array?]
}

@defproc[(array-shape [arr (Array A)]) Indexes]{
Returns @racket[arr]'s @tech{shape}, a vector of indexes that contains the lengths
of @racket[arr]'s axes.
@examples[#:eval typed-eval
                 (array-shape (array 0))
                 (array-shape (array #[0 1]))
                 (array-shape (array #[#[0 1]]))
                 (array-shape (array #[]))]
}

@defproc[(array-size [arr (Array A)]) Index]{
Returns the number of elements in @racket[arr], which is the product of its axis lengths.
@examples[#:eval typed-eval
                 (array-size (array 0))
                 (array-size (array #[0 1]))
                 (array-size (array #[#[0 1]]))
                 (array-size (array #[]))]
}

@defproc[(array-dims [arr (Array A)]) Index]{
Returns the number of @racket[arr]'s dimensions. Equivalent to
@racket[(vector-length (array-shape arr))].
}

@defproc[(mutable-array-data [arr (Mutable-Array A)]) (Vectorof A)]{
Returns the vector of data that @racket[arr] contains.
}


@;{==================================================================================================}


@section[#:tag "array:construct"]{Construction}

@defform/subs[(array #[#[...] ...] maybe-type-ann)
              [(maybe-type-ann (code:line) (code:line : type))]]{
Creates an @racket[Array] from nested rows of expressions.

The vector syntax @racket[#[...]] delimits rows. These may be nested to any depth, and must have a
rectangular shape. Using square parentheses is not required, but is encouraged to help visually
distinguish array contents from array indexes and other vectors.
(See the examples for @racket[indexes-array] for an illustration.)

@examples[#:eval typed-eval
                 (array 0)
                 (array #[0 1 2 3])
                 (array #[#[1 2 3] #[4 5 6]])
                 (array #[#[1 2 3] #[4 5]])]
As with the @racket[list] constructor, the type chosen for the array is the narrowest type
all the elements can have. Unlike @racket[list], because @racket[array] is syntax, instantiating
@racket[array] with the desired element type is a syntax error:
@interaction[#:eval typed-eval
                    (list 1 2 3)
                    (array #[1 2 3])
                    ((inst list Real) 1 2 3)
                    ((inst array Real) #[1 2 3])]
There are two easy ways to annotate the element type:
@interaction[#:eval typed-eval
                    (array #[1 2 3] : Real)
                    (ann (array #[1 2 3]) (Array Real))]
Annotating should rarely be necessary because the @racket[Array] type is covariant.

Normally, the datums within literal vectors are implicitly quoted. However, when used within the
@racket[array] form, the datums must be explicitly quoted.
@interaction[#:eval typed-eval
                    #(this is okay)
                    (array #[not okay])
                    (array #['this 'is 'okay])
                    (array #['#(an) '#(array) '#(of) '#(vectors)])]

Arrays returned by @racket[array] are @tech{strict}.
Another way to create immutable, strict arrays from literal data is to use @racket[list->array].
}

@defform/subs[(mutable-array #[#[...] ...] maybe-type-ann)
              [(maybe-type-ann (code:line) (code:line : type))]]{
Creates a @racket[Mutable-Array] from nested rows of expressions.

The semantics are almost identical to @racket[array]'s, except the result is mutable:
@interaction[#:eval typed-eval
                    (define arr (mutable-array #[0 1 2 3]))
                    arr
                    (array-set! arr #(0) 10)
                    arr]
Because mutable arrays are invariant, this form additionally accepts a type annotation for
the array's elements:
@interaction[#:eval typed-eval
                    (define arr (mutable-array #[0 1 2 3] : Real))
                    arr
                    (array-set! arr #(0) 10.0)
                    arr]

Another way to create mutable arrays from literal data is to use @racket[vector->array].
}

@defproc[(make-array [ds In-Indexes] [value A]) (Array A)]{
Returns an array with @tech{shape} @racket[ds], with every element's value as @racket[value].
Analogous to @racket[make-vector].
@examples[#:eval typed-eval
                 (make-array #() 5)
                 (make-array #(1 2) 'sym)
                 (make-array #(4 0 2) "Invisible")]
The arrays returned by @racket[make-array] do not allocate storage for their elements and
are @tech{strict}.
}

@defproc[(build-array [ds In-Indexes] [proc (Indexes -> A)]) (Array A)]{
Returns an array with @tech{shape} @racket[ds] and @tech{procedure} @racket[proc].
Analogous to @racket[build-vector].
}

@defproc[(array->mutable-array [arr (Array A)]) (Mutable-Array A)]{
Returns a mutable array with the same elements as @racket[arr]. The result is a copy of
@racket[arr], even when @racket[arr] is mutable.
}

@defproc[(mutable-array-copy [arr (Mutable-Array A)]) (Mutable-Array A)]{
Like @racket[(array->mutable-array arr)], but restricted to mutable arrays. It is also faster.
}

@defproc[(indexes-array [ds In-Indexes]) (Array Indexes)]{
Returns an array with @tech{shape} @racket[ds], with each element set to its position in the
array.
@examples[#:eval typed-eval
                 (indexes-array #())
                 (indexes-array #(4))
                 (indexes-array #(2 3))
                 (indexes-array #(4 0 2))]
The resulting array does not allocate storage for its return value's elements, and is @tech{strict}.
(It is essentially the identity function for the domain @racket[ds].)
}

@defproc[(index-array [ds In-Indexes]) (Array Index)]{
Returns an array with @tech{shape} @racket[ds], with each element set to its row-major index in
the array.
@examples[#:eval typed-eval
                 (index-array #(2 3))
                 (array-flatten (index-array #(2 3)))]
As with @racket[indexes-array], the result does not allocate storage for its elements, and is
@tech{strict}.
}

@defproc[(axis-index-array [ds In-Indexes] [axis Integer]) (Array Index)]{
Returns an array with @tech{shape} @racket[ds], with each element set to its position in axis
@racket[axis]. The axis number @racket[axis] must be nonnegative and less than the number of axes
(the length of @racket[ds]).
@examples[#:eval typed-eval
                 (axis-index-array #(3 3) 0)
                 (axis-index-array #(3 3) 1)
                 (axis-index-array #() 0)]
As with @racket[indexes-array], the result does not allocate storage for its elements, and is
@tech{strict}.
}

@defproc[(diagonal-array [dims Integer] [axes-length Integer] [on-value A] [off-value A])
         (Array A)]{
Returns an array with @racket[dims] axes, each with length @racket[axes-length].
(For example, the returned array for @racket[dims = 2] is square.)
The elements on the diagonal (i.e. at indexes of the form @racket[(vector j j ...)] for
@racket[j < axes-length]) have the value @racket[on-value]; the rest have @racket[off-value].
@examples[#:eval typed-eval
                 (diagonal-array 2 7 1 0)]
As with @racket[indexes-array], the result does not allocate storage for its elements, and is
@tech{strict}.
}


@;{==================================================================================================}


@section[#:tag "array:convert"]{Conversion}

@defform[(Listof* A)]{
Equivalent to @racket[(U A (Listof A) (Listof (Listof A)) ...)] if infinite unions were allowed.
This is used as an argument type to @racket[list*->array] and as the return type of
@racket[array->list*].
}

@defform[(Vectorof* A)]{
Like @racket[(Listof* A)], but for vectors. See @racket[vector*->array] and @racket[array->vector*].
}

@deftogether[(@defproc*[([(list->array [lst (Listof A)]) (Array A)]
                         [(list->array [ds In-Indexes] [lst (Listof A)]) (Array A)])]
              @defproc[(array->list [arr (Array A)]) (Listof A)])]{
Convert lists to immutable arrays and back.

The two-argument variant of @racket[list->array] assumes the elements in @racket[lst] are in
row-major order.

For @racket[array->list], if @racket[arr] has no axes or more than one axis, it is (conceptually)
flattened before being converted to a list.

@examples[#:eval typed-eval
                 (list->array '(1 2 3))
                 (list->array '((1 2 3) (4 5)))
                 (list->array #(2 2) '(1 2 3 4))
                 (array->list (array #[1 2 3]))
                 (array->list (array 10))
                 (array->list (array #[#[1 2 3] #[4 5 6]]))]
For conversion between nested lists and multidimensional arrays, see @racket[list*->array] and
@racket[array->list*].
For conversion from flat values to mutable arrays, see @racket[vector->array].

The arrays returned by @racket[list->array] are always @tech{strict}.
}

@deftogether[(@defproc*[([(vector->array [vec (Vectorof A)]) (Mutable-Array A)]
                         [(vector->array [ds In-Indexes] [vec (Vectorof A)]) (Mutable-Array A)])]
              @defproc[(array->vector [arr (Array A)]) (Vectorof A)])]{
Like @racket[list->array] and @racket[array->list], but for vectors.
@examples[#:eval typed-eval
                 (vector->array #(1 2 3))
                 (vector->array #((1 2 3) (4 5)))
                 (vector->array #(2 2) #(1 2 3 4))
                 (array->vector (array #[1 2 3]))
                 (array->vector (array 10))
                 (array->vector (array #[#[1 2 3] #[4 5 6]]))]
For conversion between nested vectors and multidimensional arrays, see @racket[vector*->array] and
@racket[array->vector*].
}

@defproc[(list*->array [lsts (Listof* A)] [pred? ((Listof* A) -> Any : A)]) (Array A)]{
Converts a nested list of elements of type @racket[A] to an array.
The predicate @racket[pred?] identifies elements of type @racket[A].
The shape of @racket[lsts] must be rectangular.

@examples[#:eval typed-eval
                 (list*->array 'singleton symbol?)
                 (list*->array '(0 1 2 3) byte?)
                 (list*->array (list (list (list 5) (list 2 3))
                                     (list (list 4.0) (list 1.4 0.2 9.3)))
                               (make-predicate (Listof Nonnegative-Real)))]

There is no well-typed Typed Racket function that behaves like @racket[list*->array] but does not
require @racket[pred?].
Without an element predicate, there is no way to prove to the type checker that
@racket[list*->array]'s implementation correctly distinguishes elements from rows.

The arrays returned by @racket[list*->array] are always @tech{strict}.
}

@defproc[(array->list* [arr (Array A)]) (Listof* A)]{
The inverse of @racket[list*->array].
}

@defproc[(vector*->array [vecs (Vectorof* A)] [pred? ((Vectorof* A) -> Any : A)]) (Mutable-Array A)]{
Like @racket[list*->array], but accepts nested vectors of elements.
@examples[#:eval typed-eval
                 (vector*->array 'singleton symbol?)
                 ((inst vector*->array Byte) #(0 1 2 3) byte?)]
As in the last example, Typed Racket often needs help inferring @racket[vector*->array]'s
type parameters.
}

@defproc[(array->vector* [arr (Array A)]) (Vectorof* A)]{
Like @racket[array->list*], but produces nested vectors of elements.
}

@defproc[(array-list->array [arrs (Listof (Array A))] [axis Integer 0]) (Array A)]{
Concatenates @racket[arrs] along axis @racket[axis] to form a new array.
If the arrays have different shapes, they are broadcast first.
The axis number @racket[axis] must be nonnegative and @italic{no greater than} the number of axes in
the highest dimensional array in @racket[arrs].
@examples[#:eval typed-eval
                 (array-list->array (list (array 0) (array 1) (array 2) (array 3)))
                 (array-list->array (list (array 0) (array 1) (array 2) (array 3)) 1)
                 (array-list->array (list (array #[0 1 2 3]) (array #['a 'b 'c 'd])))
                 (array-list->array (list (array #[0 1 2 3]) (array '!)))
                 (array-list->array (list (array #[0 1 2 3]) (array '!)) 1)
                 ]
This function is a left inverse of @racket[array->array-list]. (It cannot be a right inverse
because broadcasting cannot be undone.)

For a similar function that does not increase the dimension of the broadcast arrays, see
@racket[array-append*].
}

@defproc[(array->array-list [arr (Array A)] [axis Integer 0]) (Listof (Array A))]{
Turns one axis of @racket[arr] into a list of arrays. Each array in the result has the same shape.
The axis number @racket[axis] must be nonnegative and less than the number of @racket[arr]'s axes.
@examples[#:eval typed-eval
                 (array->array-list (array #[0 1 2 3]))
                 (array->array-list (array #[#[1 2] #[10 20]]))
                 (array->array-list (array #[#[1 2] #[10 20]]) 1)
                 (array->array-list (array 10))]
}

@subsection[#:tag "array:print"]{Printing}

@defparam[array-custom-printer
          print-array
          (All (A) ((Array A)
                    Symbol
                    Output-Port
                    (U Boolean 0 1) -> Any))]{
A parameter whose value is used to print subtypes of @racket[Array].
}

@defproc[(print-array [arr (Array A)]
                      [name Symbol]
                      [port Output-Port]
                      [mode (U Boolean 0 1)])
         Any]{
Prints an array using @racket[array] syntax, using @racket[name] instead of @racket['array]
as the head form. This function is set as the value of @racket[array-custom-printer] when
@racketmodname[math/array] is first required.

Well-behaved @racket[Array] subtypes do not call this function directly to print themselves.
They call the current @racket[array-custom-printer]:
@interaction[#:eval typed-eval
                    (eval:alts
                     ((array-custom-printer)
                      (array #[0 1 2 3])
                      'my-cool-array
                      (current-output-port)
                      #t)
                     (eval:result "" "(my-cool-array #[0 1 2 3])"))]
See @racket[prop:custom-write] for the meaning of the @racket[port] and @racket[mode] arguments.
}


@;{==================================================================================================}


@section[#:tag "array:sequences"]{Comprehensions and Sequences}

Sometimes sequential processing is unavoidable, so @racket[math/array] provides loops and sequences.

@deftogether[(@defform[(for/array: maybe-shape maybe-fill (for:-clause ...) maybe-type-ann
                         body ...+)]
              @defform/subs[(for*/array: maybe-shape maybe-fill (for:-clause ...) maybe-type-ann
                              body ...+)
                            ([maybe-shape (code:line) (code:line #:shape ds)]
                             [maybe-fill (code:line) (code:line #:fill fill)]
                             [maybe-type-ann (code:line) (code:line : body-type)])
                            #:contracts ([ds In-Indexes]
                                         [fill body-type])])]{
Creates arrays by generating elements in a @racket[for]-loop or @racket[for*]-loop.
Unlike other Typed Racket loop macros, these accept a @italic{body annotation}, which declares
the type of elements. They do not accept an annotation for the entire type of the result.
@examples[#:eval typed-eval
                 (for/array: ([x  (in-range 3)] [y  (in-range 3)]) : Integer
                   (+ x y))
                 (for*/array: ([x  (in-range 3)] [y  (in-range 3)]) : Integer
                   (+ x y))]
The shape of the result is independent of the loop clauses: note that the last example
does not have shape @racket[#(3 3)], but shape @racket[#(9)]. To control the shape, use the
@racket[#:shape] keyword:
@interaction[#:eval typed-eval
                    (for*/array: #:shape #(3 3) ([x  (in-range 3)]
                                                 [y  (in-range 3)]) : Integer
                      (+ x y))]

If the loop does not generate enough elements, the rest are filled with the @italic{first}
generated value:
@interaction[#:eval typed-eval
                    (for*/array: #:shape #(4) ([x  (in-range 1 3)]) x)]
To change this behavior, use the @racket[#:fill] keyword:
@interaction[#:eval typed-eval
                    (for*/array: #:shape #(4) #:fill -1 ([x  (in-range 1 3)]) x)]
In the last two examples, the array's type is @racket[(Mutable-Array Any)] because
a body annotation was not given.
}

@deftogether[(@defform[(for/array maybe-shape maybe-fill (for-clause ...)
                         body ...+)]
              @defform[(for*/array maybe-shape maybe-fill (for-clause ...)
                         body ...+)])]{
Untyped versions of the loop macros.
}

@defproc[(in-array [arr (Array A)]) (Sequenceof A)]{
Returns a sequence of @racket[arr]'s elements in row-major order.
@examples[#:eval typed-eval
                 (define arr (array #[#[1 2] #[10 20]]))
                 (for/list: : (Listof Integer) ([x  (in-array arr)]) x)]
}

@defproc[(in-array-axis [arr (Array A)] [axis Integer 0]) (Sequenceof (Array A))]{
Like @racket[array->array-list], but returns a sequence.
@examples[#:eval typed-eval
                 (define arr (array #[#[1 2] #[10 20]]))
                 (sequence->list (in-array-axis arr))
                 (sequence->list (in-array-axis arr 1))]
}

@defproc[(in-array-indexes [ds In-Indexes]) (Sequenceof Indexes)]{
Returns a sequence of indexes for shape @racket[ds], in row-major order.
@examples[#:eval typed-eval
                 (for/array: #:shape #(3 3) ([js  (in-array-indexes #(3 3))]) : Indexes
                   js)
                 (for*/array: #:shape #(3 3) ([j0  (in-range 3)]
                                              [j1  (in-range 3)]) : In-Indexes
                   (vector j0 j1))
                 (indexes-array #(3 3))]
}


@;{==================================================================================================}


@section[#:tag "array:pointwise"]{Pointwise Operations}

Most of the operations documented in this section are simple macros that apply @racket[array-map]
to a function and their array arguments.

@defproc*[([(array-map [f (-> R)]) (Array R)]
           [(array-map [f (A -> R)] [arr0 (Array A)]) (Array R)]
           [(array-map [f (A B Ts ... -> R)] [arr0 (Array A)] [arr1 (Array B)] [arrs (Array Ts)] ...)
            (Array R)])]{
Composes @racket[f] with the given arrays' @tech{procedures}. When the arrays' shapes do not match,
they are @tech{broadcast} to the same shape first. If broadcasting fails, @racket[array-map] raises
an error.

@examples[#:eval typed-eval
                 (array-map (λ: ([x : String]) (string-append x "!"))
                            (array #[#["Hello" "I"] #["Am" "Shouting"]]))
                 (array-map string-append
                            (array #[#["Hello" "I"] #["Am" "Shouting"]])
                            (array "!"))
                 (array-map + (index-array #(3 3 3)) (array 2))
                 (array-map + (index-array #(2 2)) (index-array #(3 3)))]

Typed Racket can often derive fairly precise element types for the resulting array:
@interaction[#:eval typed-eval
                    (array-map * (array #[-4.3 -1.2 -0.2]) (array -2.81))]
How precise the result type is depends on the type of @racket[f]. Preserving precise result types
for lifted arithmetic operators is the main reason most pointwise operations are macro wrappers for
@racket[array-map].

Unlike @racket[map], @racket[array-map] can map a zero-argument function:
@interaction[#:eval typed-eval
                    (array-map (λ () "Whoa, Nelly!"))]
If the resulting zero-dimensional array is used in a pointwise operation with other arrays,
it will be broadcast to their shape:
@interaction[#:eval typed-eval
                    (array-map + (array #[1 2 3]) (array-map (λ () -10)))]

When explicitly instantiating @racket[array-map]'s types using @racket[inst], instantiate
@racket[R] (the return type's element type) first, then the arguments' element types in order.
}

@defform[(inline-array-map f arrs ...)]{
Like @racket[array-map], but possibly faster. Inlining a map operation can allow Typed Racket's
optimizer to replace @racket[f] with something unchecked and type-specific (for example,
replace @racket[*] with @racket[unsafe-fl*]), at the expense of code size.
}

@deftogether[(@defform[(array+ arrs ...)]
              @defform[(array* arrs ...)]
              @defform[(array- arr0 arrs ...)]
              @defform[(array/ arr0 arrs ...)]
              @defform[(array-min arr0 arrs ...)]
              @defform[(array-max arr0 arrs ...)])]{
Equivalent to mapping arithmetic operators over arrays. Note that because @racket[(array-map f)]
returns sensible answers, so do @racket[(array+)] and @racket[(array*)].
@examples[#:eval typed-eval
                 (array+ (array #[#[0.0 1.0] #[2.0 3.0]]) (array 200))
                 (array+)
                 (array*)
                 (array/ (array #[2 1/2]))]
}

@defform[(array-scale arr x)]{
Equivalent to @racket[(array* arr (array x))], but faster.
}

@deftogether[(@defform[(array-abs arr)]
              @defform[(array-sqr arr)]
              @defform[(array-sqrt arr)]
              @defform[(array-conjugate arr)])]{
Equivalent to @racket[(array-map f arr)], where @racket[f] is respectively
@racket[abs],
@racket[sqr],
@racket[sqrt],
or @racket[conjugate].
}

@deftogether[(@defform[(array-real-part arr)]
              @defform[(array-imag-part arr)]
              @defform[(array-make-rectangular arr0 arr1)]
              @defform[(array-magnitude arr)]
              @defform[(array-angle arr)]
              @defform[(array-make-polar arr0 arr1)])]{
Conversions to and from complex numbers, lifted to operate on arrays.
}

@deftogether[(@defform[(array< arr0 arr1 arrs ...)]
              @defform[(array<= arr0 arr1 arrs ...)]
              @defform[(array> arr0 arr1 arrs ...)]
              @defform[(array>= arr0 arr1 arrs ...)]
              @defform[(array= arr0 arr1 arrs ...)])]{
Equivalent to @racket[(array-map f arr0 arr1 arrs ...)], where @racket[f] is respectively
@racket[<], @racket[<=], @racket[>], @racket[>=], or @racket[=].
}

@deftogether[(@defform[(array-not arr)]
              @defform[(array-and arr ...)]
              @defform[(array-or arr ...)]
              @defform[(array-if cond-arr true-arr false-err)])]{
Boolean operators lifted to operate on arrays.

When given @tech{nonstrict} arrays, the short-cutting behavior of @racket[array-and],
@racket[array-or] and @racket[array-if] can keep their elements from being referred to (and thus
computed).
However, these macros cannot be used to distinguish base and inductive cases in a recursive function,
because the array arguments are eagerly evaluated. For example, this function never returns, even
when @racket[array-strictness] is @racket[#f]:
@racketblock[(: array-factorial ((Array Integer) -> (Array Integer)))
             (define (array-factorial arr)
               (array-if (array<= arr (array 0))
                         (array 1)
                         (array* arr (array-factorial (array- arr (array 1))))))]
}

@subsection{Broadcasting}

@defparam[array-broadcasting broadcasting (U Boolean 'permissive)]{
Determines the rules used when broadcasting arrays for pointwise operations. See
@secref{array:broadcasting:control}.
}

@defproc[(array-shape-broadcast [dss (Listof Indexes)]
                                [broadcasting (U Boolean 'permissive) (array-broadcasting)])
         Indexes]{
Determines the shape of the resulting array if some number of arrays with shapes @racket[dss]
were broadcast for a pointwise operation using the given broadcasting rules. If broadcasting
fails, @racket[array-shape-broadcast] raises an error.
@examples[#:eval typed-eval
                 (array-shape-broadcast '())
                 (array-shape-broadcast (list (vector) ((inst vector Index) 10)))
                 (array-shape-broadcast (list ((inst vector Index) 2)
                                              ((inst vector Index) 10)))
                 (array-shape-broadcast (list ((inst vector Index) 2)
                                              ((inst vector Index) 10))
                                        'permissive)]
}

@defproc[(array-broadcast [arr (Array A)] [ds Indexes]) (Array A)]{
Returns an array with shape @racket[ds] made by inserting new axes and repeating rows.
This is used for both @racket[(array-broadcasting #t)] and @racket[(array-broadcasting 'permissive)].
@examples[#:eval typed-eval
                 (array-broadcast (array 10) ((inst vector Index) 10))
                 (array-broadcast (array #[0 1]) #())
                 (array-broadcast (array #[0 1]) ((inst vector Index) 5))]

When @racket[array-strictness] is @racket[#f], @racket[array-broadcast] always returns a
@tech{nonstrict} array.

When @racket[array-strictness] is @racket[#t], @racket[array-broadcast] returns a strict array
when @racket[arr] is nonstrict and the result has more elements than @racket[arr].
}


@;{==================================================================================================}


@section[#:tag "array:indexing"]{Indexing and Slicing}

@defproc[(array-ref [arr (Array A)] [js In-Indexes]) A]{
Returns the element of @racket[arr] at position @racket[js]. If any index in @racket[js] is
negative or not less than its corresponding axis length, @racket[array-ref] raises an error.
}

@defproc[(array-set! [arr (Settable-Array A)] [js In-Indexes] [value A]) Void]{
Sets the element of @racket[arr] at position @racket[js] to @racket[value].
If any index in @racket[js] is negative or not less than its corresponding axis length,
@racket[array-set!] raises an error.
}

@defproc[(array-indexes-ref [arr (Array A)] [idxs (Array In-Indexes)]) (Array A)]{
High-level explanation: Returns multiple elements from @racket[arr] in a new array.

Lower-level explanation: Returns an array with same shape as @racket[idxs], whose elements are
@racket[array-ref]'d from @racket[arr] using the indexes in @racket[idxs]. 
@examples[#:eval typed-eval
                 (define arr (array #[#[1 2] #[10 20]]))
                 (define idxs (array #['#(0 0) '#(1 1)]))
                 (array-indexes-ref arr idxs)]

Implementation-level explanation: @racket[(array-indexes-ref arr idxs)] is equivalent to
@interaction[#:eval typed-eval
                    (build-array (array-shape idxs)
                                 (λ: ([js : Indexes])
                                   (array-ref arr (array-ref idxs js))))]
but faster.
}

@defproc[(array-indexes-set! [arr (Settable-Array A)] [idxs (Array In-Indexes)] [vals (Array A)])
         Void]{
Indexes @racket[arr] in the same way that @racket[array-indexes-ref] does, but mutates elements.
If @racket[idxs] and @racket[vals] do not have the same shape, they are @tech{broadcast} first.
@examples[#:eval typed-eval
                 (define arr (mutable-array #[#[1 2] #[10 20]]))
                 (define idxs (array #['#(0 0) '#(1 1)]))
                 (array-indexes-set! arr idxs (array -1))
                 arr]
When two indexes in @racket[idxs] are the same, the element at that index is mutated more
than once in some unspecified order.
}

@defproc[(array-slice-ref [arr (Array A)] [specs (Listof Slice-Spec)]) (Array A)]{
Returns a transformation of @racket[arr] according to the list of slice specifications
@racket[specs]. See @secref{array:slicing} for a discussion and examples.
}

@defproc[(array-slice-set! [arr (Settable-Array A)] [specs (Listof Slice-Spec)] [vals (Array A)])
         Void]{
Like @racket[array-indexes-set!], but for slice specifications. Equivalent to
@racketblock[(let ([idxs  (array-slice-ref (indexes-array (array-shape arr)) specs)])
               (array-indexes-set! arr idxs vals))]
@examples[#:eval typed-eval
                 (define arr (array->mutable-array (axis-index-array #(5 5) 1)))
                 (array-slice-set! arr (list (:: 1 #f 2) (::)) (array 1))
                 arr
                 (array-slice-set!
                  arr (list (::) (:: 1 #f 2))
                  (array-scale (array-slice-ref arr (list (::) (:: 1 #f 2))) -1))
                 arr]
When a slice specification refers to an element in @racket[arr] more than once, the element is
mutated more than once in some unspecified order.
}

@defidform[Slice-Spec]{
The type of a slice specification. Currently defined as
@racketblock[(U (Sequenceof Integer) Slice Slice-Dots Integer Slice-New-Axis)]

A @racket[(Sequenceof Integer)] slice specification causes @racket[array-slice-ref] to pick rows
from an axis.
An @racket[Integer] slice specification causes @racket[array-slice-ref] to remove an axis by
replacing it with one of its rows.

See @secref{array:slicing} for an extended example.
}

@deftogether[(@defidform[Slice]
              @defproc*[([(:: [end (U #f Integer) #f]) Slice]
                         [(:: [start (U #f Integer)] [end (U #f Integer)] [step Integer 1])
                          Slice])]
              @defproc[(slice? [v Any]) Boolean]
              @defproc[(slice-start [s Slice]) (U #f Fixnum)]
              @defproc[(slice-end [s Slice]) (U #f Fixnum)]
              @defproc[(slice-step [s Slice]) Fixnum])]{
The type of @racket[in-range]-like slice specifications, its constructor, predicate, and accessors.

@racket[array-slice-ref] interprets a @racket[Slice] like an @racket[in-range] sequence object.
When @racket[start] or @racket[end] is @racket[#f], it is interpreted as an axis-length-dependent
endpoint.
}

@defproc[(slice->range-values [s Slice] [dk Index]) (Values Fixnum Fixnum Fixnum)]{
Given a slice @racket[s] and an axis length @racket[dk], returns the arguments to @racket[in-range]
that would produce an equivalent slice specification.

This is used internally by @racket[array-slice-ref] to interpret a @racket[Slice] object as a
sequence of indexes.
}

@deftogether[(@defidform[Slice-Dots]
              @defthing[::... Slice-Dots]
              @defproc[(slice-dots? [v Any]) Boolean])]{
The type of greedy, multiple-axis-preserving slice specifications, its singleton value, and predicate.
}

@deftogether[(@defidform[Slice-New-Axis]
              @defproc[(::new [dk Integer 1]) Slice-New-Axis]
              @defproc[(slice-new-axis? [v Any]) Boolean]
              @defproc[(slice-new-axis-length [s Slice-New-Axis]) Index])]{
The type of slice specifications that indicate inserting a new axis, its constructor, predicate, and
accessor. The axis length @racket[dk] must be nonnegative.
}


@;{==================================================================================================}


@section[#:tag "array:transform"]{Transformations}

@defproc[(array-transform [arr (Array A)] [ds In-Indexes] [proc (Indexes -> In-Indexes)])
         (Array A)]{
Returns an array with shape @racket[ds] and elements taken from @racket[arr], by composing
@racket[arr]'s procedure with @racket[proc].

Possibly the most useless, but simplest example of @racket[proc] disregards its input
indexes and returns constant indexes:
@interaction[#:eval typed-eval
                    (define arr (array #[#[0 1] #[2 'three]]))
                    (array-transform arr #(3 3) (λ: ([js : Indexes]) #(1 1)))]
Doubling an array in every dimension by duplicating elements:
@interaction[#:eval typed-eval
                    (define arr (index-array #(3 3)))
                    arr
                    (array-transform
                     arr
                     (vector-map (λ: ([d : Index]) (* d 2)) (array-shape arr))
                     (λ: ([js : Indexes])
                       (vector-map (λ: ([j : Index]) (quotient j 2)) js)))]
When @racket[array-strictness] is @racket[#f], the above result takes little more space than the
original array.

Almost all array transformations, including @secref{array:slicing}, are implemented using
@racket[array-transform] or its unsafe counterpart.
}

@defproc[(array-append* [arrs (Listof (Array A))] [k Integer 0]) (Array A)]{
Appends the arrays in @racket[arrs] along axis @racket[k]. If the arrays' shapes are not
the same, they are @tech{broadcast} first.
@examples[#:eval typed-eval
                 (define arr (array #[#[0 1] #[2 3]]))
                 (define brr (array #[#['a 'b] #['c 'd]]))
                 (array-append* (list arr brr))
                 (array-append* (list arr brr) 1)
                 (array-append* (list arr (array 'x)))]
For an append-like operation that increases the dimension of the broadcast arrays, see
@racket[array-list->array].
}

@defproc[(array-axis-insert [arr (Array A)] [k Integer] [dk Integer 1]) (Array A)]{
Inserts an axis of length @racket[dk] before axis number @racket[k], which must be no greater
than the dimension of @racket[arr].
@examples[#:eval typed-eval
                 (define arr (array #[#[0 1] #[2 3]]))
                 (array-axis-insert arr 0)
                 (array-axis-insert arr 1)
                 (array-axis-insert arr 2)
                 (array-axis-insert arr 1 2)]
}

@defproc[(array-axis-ref [arr (Array A)] [k Integer] [jk Integer]) (Array A)]{
Removes an axis from @racket[arr] by keeping only row @racket[jk] in axis @racket[k], which
must be less than the dimension of @racket[arr].
@examples[#:eval typed-eval
                 (define arr (array #[#[0 1] #[2 3]]))
                 (array-axis-ref arr 0 0)
                 (array-axis-ref arr 0 1)
                 (array-axis-ref arr 1 0)]
}

@defproc[(array-axis-swap [arr (Array A)] [k0 Integer] [k1 Integer]) (Array A)]{
Returns an array like @racket[arr], but with axes @racket[k0] and @racket[k1] swapped.
In two dimensions, this is called a transpose.
@examples[#:eval typed-eval
                 (array-axis-swap (array #[#[0 1] #[2 3]]) 0 1)
                 (define arr (indexes-array #(2 2 2)))
                 arr
                 (array-axis-swap arr 0 1)
                 (array-axis-swap arr 1 2)]
}

@defproc[(array-axis-permute [arr (Array A)] [perm (Listof Integer)]) (Array A)]{
Returns an array like @racket[arr], but with axes permuted according to @racket[perm].

The list @racket[perm] represents a mapping from source axis numbers to destination
axis numbers: the source is the list position, the destination is the list element.
For example, the permutation @racket['(0 1 2)] is the identity permutation for three-dimensional
arrays, @racket['(1 0)] swaps axes @racket[0] and @racket[1], and @racket['(3 1 2 0)] swaps
axes @racket[0] and @racket[3].

The permutation must contain each integer from @racket[0] to @racket[(- (array-dims arr) 1)]
exactly once.

@examples[#:eval typed-eval
                 (array-axis-swap (array #[#[0 1] #[2 3]]) 0 1)
                 (array-axis-permute (array #[#[0 1] #[2 3]]) '(1 0))]
}

@defproc[(array-reshape [arr (Array A)] [ds In-Indexes]) (Array A)]{
Returns an array with elements in the same row-major order as @racket[arr], but with
shape @racket[ds]. The product of the indexes in @racket[ds] must be @racket[(array-size arr)].
@examples[#:eval typed-eval
                 (define arr (indexes-array #(2 3)))
                 arr
                 (array-reshape arr #(3 2))
                 (array-reshape (index-array #(3 3)) #(9))]
}

@defproc[(array-flatten [arr (Array A)]) (Array A)]{
Returns an array with shape @racket[(vector (array-size arr))], with the elements of
@racket[arr] in row-major order.
@examples[#:eval typed-eval
                 (array-flatten (array 10))
                 (array-flatten (array #[#[0 1] #[2 3]]))]
}


@;{==================================================================================================}


@section[#:tag "array:fold"]{Folds, Reductions and Expansions}

@subsection{Axis Folds}

@defproc*[([(array-axis-fold [arr (Array A)] [k Integer] [f (A A -> A)]) (Array A)]
           [(array-axis-fold [arr (Array A)] [k Integer] [f (A B -> B)] [init B]) (Array B)])]{
Folds a binary function @racket[f] over axis @racket[k] of @racket[arr]. The result has the
shape of @racket[arr] but with axis @racket[k] removed.

The three-argument variant uses the first value of each row in axis @racket[k] as @racket[init].
It therefore requires axis @racket[k] to have positive length.

@examples[#:eval typed-eval
                 (define arr (index-array #(3 4)))
                 arr
                 (array-axis-fold arr 0 +)
                 (array-axis-fold arr 1 (inst cons Index (Listof Index)) empty)]
Notice that the second example returns an array of reversed lists.
This is therefore a left fold; see @racket[foldl].

If you need control over the order of evaluation in axis @racket[k]'s rows, see
@racket[array-axis-reduce].
}

@deftogether[(@defform*[((array-axis-sum arr k)
                         (array-axis-sum arr k init))]
              @defform*[((array-axis-prod arr k)
                         (array-axis-prod arr k init))
                        #:contracts ([arr   (Array Number)]
                                     [k     Integer]
                                     [init  Number])])]{
}
@deftogether[(@defform*[((array-axis-min arr k)
                         (array-axis-min arr k init))]
              @defform*[((array-axis-max arr k)
                         (array-axis-max arr k init))
                        #:contracts ([arr   (Array Real)]
                                     [k     Integer]
                                     [init  Real])])]{
Some standard per-axis folds, defined in terms of @racket[array-axis-fold]. The two-argument
variants require axis @racket[k] to have positive length.
@examples[#:eval typed-eval
                 (define arr (index-array #(3 4)))
                 arr
                 (array-axis-fold arr 1 +)
                 (array-axis-sum arr 1)
                 (array-axis-sum arr 0 0.0)]
}

@defproc[(array-axis-count [arr (Array A)] [k Integer] [pred? (A -> Any)]) (Array Index)]{
Counts the elements @racket[x] in rows of axis @racket[k] for which @racket[(pred? x)] is true.
@examples[#:eval typed-eval
                 (define arr (index-array #(3 3)))
                 arr
                 (array-axis-count arr 1 odd?)]
}

@deftogether[(@defproc[(array-axis-and [arr (Array A)] [k Integer]) (Array (U A Boolean))]
              @defproc[(array-axis-or [arr (Array A)] [k Integer]) (Array (U A #f))])]{
Apply @racket[and] or @racket[or] to each row in axis @racket[k] of array @racket[arr].
Evaluation is short-cut as with the @racket[and] and @racket[or] macros, which is only observable
if @racket[arr] is @tech{nonstrict}.

In the following example, computing the second array element sets @racket[second?] to @racket[#t]:
@interaction[#:eval typed-eval
                    (define second? (ann #f Boolean))
                    (define arr
                      (parameterize ([array-strictness #f])
                        (build-array #(2) (λ: ([js : Indexes])
                                            (cond [(zero? (vector-ref js 0))  #f]
                                                  [else  (set! second? #t)
                                                         #t])))))]
Printing @racket[arr] causes @racket[(set! second? #t)] to be evaluated, but applying
@racket[array-axis-and] does not:
@interaction[#:eval typed-eval
                    (array-axis-and arr 0)
                    second?]
However, if @racket[arr] were strict, @racket[(set! second? #t)] would be evaluated when @racket[arr]
was created.
}

@subsection{Whole-Array Folds}

@defproc[(array-fold [arr (Array A)] [g ((Array A) Index -> (Array A))]) (Array A)]{
Folds @racket[g] over @italic{each axis} of @racket[arr], in reverse order. The arguments
to @racket[g] are an array (initially @racket[arr]) and the current axis.
It should return an array with one fewer dimension than the array given, but does not have to.
@examples[#:eval typed-eval
                 (define arr (index-array #(3 4)))
                 arr
                 (array-fold arr (λ: ([arr : (Array Integer)] [k : Index])
                                   (array-axis-sum arr k)))
                 (apply + (array->list arr))
                 (array-ref (array-fold arr (inst array->list-array (Listof* Integer)))
                            #())]
}

@defproc*[([(array-all-fold [arr (Array A)] [f (A A -> A)]) A]
           [(array-all-fold [arr (Array A)] [f (A A -> A)] [init A]) A])]{
Folds @racket[f] over every element of @racket[arr] by folding @racket[f] over each axis in
reverse order. The two-argument variant is equivalent to
@racketblock[(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
                                          (array-axis-fold arr k f)))
                        #())]
and the three-argument variant is similar. The two-argument variant requires every axis to have
positive length.
@examples[#:eval typed-eval
                 (define arr (index-array #(3 4)))
                 arr
                 (array-all-fold arr +)
                 (array-all-fold (array #[]) + 0.0)]
Because @racket[f] is folded over the last axis first, it receives @racket[arr]'s elements (as its
first argument) in row-major order.
}

@deftogether[(@defform*[((array-all-sum arr)
                         (array-all-sum arr init))]
              @defform*[((array-all-prod arr)
                         (array-all-prod arr init))
                        #:contracts ([arr   (Array Number)]
                                     [init  Number])])]{
}
@deftogether[(@defform*[((array-all-min arr)
                         (array-all-min arr init))]
              @defform*[((array-all-max arr)
                         (array-all-max arr init))
                        #:contracts ([arr   (Array Real)]
                                     [init  Real])])]{
Some standard whole-array folds, defined in terms of @racket[array-all-fold]. The one-argument
variants require each axis in @racket[arr] to have positive length.
@examples[#:eval typed-eval
                 (define arr (index-array #(3 4)))
                 arr
                 (array-all-fold arr +)
                 (array-all-sum arr)
                 (array-all-sum arr 0.0)]
}

@deftogether[(@defproc[(array-all-and [arr (Array A)]) (U A Boolean)]
              @defproc[(array-all-or [arr (Array A)]) (U A #f)])]{
Apply @racket[and] or @racket[or] to @racket[arr]'s elements using short-cut evaluation in row-major
order.

@examples[#:eval typed-eval
                 (define arr (index-array #(3 3)))
                 (array-all-and (array= arr arr))
                 (define brr (array+ arr (array 1)))
                 (array-all-and (array= arr brr))
                 (array-all-or (array= arr (array 0)))]

@racket[(array-all-and arr)] is defined as
@racketblock[(parameterize ([array-strictness #f])
               (array-ref (array-fold arr array-axis-and) #()))]
and @racket[array-all-or] is defined similarly, using @racket[array-axis-or].
}

@defform[(array-count pred? arrs ...)
         #:contracts ([arrs   (Array Ts)]
                      [pred?  (Ts ... -> Any)])]{
When given one array @racket[arr], returns the number of elements @racket[x] in @racket[arr] for
which @racket[(pred? x)] is true.
When given multiple arrays, @racket[array-count] does the same with the corresponding elements from
any number of arrays.
If the arrays' shapes are not the same, they are @tech{broadcast} first.

@examples[#:eval typed-eval
                 (array-count zero? (array #[#[0 1 0 2] #[0 3 -1 4]]))
                 (array-count equal?
                              (array #[#[0 1] #[2 3] #[0 1] #[2 3]])
                              (array #[0 1]))]

@racket[(array-count pred? arrs ...)] is like
@racketblock[(array-all-sum (array-map (λ (x ...) (if (pred? x ...) 1 0)) arrs ...)
                            0)]
but does not create intermediate (strict) arrays, and always returns an @racket[Index].
}

@deftogether[(@defform[(array-andmap pred? arrs ...)]
              @defform[(array-ormap pred? arrs ...)
                       #:contracts ([arrs   (Array Ts)]
                                    [pred?  (Ts ... -> Any)])])]{
Like @racket[andmap] and @racket[ormap], but for arrays.
Evaluation is short-cut, in row-major order.
If the arrays' shapes are not the same, they are @tech{broadcast} first.

Determining whether each row is equal to @racket[(array #[0 1])]:
@interaction[#:eval typed-eval
                    (array-andmap equal?
                                  (array #[#[0 1] #[0 1] #[0 1] #[0 1]])
                                  (array #[0 1]))]
Determining whether any row has @racket[0] as its first element or @racket[1] as its second:
@interaction[#:eval typed-eval
                    (array-ormap equal?
                                 (array #[#[0 2] #[2 3] #[1 1] #[2 3]])
                                 (array #[0 1]))]
Determining whether any row is equal to @racket[(array #[0 1])]:
@interaction[#:eval typed-eval
                    (array-ormap equal?
                                 (array->list-array (array #[#[0 2] #[2 3] #[1 1] #[2 3]]))
                                 (array->list-array (array #[0 1])))]

@racket[(array-andmap pred? arrs ...)] is defined as
@racketblock[(parameterize ([array-strictness #f])
               (array-all-and (array-map pred? arrs ...)))]
and @racket[array-ormap] is defined similarly, using @racket[array-all-or].
}

@subsection{General Reductions and Expansions}

@defproc[(array-axis-reduce [arr (Array A)] [k Integer] [h (Index (Integer -> A) -> B)]) (Array B)]{
Like @racket[array-axis-fold], but allows evaluation control (such as short-cutting @racket[and] and
@racket[or]) by moving the loop into @racket[h]. The result has the shape of @racket[arr], but with
axis @racket[k] removed.

The arguments to @racket[h] are the length of axis @racket[k] and a procedure that retrieves
elements from that axis's rows by their indexes in axis @racket[k]. It should return the elements
of the resulting array.

For example, summing the squares of the rows in axis @racket[1]:
@interaction[#:eval typed-eval
                    (define arr (index-array #(3 3)))
                    arr
                    (array-axis-reduce
                     arr 1
                     (λ: ([dk : Index] [proc : (Integer -> Real)])
                       (for/fold: ([s : Real 0]) ([jk  (in-range dk)])
                         (+ s (sqr (proc jk))))))
                    (array-axis-sum (array-map sqr arr) 1)]
Transforming an axis into a list using @racket[array-axis-fold] and @racket[array-axis-reduce]:
@interaction[#:eval typed-eval
                    (array-map (inst reverse Index)
                               (array-axis-fold arr 1
                                                (inst cons Index (Listof Index))
                                                empty))
                    (array-axis-reduce arr 1 (inst build-list Index))]
The latter is essentially the definition of @racket[array->list-array].

Every fold, including @racket[array-axis-fold], is ultimately defined using
@racket[array-axis-reduce] or its unsafe counterpart.
}

@defproc[(array-axis-expand [arr (Array A)] [k Integer] [dk Integer] [g (A Index -> B)]) (Array B)]{
Inserts a new axis number @racket[k] of length @racket[dk], using @racket[g] to generate values;
@racket[k] must be @italic{no greater than} the dimension of @racket[arr], and @racket[dk] must be
nonnegative.

Conceptually, @racket[g] is applied @racket[dk] times to each element in each row of axis @racket[k],
once for each nonnegative index @racket[jk < dk].

Turning vector elements into rows of a new last axis using @racket[array-axis-expand] and
@racket[vector-ref]:
@interaction[#:eval typed-eval
                    (define arr (array #['#(a b c) '#(d e f) '#(g h i)]))
                    (array-axis-expand arr 1 3 vector-ref)]
Creating a @racket[vandermonde-matrix]:
@interaction[#:eval typed-eval
                    (array-axis-expand (list->array '(1 2 3 4)) 1 5 expt)]

This function is a dual of @racket[array-axis-reduce] in that it can be used to invert applications
of @racket[array-axis-reduce].
To do so, @racket[g] should be a destructuring function that is dual to the constructor passed to
@racket[array-axis-reduce].
Example dual pairs are @racket[vector-ref] and @racket[build-vector], and @racket[list-ref] and
@racket[build-list].

(Do not pass @racket[list-ref] to @racket[array-axis-expand] if you care about performance, though.
See @racket[list-array->array] for a more efficient solution.)
}

@defproc[(array->list-array [arr (Array A)] [k Integer 0]) (Array (Listof A))]{
Returns an array of lists, computed as if by applying @racket[list] to the elements in each row of
axis @racket[k].
@examples[#:eval typed-eval
                 (define arr (index-array #(3 3)))
                 arr
                 (array->list-array arr 1)
                 (array-ref (array->list-array (array->list-array arr 1) 0) #())]
See @racket[mean] for more useful examples, and @racket[array-axis-reduce] for an example that shows
how @racket[array->list-array] is implemented.
}

@defproc[(list-array->array [arr (Array (Listof A))] [k Integer 0]) (Array A)]{
Returns an array in which the list elements of @racket[arr] comprise a new axis @racket[k].
Equivalent to @racket[(array-axis-expand arr k n list-ref)] where @racket[n] is the
length of the lists in @racket[arr], but with O(1) indexing.

@examples[#:eval typed-eval
                 (define arr (array->list-array (index-array #(3 3)) 1))
                 arr
                 (list-array->array arr 1)]

For fixed @racket[k], this function and @racket[array->list-array] are mutual inverses with respect
to their array arguments.
}

@;{==================================================================================================}


@section[#:tag "array:other"]{Other Array Operations}

@subsection{Fast Fourier Transform}

@margin-note{Wikipedia: @hyperlink["http://wikipedia.org/wiki/Discrete_Fourier_transform"]{Discrete
Fourier Transform}}
@defproc[(array-axis-fft [arr (Array Number)] [k Integer]) (Array Float-Complex)]{
Performs a discrete Fourier transform on axis @racket[k] of @racket[arr]. The length of @racket[k]
must be an integer power of two. (See @racket[power-of-two?].) The scaling convention is
determined by the parameter @racket[dft-convention], which defaults to the convention used in
signal processing.

The transform is done in parallel using @racket[max-math-threads] threads.
}

@defproc[(array-axis-inverse-fft [arr (Array Number)] [k Integer]) (Array Float-Complex)]{
The inverse of @racket[array-axis-fft], performed by parameterizing the forward transform on
@racket[(dft-inverse-convention)].
}

@defproc[(array-fft [arr (Array Number)]) FCArray]{
Performs a discrete Fourier transform on each axis of @racket[arr] using @racket[array-axis-fft].
}

@defproc[(array-inverse-fft [arr (Array Number)]) FCArray]{
The inverse of @racket[array-fft], performed by parameterizing the forward transform on
@racket[(dft-inverse-convention)].
}


@;{==================================================================================================}


@section[#:tag "array:subtypes"]{Subtypes}

@subsection[#:tag "flarray"]{Flonum Arrays}

@defidform[FlArray]{
The type of @deftech{flonum arrays}, a subtype of @racket[(Settable-Array Flonum)] that stores its
elements in an @racket[FlVector]. A flonum array is always @tech{strict}.
}

@defform[(flarray #[#[...] ...])]{
Like @racket[array], but creates @tech{flonum arrays}. The listed elements must be real numbers,
and may be exact.

@examples[#:eval typed-eval
                 (flarray 0.0)
                 (flarray #['x])
                 (flarray #[#[1 2] #[3 4]])]
}

@defproc[(array->flarray [arr (Array Real)]) FlArray]{
Returns a flonum array that has approximately the same elements as @racket[arr]. Exact
elements will likely lose precision during conversion.
}

@defproc[(flarray-data [arr FlArray]) FlVector]{
Returns the elements of @racket[arr] in a flonum vector, in row-major order.
@examples[#:eval typed-eval
                 (flarray-data (flarray #[#[1 2] #[3 4]]))]
}

@defproc[(flarray-map [f (Flonum ... -> Flonum)] [arrs FlArray] ...) FlArray]{
Maps the function @racket[f] over the arrays @racket[arrs]. If the arrays do not have the same
shape, they are @tech{broadcast} first. If the arrays do have the same shape, this operation can
be quite fast.

The function @racket[f] is meant to accept the same number of arguments as the number of its
following flonum array arguments. However, a current limitation in Typed Racket requires @racket[f]
to accept @italic{any} number of arguments. To map a single-arity function such as @racket[fl+],
for now, use @racket[inline-flarray-map] or @racket[array-map].
}

@defform[(inline-flarray-map f arrs ...)
         #:contracts ([f  (Flonum ... -> Flonum)]
                      [arrs  FlArray])]{
Like @racket[inline-array-map], but for flonum arrays.

@bold{This is currently unavailable in untyped Racket.}
}

@deftogether[(@defproc[(flarray+ [arr0 FlArray] [arr1 FlArray]) FlArray]
              @defproc[(flarray* [arr0 FlArray] [arr1 FlArray]) FlArray]
              @defproc*[([(flarray- [arr FlArray]) FlArray]
                         [(flarray- [arr0 FlArray] [arr1 FlArray]) FlArray])]
              @defproc*[([(flarray/ [arr FlArray]) FlArray]
                         [(flarray/ [arr0 FlArray] [arr1 FlArray]) FlArray])]
              @defproc[(flarray-min [arr0 FlArray] [arr1 FlArray]) FlArray]
              @defproc[(flarray-max [arr0 FlArray] [arr1 FlArray]) FlArray]
              @defproc[(flarray-scale [arr FlArray] [x Flonum]) FlArray]
              @defproc[(flarray-abs [arr FlArray]) FlArray]
              @defproc[(flarray-sqr [arr FlArray]) FlArray]
              @defproc[(flarray-sqrt [arr FlArray]) FlArray])]{
Arithmetic lifted to flonum arrays.
}

@subsection[#:tag "fcarray"]{Float-Complex Arrays}

@defidform[FCArray]{
The type of @deftech{float-complex arrays}, a subtype of @racket[(Settable-Array Float-Complex)]
that stores its elements in a pair of @racket[FlVector]s. A float-complex array is always
@tech{strict}.
}

@defform[(fcarray #[#[...] ...])]{
Like @racket[array], but creates @tech{float-complex arrays}. The listed elements must be numbers,
and may be exact.

@examples[#:eval typed-eval
                 (fcarray 0.0)
                 (fcarray #['x])
                 (fcarray #[#[1 2+1i] #[3 4+3i]])]
}

@defproc[(array->fcarray [arr (Array Number)]) FCArray]{
Returns a float-complex array that has approximately the same elements as @racket[arr]. Exact
elements will likely lose precision during conversion.
}

@deftogether[(@defproc[(fcarray-real-data [arr FCArray]) FlVector]
              @defproc[(fcarray-imag-data [arr FCArray]) FlVector])]{
Return the real and imaginary parts of @racket[arr]'s elements in flonum vectors, in row-major order.
@examples[#:eval typed-eval
                 (define arr (fcarray #[#[1 2+1i] #[3 4+3i]]))
                 (fcarray-real-data arr)
                 (fcarray-imag-data arr)]
}

@defproc[(fcarray-map [f (Float-Complex ... -> Float-Complex)] [arrs FCArray] ...) FCArray]{
Maps the function @racket[f] over the arrays @racket[arrs]. If the arrays do not have the same
shape, they are @tech{broadcast} first. If the arrays do have the same shape, this operation can
be quite fast.

The function @racket[f] is meant to accept the same number of arguments as the number of its
following float-complex array arguments. However, a current limitation in Typed Racket requires
@racket[f] to accept @italic{any} number of arguments. To map a single-arity function, for now,
use @racket[inline-fcarray-map] or @racket[array-map].
}

@defform[(inline-fcarray-map f arrs ...)
         #:contracts ([f  (Float-Complex ... -> Float-Complex)]
                      [arrs  FCArray])]{
Like @racket[inline-array-map], but for float-complex arrays.

@bold{This is currently unavailable in untyped Racket.}
}

@deftogether[(@defproc[(fcarray+ [arr0 FCArray] [arr1 FCArray]) FCArray]
              @defproc[(fcarray* [arr0 FCArray] [arr1 FCArray]) FCArray]
              @defproc*[([(fcarray- [arr FCArray]) FCArray]
                         [(fcarray- [arr0 FCArray] [arr1 FCArray]) FCArray])]
              @defproc*[([(fcarray/ [arr FCArray]) FCArray]
                         [(fcarray/ [arr0 FCArray] [arr1 FCArray]) FCArray])]
              @defproc[(fcarray-scale [arr FCArray] [z Float-Complex]) FCArray]
              @defproc[(fcarray-sqr [arr FCArray]) FCArray]
              @defproc[(fcarray-sqrt [arr FCArray]) FCArray]
              @defproc[(fcarray-conjugate [arr FCArray]) FCArray])]{
Arithmetic lifted to float-complex arrays.
}

@deftogether[(@defproc[(fcarray-real-part [arr FCArray]) FlArray]
              @defproc[(fcarray-imag-part [arr FCArray]) FlArray]
              @defproc[(fcarray-make-rectangular [arr0 FlArray] [arr1 FlArray]) FCArray]
              @defproc[(fcarray-magnitude [arr FCArray]) FlArray]
              @defproc[(fcarray-angle [arr FCArray]) FlArray]
              @defproc[(fcarray-make-polar [arr0 FlArray] [arr1 FlArray]) FCArray])]{
Conversions to and from complex numbers, lifted to flonum and float-complex arrays.
}


@;{==================================================================================================}


@section[#:tag "array:strict"]{Strictness}

@defparam[array-strictness strictness Boolean]{
Determines whether @racketmodname[math/array] functions return strict arrays.
The default value is @racket[#t].

See @secref{array:nonstrict} for a discussion on nonstrict arrays.
}

@defproc[(array-strict? [arr (Array A)]) Boolean]{
Returns @racket[#t] when @racket[arr] is @tech{strict}.
@examples[#:eval typed-eval
                 (define arr
                   (parameterize ([array-strictness #f])
                     (array+ (array 10) (array #[0 1 2 3]))))
                 (array-strict? arr)
                 (array-strict! arr)
                 (array-strict? arr)]
}

@defproc[(array-strict! [arr (Array A)]) Void]{
Causes @racket[arr] to compute and store all of its elements. Thereafter, @racket[arr]
computes its elements by retrieving them from the store.

If @racket[arr] is already strict, @racket[(array-strict! arr)] does nothing.
}

@defform[(array-strict arr)
         #:contracts ([arr (Array A)])]{
An expression form of @racket[array-strict!], which is often more convenient. First evaluates
@racket[(array-strict! arr)], then returns @racket[arr].

This is a macro so that Typed Racket will preserve @racket[arr]'s type exactly. If it were a
function, @racket[(array-strict arr)] would always have the type @racket[(Array A)], even if
@racket[arr] were a subtype of @racket[(Array A)], such as @racket[(Mutable-Array A)].
}

@deftogether[(@defproc[(array-default-strict! [arr (Array A)]) Void]
              @defform[(array-default-strict arr)
                       #:contracts ([arr (Array A)])])]{
Like @racket[array-strict!] and @racket[array-strict], but do nothing when @racket[array-strictness]
is @racket[#f].

Apply one of these to return values from library functions to ensure that users get strict arrays
by default. See @secref{array:nonstrict} for details.
}

@defproc[(build-simple-array [ds In-Indexes] [proc (Indexes -> A)]) (Array A)]{
Like @racket[build-array], but returns an array without storage that is nevertheless considered to be
strict, regardless of the value of @racket[array-strictness].
Such arrays will @italic{not} cache their elements when @racket[array-strict!] or
@racket[array-strict] is applied to them.

Use @racket[build-simple-array] to create arrays that represent simple functions of their indexes.
For example, basic array constructors such as @racket[make-array] are defined in terms of this or its
unsafe counterpart.

@bold{Be careful with this function.} While it creates arrays that are always memory-efficient,
it is easy to ruin your program's performance by using it to define arrays for which element lookup
is permanently expensive. In the wrong circumstances, using it instead of @racket[build-array] can
turn a linear algorithm into an exponential one!

In general, use @racket[build-simple-array] when
@itemlist[@item{Computing an element is never more expensive than computing a row-major index followed
                by applying @racket[vector-ref]. An example is @racket[index-array], which only
                computes row-major indexes.}
          @item{Computing an element is independent of any other array's elements.
                In this circumstance, it is impossible to compose some unbounded number of possibly
                expensive array @tech{procedures}.}
          @item{You can prove that each element will be computed at most once, throughout the
                entire life of your program. This is true, for example, when the result is sent
                only to a function that makes a copy of it, such as @racket[array-lazy] or
                @racket[array->mutable-array].}]
See @racket[array-lazy] for an example of the last circumstance.
}

@defproc[(array-lazy [arr (Array A)]) (Array A)]{
Returns an immutable, @tech{nonstrict} array with the same elements as @racket[arr], but element
computations are cached.

Perhaps the most natural way to use @racket[array-lazy] is for so-called ``dynamic programming,''
or memoizing a function that happens to have a rectangular domain.
For example, this computes the first 10 Fibonacci numbers in linear time:
@interaction[#:eval typed-eval
                    (eval:alts
                     (define: fibs : (Array Natural)
                       (array-lazy
                        (build-simple-array
                         #(10) (λ: ([js : Indexes])
                                 (define j (vector-ref js 0))
                                 (cond [(j . < . 2)  j]
                                       [else  (+ (array-ref fibs (vector (- j 1)))
                                                 (array-ref fibs (vector (- j 2))))])))))
                     (void))
                    (eval:alts
                     fibs
                     (ann (array #[0 1 1 2 3 5 8 13 21 34]) (Array Natural)))]
Because @racket[build-simple-array] never stores its elements, its procedure argument may refer to
the array it returns.
Wrapping its result with @racket[array-lazy] makes each @racket[array-ref] take no more than linear
time; further, each takes constant time when the elements of @racket[fibs] are computed in order.
Without @racket[array-lazy], computing the elements of @racket[fibs] would take exponential time.

Printing a lazy array computes and caches all of its elements, as does applying
@racket[array-strict!] or @racket[array-strict] to it.

Except for arrays returned by @racket[build-simple-array], it is useless to apply @racket[array-lazy]
to a @tech{strict} array.
Using the lazy copy instead of the original only degrades performance.

While it may seem that @racket[array-lazy] should just return @racket[arr] when @racket[arr] is
strict, this would violate the invariant that @racket[array-lazy] returns immutable arrays.
For example:
@interaction[#:eval typed-eval
                    (eval:alts
                     (: array-maybe-lazy (All (A) ((Array A) -> (Array A))))
                     (void))
                    (eval:alts
                     (define (array-maybe-lazy arr)
                       (if (array-strict? arr) arr (array-lazy arr)))
                     (void))
                    (eval:alts
                     (define arr (mutable-array #[0 1 2 3]))
                     (void))
                    (eval:alts
                     (define brr (array-maybe-lazy arr))
                     (void))
                    (eval:alts
                     (array-set! arr #(0) -1000)
                     (void))
                    (eval:alts
                     brr
                     (ann (array #[-1000 1 2 3]) (Array Integer)))]
}


@;{==================================================================================================}


@;{
@section[#:tag "array:unsafe"]{Unsafe Operations}

unsafe-array-ref
unsafe-array-set!
unsafe-array-proc
unsafe-settable-array-set-proc
unsafe-fcarray 
in-unsafe-array-indexes
make-unsafe-array-set-proc
make-unsafe-array-proc
unsafe-build-array
unsafe-build-simple-array
unsafe-vector->array
unsafe-flarray
unsafe-array-transform
unsafe-array-axis-reduce
}

@;{
Don't know whether or how to document these yet:

parallel-array-strict
parallel-array->mutable-array
array/syntax
}

@(close-eval typed-eval)