# 3-D Antiferromagnetism

A while ago, we had a challenge related to antiferromagnetism (AF) in two dimensions. Now, on a 2-d square lattice, antiferromagnetic is antiferromagnetic, and that is all there is to it. Moving to other lattice types or higher dimensionality, things get more interesting. Here, we will explore the second route: magnetic order on the 3-d cubic lattice1.

We will consider the following spin patterns, as illustrated in the figure. The cubes are repeated periodically in every direction (“periodic boundary conditions”).

• G-type is the most straightforward generalization from 2-D AF: antiferromagnetic in all directions
• A-type: antiferromagnetically coupled ferromagnetic planes
• C-type: ferromagnetically coupled antiferromagnetic planes (a.k.a “checkerboard”)
• D-type: criss-crossing stripes
• E-type and F-type:ferrimagnetic planes”?
• B-type is ferromagnetic (FM) order adapted from E. Dagotto, Nanoscale phase separation and colossal magnetoresistance

# The challenge

Your code should take a string as input specifying a magnetic order and a lattice plane, and output the spin arrangement on that plane, in the orientation specified below. Output should be “drawn“ in some sense: writing to STDOUT, graphical output, or similar; a function returning a string is not enough.

You must support at least A-, C-, and G-type (the more familiar AF arrangements); B-, E-, and F-type may be supported optionally. Your score will be code length per order type supported.

## Input

Input will be of the form S (a b c), i.e., a token S specifying the order type, a space, and three integers a,b,c defining a lattice plane, enclosed in parentheses and delimited by spaces.

The string S will be either “AF-T” with T ∈ {A, C, D, E, F, G} for the antiferromagnetic cases, or “FM” in the ferromagnetic case (B).

We define the following coordinate system relative to the figure: the x-axis points to the right, the y-axis into the screen, and the z-axis upwards; the origin is the lower left front corner of the cube, and the lattice parameter (the side length of the cube) will be 1.

For simplicity, exactly one of the integers a,b,c will be nonzero. The plane of projection is perpendicular to the corresponding axis and displaced from the origin by that number of unit cells.2 To get the proper orientation, look along the axis of displacement in positive/negative direction according to the displacement, and rotate such that the first in-plane axis (alphabetically: y for the yz-plane, x otherwise) increases to the right. Examples are given below.

## Output

On the selected plane, the spins are arranged on a square lattice. Your code should draw 2×2 spins (the “magnetic unit cell”) on this plane, taking into account the periodicity and the proper orientation.

### A ↑ by any other name …

Spin “up” and “down” are just names,3 and I do not want to limit your artistic freedom. Choose any (visually distinguishable) symbols for the spin directions you like, they only have to be consistent and laid out on a “square” lattice (as rectangular as necessary according to output format). You can use ASCII/Unicode art, graphical output, what have you. Leading or trailing white space does not matter.

## Examples of input, valid output, and orientation

A (0 0 1)  C (1 0 0)  D (0 0 2)  E (0 1 0)  F (0 -2 0)  G (0 0 7)
- -       ↓  ↑        ud         0 1       ->  ->       🔫 •
- -       ↓  ↑        ud         1 0       ->  <-       • 🔫

--> x      --> y      --> x      ^ z         --> x       --> x
|          |          |          |           |           |
V y        V z        V y        --> x       V z         V y


# Scoring

Your score is B/O, the length B of your code in bytes divided by the number of patterns O your code supports (O is between 3 and 7). Smallest score wins.

In your answer, please indicate (i) code length, (ii) supported orders, and (iii) sample output, and (iv) the correspondence of your symbols with + and - in the figure, if yours are different.

1. Which is the analogue of the square lattice in three dimensions. The general term would be “hypercubic”.

2. They are a perverted variation of Miller indices.

3. We are being strictly non-relativistic here.

# Ruby Rev 1, 176/7 = 25.14

Problem with negative inputs fixed: m>>9&2 shifts the characters by 2 when m is negative.

Magic strings with non-ASCII characters proved problematic: they produced syntax errors. So I just compressed the data to a hexadecimal number instead.

a=gets.delete("()").split
m=e=0
4.times{|i|m+=b=a[i].to_i;b>0&&e=i-1}
4.times{|c|print 0xFFF9935871769>>568-a.ord*8+(" j\204\316"[c-(m>>9&2)].ord>>e*3&7^m%2<<e)&1,"
"[c%2]}


# Ruby Rev 0, 174/7 = 24.86

work in progress. I just realized I missed a rule: I have to flip the output vertically when the input is negative. Once checked and clarified I will golf the magic strings / arrays down to single characters.

a=gets.delete("()").split
m=e=0
4.times{|i|m+=b=a[i].to_i;b>0&&e=i-1}
" j\204\316".bytes{|c|print [15,255,153,53,135,23,105][a.ord-65]>>(c>>e*3&7^m%2<<e)&1,c==106?"\n":''}


The first magic string contains 4 bytes, corresponding to the first, second, third and 4th symbol to be printed. Each is a 3-digit octal number indicating which bit of the data in the array should be displayed. The table looks like this. Note that the odd values differ from the even ones by a power of 2 so only the even values need be stored. Fortunately the z values never exceed 3, so it's possible to get the 3 octal digits into 1 byte.

nonzero digit    x    y    z
02   45   01
even            46   01   23

13   67   45
odd             57   23   67


Output

I use 1 for +, 0 for - . I didnt bother with the output for B because it's just plain 1's.

A 1 0 0
11
00
A 2 0 0
11
00
A 0 1 0
00
11
A 0 2 0
00
11
A 0 0 1
00
00
A 0 0 2
11
11

C 1 0 0
01
01
C 2 0 0
10
10
C 0 1 0
01
01
C 0 2 0
10
10
C 0 0 1
10
01
C 0 0 2
10
01

D 1 0 0
00
10
D 2 0 0
11
10
D 0 1 0
00
10
D 0 2 0
11
10
D 0 0 1
11
00
D 0 0 2
10
10

E 1 0 0
10
01
E 2 0 0
11
00
E 0 1 0
01
10
E 0 2 0
00
11
E 0 0 1
00
01
E 0 0 2
11
10

F 1 0 0
10
00
F 2 0 0
11
10
F 0 1 0
00
10
F 0 2 0
10
11
F 0 0 1
10
00
F 0 0 2
11
10

G 1 0 0
01
10
G 2 0 0
10
01
G 0 1 0
10
01
G 0 2 0
01
10
G 0 0 1
01
10
G 0 0 2
10
01


# Octave, 809/7 ≈ 115.57

This is a reference implementation supporting all 7 order types (not quite, since it does not parse the input string), ungolfed.

Output for all distinct inputs is available for download. Assuming the implementation is correct, there are 13 distinct outputs, two of which are unique; one more occurs twice; all others at least four times.

format plus "+-."

A = ones(2,2,2);
A(:,:,2) = -1;

B = ones(2,2,2);

C(:,:,1) = [ 1 -1; -1  1];
C(:,:,2) = C(:,:,1);

D(:,:,1) = [ 1  1; -1 -1];
D(:,:,2) = D(:,:,1)';

E(:,:,1) = [ 1  1;  1 -1];
E(:,:,2) = -E(:,:,1);

F(:,:,1) = E(:,:,1);
F(:,:,2) = [ 1 -1; -1 -1];

G(:,:,1) = C(:,:,1);
G(:,:,2) =-G(:,:,1);

function SP = afmproj(S, idx)
dim = find(idx)(1);
idx = idx(dim);
sgn = sign(idx);
idx = mod(idx, 2) + 1;

switch dim
case 1
SP = S(idx,:,:); flp = sgn==+1;
case 2
SP = S(:,idx,:); flp = sgn==-1;
case 3
SP = S(:,:,idx); flp = sgn==+1;
endswitch

SP = rot90(reshape(SP,2,2));

if flp
SP = flipud(SP);
endif
endfunction

function afmproj_pretty(Str, S, idx)
printf('%s (%2i %2i %2i)\n', Str, idx);
disp(afmproj(S, idx));
disp('')
endfunction

• Cool. I've looked through your outputs for A and F, that's where i realised I'd missed the rule about looking along the axis in the positive/negative direction. Could you provide the outputs in an easier format? Individual 6-bit files take about 10-15 seconds each to preview, a single file / document would be easier to manage. – Level River St Sep 29 '15 at 23:53
• @steveverrill I added a file to the link containing all the inputs and outputs in a table, I hope that works for you. I guess I was thinking more of automated than manual checking (note that you can download the whole shebang in a zip file). – xebtl Sep 30 '15 at 6:52