summaryrefslogtreecommitdiff
path: root/hybrids.c
blob: 00977da62089ace08e69a7d5fc5485aa21ad3279 (plain) (blame)
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
#include <u.h>
#include <libc.h>
#include <bio.h>

#include "apl9.h"

Rune primhybridnames[] = L"/\\⌿⍀";

fndyad hybridfunctiondefs[] = {
	0, /* / */
	0, /* \ */
	0, /* ⌿ */
	0, /* ⍀ */
};

opmonad hybridoperatordefs[] = {
	opReduceLast, /* / */
	opScanLast, /* \ */
	opReduceFirst, /* ⌿ */
	opScanFirst, /* ⍀ */
};

/* function definitions */

/* operator definitions */
Array *
opReduceLast(Datum *lefto, Array *left, Array *right)
{
	if(left)
		throwerror(L"left argument to f/", ENotImplemented);

	right = fnTranspose(right);
	Array *tmp = opReduceFirst(lefto, left, right);
	Array *res = fnTranspose(tmp);
	freearray(right);
	freearray(tmp);
	return res;
}

Array *
opScanLast(Datum *lefto, Array *left, Array *right)
{
	if(left)
		throwerror(L"f\ doesn't take a left argument", ESyntax);

	right = fnTranspose(right);
	Array *tmp = opScanFirst(lefto, left, right);
	Array *res = fnTranspose(tmp);
	freearray(right);
	freearray(tmp);
	return res;
}

Array *
opReduceFirst(Datum *lefto, Array *left, Array *right)
{
	if(left)
		throwerror(L"left argument to f⌿", ENotImplemented);

	if(right->rank == 0)
		return fnSame(right);

	int n = right->shape[0];
	int io = currentsymtab->io;
	if(n == 0)
		throwerror(L"Can't figure out identity element", ENotImplemented);

	Array *result = allocarray(AtypeArray, right->rank - 1, right->size / n);
	for(int i = 0; i < right->rank-1; i++)
		result->shape[i] = right->shape[i+1];

	Array *index = allocarray(AtypeArray, 1, right->rank);
	index->shape[0] = right->rank;
	Array *tmp = mkscalarint(n);
	index->arraydata[0] = fnIndexGenerator(tmp);
	freearray(tmp);
	for(int i = 1; i < index->size; i++)
		index->arraydata[i] = mkscalarint(io);

	for(int i = 0; i < result->size; i++){
		for(int j = index->size - 1; index->arraydata[j]->intdata[0] == io + right->shape[j]; j--){
			index->arraydata[j]->intdata[0] = io;
			index->arraydata[j-1]->intdata[0]++;
		}
		Array *vector = fnIndex(index, right);
		result->arraydata[i] = arrayitem(vector, n-1);
		for(int j = n-2; j >= 0; j--){
			Array *argL = arrayitem(vector, j);
			Array *argR = result->arraydata[i];
			result->arraydata[i] = runfunc(lefto->func, argL, argR);
			freearray(argL);
			freearray(argR);
		}
		index->arraydata[index->size-1]->intdata[0]++;
	}
	freearray(index);

	return result;
}

Array *
opScanFirst(Datum *lefto, Array *left, Array *right)
{
	if(left)
		throwerror(L"f⍀ doesn't take a left argument", ESyntax);

	Array *result = allocarray(AtypeArray, right->rank, right->size);
	for(int i = 0; i < right->rank; i++)
		result->shape[i] = right->shape[i];

	int n = result->shape[0];
	int m = result->size / n;
	for(int i = 0; i < n; i++){
		Array *len = mkscalarint(i + 1);
		Array *index = fnIndexGenerator(len);
		Array *ix = fnEnclose(index);
		Array *subarr = fnIndex(ix, right);
		Array *subres = opReduceFirst(lefto, left, subarr);
		for(int j = 0; j < m; j++)
			result->arraydata[i*m + j] = arrayitem(subres, j);
		freearray(len);
		freearray(index);
		freearray(ix);
		freearray(subarr);
		freearray(subres);
	}
	return result;
}