org.akraievoy.cnet.gen.domain.LocationGeneratorRecursive.java Source code

Java tutorial

Introduction

Here is the source code for org.akraievoy.cnet.gen.domain.LocationGeneratorRecursive.java

Source

/*
 Copyright 2011 Anton Kraievoy akraievoy@gmail.com
 This file is part of Holonet.
    
 Holonet is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
 Holonet is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with Holonet. If not, see <http://www.gnu.org/licenses/>.
 */

package org.akraievoy.cnet.gen.domain;

import com.google.common.base.Optional;
import org.akraievoy.cnet.gen.vo.*;

public class LocationGeneratorRecursive extends LocationGeneratorBase {
    protected final EntropySource eSource;
    protected final WeightedEventModel eventModel;

    protected double dimensionRatio = 1.5;

    protected double[] weights;
    protected double cutoff;
    protected int fuzzyness = 6;

    public LocationGeneratorRecursive(final EntropySource eSource) {
        this.eSource = eSource;
        this.eventModel = new WeightedEventModelBase(Optional.of("locationsRecursive"));
    }

    public void setDimensionRatio(double dimensionRatio) {
        this.dimensionRatio = dimensionRatio;
    }

    public double getDimensionRatio() {
        return dimensionRatio;
    }

    public int getFuzzyness() {
        return fuzzyness;
    }

    public void setFuzzyness(int fuzzyness) {
        this.fuzzyness = fuzzyness;
    }

    public void run() {
        eSource.diagnoseSeed(this.getClass().getSimpleName());
        computeWeights();
    }

    protected void computeWeights() {
        weights = new double[cells];

        final double ratio = Math.pow(2, dimensionRatio - 2);

        final double[] curWeights = new double[cells];
        int curGridSize = 1;
        curWeights[0] = 1;

        final double[] subGrid = new double[9];
        final double[] subWeights = new double[4];
        final int totalIterations = (int) Math.round(Math.log(gridSize) / Math.log(2));
        for (int iter = 0; iter < totalIterations; iter++) {
            for (int y = 0; y < curGridSize; y++) {
                for (int x = 0; x < curGridSize; x++) {
                    produceSubGrid(y, x, curGridSize, curWeights, subGrid);
                    produceSubWeights(subGrid, subWeights);
                    randomizeSubWeights(eSource, ratio, subWeights, subGrid[4]);
                    zerifySubWeights(subWeights, iter / (double) totalIterations);
                    storeSubWeights(subWeights, y, x);
                }
            }

            curGridSize *= 2;
            System.arraycopy(weights, 0, curWeights, 0, curGridSize * gridSize);
        }

        for (int i = 0; i < cells; i++) {
            if (weights[i] > 0) {
                eventModel.add(i, weights[i]);
            }
        }
    }

    protected void zerifySubWeights(double[] subWeights, double completion) {
        cutoff = completion / fuzzyness;
        if (cutoff == 0) {
            return;
        }

        for (int i = 0; i < 4; i++) {
            int zeroed = 0;

            double minNotZeroValue = Double.POSITIVE_INFINITY;
            int minNotZeroIndex = -1;
            for (int j = 0; j < 4; j++) {
                final double value = subWeights[j];
                if (value == 0) {
                    zeroed++;
                    continue;
                }

                if (minNotZeroValue > value) {
                    minNotZeroValue = value;
                    minNotZeroIndex = j;
                }
            }

            if (zeroed >= 3 || minNotZeroValue > cutoff) {
                break;
            }

            subWeights[minNotZeroIndex] = 0;
            zeroed++;

            for (int j = 0; j < 4; j++) {
                if (subWeights[j] != 0) {
                    subWeights[j] += minNotZeroValue / (4 - zeroed);
                }
            }
        }
    }

    protected void storeSubWeights(double[] subWeights, int y, int x) {
        final int pos = y * 2 * gridSize + x * 2;
        weights[pos] = subWeights[0];
        weights[pos + 1] = subWeights[1];
        weights[pos + gridSize] = subWeights[2];
        weights[pos + gridSize + 1] = subWeights[3];
    }

    protected void randomizeSubWeights(EntropySource eSource, double ratio, double[] subWeights,
            double totalWeight) {
        final double removeRatio = (1 - ratio) * 2;
        if (removeRatio > 0) {
            subWeights[0] *= 1 - removeRatio * eSource.nextDouble();
            subWeights[1] *= 1 - removeRatio * eSource.nextDouble();
            subWeights[2] *= 1 - removeRatio * eSource.nextDouble();
            subWeights[3] *= 1 - removeRatio * eSource.nextDouble();

            final double weightRandSum = subWeights[0] + subWeights[1] + subWeights[2] + subWeights[3];

            final double renorm = 4 * ratio * totalWeight / weightRandSum;

            subWeights[0] *= renorm;
            subWeights[1] *= renorm;
            subWeights[2] *= renorm;
            subWeights[3] *= renorm;
        }
    }

    protected void produceSubWeights(double[] subGrid, double[] subWeights) {
        subWeights[0] = 0.001 + 0.25 * (subGrid[0] + subGrid[1] + subGrid[3] + subGrid[4]);
        subWeights[1] = 0.001 + 0.25 * (subGrid[1] + subGrid[2] + subGrid[4] + subGrid[5]);
        subWeights[2] = 0.001 + 0.25 * (subGrid[3] + subGrid[4] + subGrid[6] + subGrid[7]);
        subWeights[3] = 0.001 + 0.25 * (subGrid[4] + subGrid[5] + subGrid[7] + subGrid[8]);
    }

    protected void produceSubGrid(int y, int x, int curGridSize, double[] curWeights, double[] subGrid) {
        int pos = y * gridSize + x;

        final boolean yG = y > 0;
        final boolean xG = x > 0;
        final boolean xL = x < curGridSize - 1;
        final boolean yL = y < curGridSize - 1;

        if (yG && xG) {
            subGrid[0] = curWeights[pos - gridSize - 1];
        } else if (xG) {
            subGrid[0] = curWeights[pos - 1];
        } else if (yG) {
            subGrid[0] = curWeights[pos - gridSize];
        } else {
            subGrid[0] = curWeights[pos];
        }

        if (yG) {
            subGrid[1] = curWeights[pos - gridSize];
        } else {
            subGrid[1] = curWeights[pos];
        }

        if (yG && xL) {
            subGrid[2] = curWeights[pos - gridSize + 1];
        } else if (yG) {
            subGrid[2] = curWeights[pos - gridSize];
        } else if (xL) {
            subGrid[2] = curWeights[pos + 1];
        } else {
            subGrid[2] = curWeights[pos];
        }

        if (xG) {
            subGrid[3] = curWeights[pos - 1];
        } else {
            subGrid[3] = curWeights[pos];
        }

        subGrid[4] = curWeights[pos];

        if (xL) {
            subGrid[5] = curWeights[pos + 1];
        } else {
            subGrid[5] = curWeights[pos];
        }

        if (yL && xG) {
            subGrid[6] = curWeights[pos + gridSize - 1];
        } else if (xG) {
            subGrid[6] = curWeights[pos - 1];
        } else if (yL) {
            subGrid[6] = curWeights[pos + gridSize];
        } else {
            subGrid[6] = curWeights[pos];
        }

        if (yL) {
            subGrid[7] = curWeights[pos + gridSize];
        } else {
            subGrid[7] = curWeights[pos];
        }

        if (yL && xL) {
            subGrid[8] = curWeights[pos + gridSize + 1];
        } else if (xL) {
            subGrid[8] = curWeights[pos + 1];
        } else if (yL) {
            subGrid[8] = curWeights[pos + gridSize];
        } else {
            subGrid[8] = curWeights[pos];
        }
    }

    public Point chooseLocation(final EntropySource eSource) {
        final int freeIndex = eventModel.generate(eSource, true, null);
        final Point point = index2p(freeIndex);

        return point;
    }

    public double getDensity(Point location) {
        return weights[p2index(location)];
    }
}