001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.core.intmatrix.calculation;
025    
026    import org.ujmp.core.Matrix;
027    import org.ujmp.core.MatrixFactory;
028    import org.ujmp.core.exceptions.MatrixException;
029    
030    /**
031     * Creates a magic square matrix. The sums of all rows and columns are equal.
032     * This code is taken from JAMA.
033     */
034    public class Magic extends AbstractIntCalculation {
035            private static final long serialVersionUID = -2372321035531662110L;
036    
037            private final Matrix magic;
038    
039            public Magic(Matrix matrix, int size) {
040                    super(matrix);
041                    this.magic = magic(size);
042            }
043    
044            public int getInt(long... coordinates) throws MatrixException {
045                    return magic.getAsInt(coordinates);
046            }
047    
048            public static Matrix magic(int n) {
049                    final int[][] M = new int[n][n];
050    
051                    // Odd order
052                    if ((n % 2) == 1) {
053                            int a = (n + 1) / 2;
054                            int b = (n + 1);
055    
056                            for (int j = 0; j < n; j++) {
057                                    for (int i = 0; i < n; i++) {
058                                            M[i][j] = n * ((i + j + a) % n) + ((i + 2 * j + b) % n) + 1;
059                                    }
060                            }
061    
062                            // Doubly Even Order
063                    } else if ((n % 4) == 0) {
064                            for (int j = 0; j < n; j++) {
065                                    for (int i = 0; i < n; i++) {
066                                            if (((i + 1) / 2) % 2 == ((j + 1) / 2) % 2) {
067                                                    M[i][j] = n * n - n * i - j;
068                                            } else {
069                                                    M[i][j] = n * i + j + 1;
070                                            }
071                                    }
072                            }
073    
074                            // Singly Even Order
075                    } else {
076                            int p = n / 2;
077                            int k = (n - 2) / 4;
078    
079                            Matrix A = magic(p);
080    
081                            for (int j = 0; j < p; j++) {
082                                    for (int i = 0; i < p; i++) {
083                                            int aij = A.getAsInt(i, j);
084                                            M[i][j] = aij;
085                                            M[i][j + p] = aij + 2 * p * p;
086                                            M[i + p][j] = aij + 3 * p * p;
087                                            M[i + p][j + p] = aij + p * p;
088                                    }
089                            }
090    
091                            for (int i = 0; i < p; i++) {
092                                    for (int j = 0; j < k; j++) {
093                                            int t = M[i][j];
094                                            M[i][j] = M[i + p][j];
095                                            M[i + p][j] = t;
096                                    }
097    
098                                    for (int j = n - k + 1; j < n; j++) {
099                                            int t = M[i][j];
100                                            M[i][j] = M[i + p][j];
101                                            M[i + p][j] = t;
102                                    }
103                            }
104                            int t = M[k][0];
105                            M[k][0] = M[k + p][0];
106                            M[k + p][0] = t;
107                            t = M[k][k];
108                            M[k][k] = M[k + p][k];
109                            M[k + p][k] = t;
110                    }
111                    return MatrixFactory.linkToArray(M);
112            }
113    
114    }