Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Yearning for APL

195 views
Skip to first unread message

luserdroog

unread,
Jun 14, 2014, 4:19:04 AM6/14/14
to
I found a small pile of printouts that represent all that survives
of the programming I did in college. One, dated 2001, is a C++
template class for dynamic arrays of arbitrary dimension.

I've really only started learning APL quite recently, just a few
months ago. But I have fallen instantly in love with it. It is
*that new sound I've been lookin' for*.

I may have introduced bugs (typos) while re-typing this.


$ cat space.h
// space.h
// template class for n-spaces
// vectors and matrices are special cases of spaces with
// dimension 1 and 2 respectively. so this class is a quick and
// easy data structure for dynamic vectors and matrices.
//
// if the symbol SPACE_DEF is not defined,
// spaces assume the value of 'init' upon creation
//
// if the symbol SPACE_DEF *is* defined,
// spaces do not automatically assume the value 'init'
// attempting to access the value of an undefined space
// will result in the throwing of an exception.
//
//
// push, pop, shift, and unshift work like in PERL
//
// exceptions are thrown when attempting to pop or unshift an empty space
//
// c_array returns a c-style array of the top-level array
// now allocates the array safely!
//
//
// flatten flattens a space into a 1D space
//
// search searches for an element, returns the path
//
// pre_traverse, in_traverse, post_traverse
// perform a traversal, calling a function on each element
// if no function is given, print_el is assumed
//
// slice interprets a 1D space as a series of indices,
// returns a 1D space of all elements on that path.
// final element is the value of the space.
//
// written by M Joshua Ryan
//

#include <stdlib.h>
#include <string.h>

#include <iostream>

template< class T >
static T print_el (T t) { cout << t << ", "; return t; }

template< class T, T init = 0 >
struct space {
T data;
#ifdef SPACE_DEF
bool def;
#endif
int size;
space **link;

/* default/single constructor */
space(void) :
#ifdef SPACE_DEF
def(false),
#endif
data(init), size(0), link(NULL) {}
space(T t) :
#ifdef SPACE_DEF
def(true),
#endif
data(t), size(0), link(NULL) {}

/* copy constructor */
space(space &l) :
#ifdef SPACE_DEF
def(l.def),
#endif
data(l.data), size(l.size), link(l.link) {}

/* array constructor */
space(T *t,int n) :
#ifdef SPACE_DEF
def(false),
#endif
data(init), size(0) {
link = (space **)malloc(n * sizeof(space *));
T dummy;
for (; size < n; size++) {
dummy = t[size];
link[size] = new space(t[size]);
dummy = link[size]->data;
}
}

/* assign */
space & operator= (T t) {
#ifdef SPACE_DEF
def = true;
#endif
data = t;
return *this;
}

/* devolve */
operator T() throw (const char *) {
#ifdef SPACE_DEF
if (def != true) throw "undefined space";
return data;
}

/* return subspace */
/* look 1 level */
space & operator[] (int i) {
if (i > size-1) {
link = (space **)realloc(link, (i+1) * sizeof(space *));
for (; size < i+1; size++)
link[size] = new space;
}
return *link[i];
}

/* look n levels */
space & operator[] (space &s) {
space *r;
r = this;
for (int i = 0; i < s.size; i++)
r = r->link[ s[i] ];
return *r;
}

/* long devolve, ends with init */
T * c_array (void) {
//T *t = (T *)malloc(size+1 * sizeof(T));
T *t = (T *)calloc(size+1, sizeof(T));
T dummy;
int i;
for (i = 0; i < size; i++) {
t[i] = link[i]->data;
dummy = t[i];
}
t[i] = init;
return t;
}

/* flatten */
space & flatten (int level = 1) {
// if (level == 0) return *(new space);
// 0 = special code to retrieve all levels;
// negative numbers mean nothing

space<T> s;
s.push(this->data);
for (int i = 0; i < size; i++) {
s.push(link[i]->data);
if (level == 0)
s.push(link[i]->flatten(0));
else if (level > 1)
s.push(link[i]->flatten(level-1));
}
return *(new space(s));
}

/* slice */
space & slice (space &s) {
space<T> *t = this;
space<T> r;
for (int i = 0; i < s.size; i++) {
t = t->link[ s[i].data ];
r[i].data = t->data;
r[i].def = true;
}
//r.data = t->data; r.def = true;
return *(new space<T> (r));
}

/* add to end of vector */
void push (space s = init) { /* push space on the end of space */
link = (space **)realloc(link, ++size * sizeof(space *));
link[size-1] = new space(s);
}

/* remove from end of vector */
space & pop (void) throw (char *) { /* pop space off the end of space */
if (size < 1) throw "bad pop. empty space";
space *r = link[--size];
link = (space **)realloc(link, size * sizeof(space *));
return *r;
}

/* add to front of vector */
void unshift (space s = init) {
link = (space **)realloc(link, (size+1) * sizeof(space *));
memmove(link+1, link, size * sizeof(space *));
size++;
link[0] = new space(s);
}

/* remove from front of vector */
space & shift (void) throw (char *) {
if (size < 1) throw "bad shift. empty space";
space *r = link[0];
memmove(link, link+1, --size * sizeof(space *));
link = (space **)realloc(link, size * sizeof(space *));
return *r;
}

/* search for element, return path */
space * search (T t) {
if (t == data) return new space<int>;
for (int i = 0; i < size; i++) {
space<int> *s;
if ((s = link[i]->search(t)) != NULL) {
//cout << "found it!" << endl;
s->unshift(t);
return s;
}
}
//cout << "not found" << endl;
return NULL;
}

/* in-order traversal, calls function on each element */
void in_traverse(T (*f)(T) = print_el) {
if (size > 0)
link[0]->in_traverse(f);
#ifdef SPACE_DEF
if (def == true)
#endif
data = (*f)(data);
for (int i = 1; i < size; i++) {
link[i]->in_traverse(f);
}
}

/* pre-order traversal, calls function on each element */
void pre_traverse (T (*f)(T) = print_el) {
#ifdef SPACE_DEF
if (def == true)
#endif
data = (*f)(data);
for (int i = 0; i < size; i++) {
link[i]->pre_traverse(f);
}
}

/* post-order traversal. calls function on each element */
void post_traverse (T (*f)(T) = print_el) {
for (int i = 0; i < size; i++) {
link[i]->post_traverse(f);
}
#ifdef SPACE_DEF
if (def == true)
#endif
data = (*f)(data);
}
};

/*
Tue Jul 10 14:49:05 CDT 2001
*/


luserdroog

unread,
Jun 20, 2014, 2:00:51 AM6/20/14
to
On Saturday, June 14, 2014 3:19:04 AM UTC-5, luserdroog wrote:
> I found a small pile of printouts that represent all that survives
> of the programming I did in college. One, dated 2001, is a C++
> template class for dynamic arrays of arbitrary dimension.
>

I found another program of mine that's *screaming for APL*, I think.
This time in PostScript. It generates tablature for simple barre-chords
on a standard-tuned guitar.

http://codegolf.stackexchange.com/a/3906/2381

Running with ghostscript and the "--" argument, passes
command-line arguments into the program, eg.

04:51 PM:~ 0> gsnd -q -- tabb.ps Em G A C Em G B B Em G A C Em B Em B
e 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---
B 0---3---2---5---0---3---4---4---0---3---2---5---0---4---0---4---
G 0---4---2---5---0---4---4---4---0---4---2---5---0---4---0---4---
D 2---5---2---5---2---5---4---4---2---5---2---5---2---4---2---4---
A 2---5---0---3---2---5---2---2---2---5---0---3---2---2---2---2---
E 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---

A good deal of the program goes to implementing array functions,
which it then uses to perform the *real* task.

%!PS
<< %axioms and operations
/t{2 2 1} %major tetrachord
/m{t t 2} %mixolydian mode
/u{2 1 2} %minor tetrachord
/a{u u} %aolian mode
/s{m m t} %2.5-octave mixolydian intervals
/r{3 1 roll}
/${[exch 0 exch{1 index add}forall]}%running sum: convert (relative)intervals to (abstract)fretstops
/+{[r exch{1 index add exch}forall pop]} %scale array by scalar
/@{[r{2 copy get r pop}forall pop]} %select array elements from array of indices
/&{0 1 3 index length 1 sub{ %array2 += array1
2 copy get 3 index 2 index get add 3 copy put pop pop}for exch pop}
>>begin<< %map ascii values to scaling functions
65[a]$ %generate fretstops of the A aolian scale to assign scalars to note names
[0 0 0 0 -12 -12 -12]& %drop E F and G down an octave
{[exch/+ cvx]cvx 1 index 1 add}forall pop %generate the pairs 'A'->{0 +}, 'B'->{2 +}
35{1 +} %'#'-> scale up by one
98{-1 +} %'b'-> scale down by one
109{dup 4 2 copy get 1 sub put} %'m'-> tweak the 'third' down by one
%generate chord pattern from (string)
/*{[s]$ %generate fretstops of the E mixolydian scale
[1 4 8 11 13 15 18] %A-shape figured bass: IV chord of E mixolydian
-1 + %convert scale degrees to array indices
@ %generate chord template by selecting indices from mixolydian scale
exch{load exec}forall %execute ascii values, scaling the pattern
dup 0 get 0 ge{0}{1}ifelse 6 getinterval %discard first note if it has fallen off the bottom
[0 -5 -10 -15 -19 -24]&} %subtract the string offsets
>>begin %activate definitions
%(A)* pstack()= clear %[0 0 2 2 2 0]
%(B)* pstack()= clear %[2 2 4 4 4 2]
%(F#)* pstack()= clear %[2 4 4 3 2 2]
%(Abm)* pstack()= %[4 6 6 4 4 4]
[ARGUMENTS{*}forall] %convert array of strings to array of patterns
[(E)(A)(D)(G)(B)(e)] %array of string names
6{ %for each "string"
[exch cvx exec print( )print] %pop string name and print with space
exch %put names behind numbers
[exch{ %for each "chord"
[exch cvx exec( )cvs print(---)print] %pop number, convert, print with trailing hyphens
}forall] %zip up chord array for next iteration
()= %print a newline
exch %put numbers behind names
}repeat

luserdroog

unread,
Jul 6, 2014, 6:33:00 PM7/6/14
to
Here's the setup part in APL, calculating an A major chord from the
E mixolydian scale.

t←2 2 1
m←t,t,2
u←2 1 2
a←u,u
s←m,m,t
+/s
29
+\s
2 4 5 7 9 10 12 14 16 17 19 21 22 24 26 28 29
s
2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 2 1
+\0,s
0 2 4 5 7 9 10 12 14 16 17 19 21 22 24 26 28 29
0,+\s
0 2 4 5 7 9 10 12 14 16 17 19 21 22 24 26 28 29
(0,+\s)[1 4 8 11 13 15 18]
0 5 12 17 21 24 29
(0,+\s)[fb←1 4 8 11 13 15 18]+0 ¯5 ¯10 ¯15 ¯19 ¯24
LENGTH ERROR
(0,+\s)[fb←1 4 8 11 13 15 18]+0 ¯5 ¯10 ¯15 ¯19 ¯24

6<⍳⍴s
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
6>⍳⍴s
1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
6≥⍳⍴s
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
af←(0,+\s)[fb]
af
0 5 12 17 21 24 29
(6≥⍳⍴af)/af
0 5 12 17 21 24
((6≥⍳⍴af)/af)+0 ¯5 ¯10 ¯15 ¯19 ¯24
0 new messages