com.actelion.research.calc.SelfOrganizedMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright 2017 Idorsia Pharmaceuticals Ltd., Hegenheimermattweg 91, CH-4123 Allschwil, Switzerland
*
* This file is part of DataWarrior.
*
* DataWarrior 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.
*
* DataWarrior is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of 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 DataWarrior.
* If not, see http://www.gnu.org/licenses/.
*
* @author Thomas Sander
*/
package com.actelion.research.calc;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class SelfOrganizedMap extends DataProcessor {
private static final int cModeNeighbourhoodMask = 7;
public static final int cModeNeighbourhoodGaussean = 0;
public static final int cModeNeighbourhoodMexicanHat = 1;
public static final int cModeNeighbourhoodLinear = 2;
public static final int cModeTopologyUnlimited = 8;
public static final int cModeGrowDuringOptimization = 16;
public static final int cModeFastBestMatchFinding = 32;
protected SOMController mController;
protected Object[][] mReferenceVector;
protected int mNX,mNY,mMode;
private int mCycle,mCyclesPerNode,mConstantInfluenceCycles,mThreadCount,
mInputVectorCount,mInputVectorIndex,mCorrectQuickBestMatches;
private boolean mFindBestMatchQuickly;
private double mMaxRange,mDiagonal;
protected double[][] mInfluence;
private Point[] mLastBestMatch;
private int[][] mSMPSOMIndex,mSMPInfluenceIndex;
private Rectangle mSMPInfluenceRect;
private ExecutorService mExecutor;
private SOMWorker[] mSOMWorker;
/**
* Constructor to be used if SOM interna are read from a SOM file with read()
*/
public SelfOrganizedMap() {
initializeSMP();
}
public SelfOrganizedMap(int nx, int ny, int mode) {
initializeSMP();
initializeReferenceVectors(nx, ny, mode);
}
public void initializeReferenceVectors(int nx, int ny, int mode) {
mNX = nx;
mNY = ny;
mMode = mode;
mReferenceVector = new Object[nx][ny];
if (mThreadCount != 1)
mSMPSOMIndex = getSMPArraySplitting(nx, ny);
}
private void initializeSMP() {
mThreadCount = Runtime.getRuntime().availableProcessors();
if (mThreadCount != 1) {
mExecutor = Executors.newFixedThreadPool(mThreadCount);
mSOMWorker = new SOMWorker[mThreadCount];
for (int t=0; t dissimilarity) {
minDissimilarity = dissimilarity;
bestMatch = mReferenceVector[x][y];
}
}
}
sum += Math.sqrt(getDissimilarity(randomVector, bestMatch));
}
return sum / (double)randomCount;
}
protected double getTimeInfluence(double time) {
return 1.0 - time;
}
protected double getNeighbourInfluence(int dx, int dy, double time) {
// distance is normalized by map diagonal
double distance = Math.sqrt(dx*dx+dy*dy)/mDiagonal;
double f = 0.0;
switch (mMode & cModeNeighbourhoodMask) {
case cModeNeighbourhoodGaussean:
f = Math.exp(distance * distance * Math.log(0.001) / (mMaxRange * mMaxRange));
return (f < 0.001) ? 0.0 : f;
case cModeNeighbourhoodMexicanHat:
f = 1.0 - distance * distance / (mMaxRange * mMaxRange);
return (f < 0.0) ? 0.0 : f;
case cModeNeighbourhoodLinear:
f = 1.0 - distance / mMaxRange;
return (f < 0.0) ? 0.0 : f;
}
return f;
}
/**
* Calculates start and end array indices for individual threads.
* @param xCount
* @param yCount
*/
private int[][] getSMPArraySplitting(int xCount, int yCount) {
int nodeCount = xCount * yCount;
int nodesPerThread = nodeCount / mThreadCount;
int remainingNodes = nodeCount % mThreadCount;
int[][] index = new int[mThreadCount+1][2];
for (int i=0; i= xCount) {
dx -= xCount;
dy++;
}
index[i+1][0] = index[i][0] + dx;
index[i+1][1] = index[i][1] + dy;
}
return index;
}
private void optimize(int startCycle, int cycles) {
mInfluence = null;
for (int cycle=startCycle; cycle= mInputVectorCount)
mInputVectorIndex = 0;
}
}
protected void applyInfluences(Object inputVector, Point location) {
// apply to every node shifts caused by assigned input vector
int maxRange = (int)(mDiagonal * mMaxRange);
int x1 = location.x-maxRange;
int x2 = location.x+maxRange;
int y1 = location.y-maxRange;
int y2 = location.y+maxRange;
if ((mMode & cModeTopologyUnlimited) != 0) {
if (x2 - x1 >= mNX) {
x1 = 0;
x2 = mNX;
}
if (y2 - y1 >= mNY) {
y1 = 0;
y2 = mNY;
}
if (mThreadCount != 1 && maxRange != 0) {
if (mSMPInfluenceRect == null || mSMPInfluenceRect.width != x2-x1 || mSMPInfluenceRect.height != y2-y1)
mSMPInfluenceIndex = getSMPArraySplitting(x2-x1, y2-y1);
mSMPInfluenceRect = new Rectangle(x1, y1, x2-x1, y2-y1);
applyInfluencesSMP(inputVector, location);
}
else {
for (int x=x1; x mNX / 2)
dx = mNX - dx;
if (dy > mNY / 2)
dy = mNY - dy;
if (mInfluence[dx][dy] > 0.0)
updateReference(inputVector, mReferenceVector[x<0?x+mNX:x mNX)
x2 = mNX;
if (y1 < 0)
y1 = 0;
if (y2 > mNY)
y2 = mNY;
if (mThreadCount != 1 && maxRange != 0) {
mSMPInfluenceRect = new Rectangle(x1, y1, x2-x1, y2-y1);
mSMPInfluenceIndex = getSMPArraySplitting(x2-x1, y2-y1);
applyInfluencesSMP(inputVector, location);
}
else {
for (int x=x1; x 0.0)
updateReference(inputVector, mReferenceVector[x][y], mInfluence[dx][dy]);
}
}
}
}
}
protected void applyInfluencesSMP(Object inputVector, Point location) {
CountDownLatch doneSignal = new CountDownLatch(mThreadCount);
for (SOMWorker worker:mSOMWorker) {
worker.initApplyInfluences(inputVector, location, doneSignal);
mExecutor.execute(worker);
}
try {
doneSignal.await();
}
catch (InterruptedException e) {}
}
public Point findBestMatchLocation(Object inputVector) {
if (inputVector == null)
return null;
// used internally during map optimization
// and externally to assign any vector to location on completed map
if (mThreadCount != 1)
return findBestMatchLocationSMP(inputVector);
Point minLocation = new Point(-1, -1);
double minDissimilarity = Double.POSITIVE_INFINITY;
for (int x=0; x dissimilarity) {
minDissimilarity = dissimilarity;
minLocation.x = x;
minLocation.y = y;
}
}
}
return minLocation;
}
public Point findBestMatchLocationSMP(Object inputVector) {
if (inputVector == null)
return null;
CountDownLatch doneSignal = new CountDownLatch(mThreadCount);
for (SOMWorker worker:mSOMWorker) {
worker.initFindBestMatch(inputVector, doneSignal);
mExecutor.execute(worker);
}
try {
doneSignal.await();
}
catch (InterruptedException e) {}
Point minLocation = new Point(-1, -1);
double minDissimilarity = Double.POSITIVE_INFINITY;
for (SOMWorker worker:mSOMWorker) {
double dissimilarity = worker.getBestMatchDissimilarity();
if (minDissimilarity > dissimilarity) {
minDissimilarity = dissimilarity;
minLocation = worker.getBestMatchLocation();
}
}
return minLocation;
}
public Point findBestMatchLocationQuickly(Object inputVector) {
if (inputVector == null)
return null;
// used internally during map optimization
// and externally to assign any vector to location on completed map
Point minLocation = mLastBestMatch[mInputVectorIndex];
double minDissimilarity = getDissimilarity(mReferenceVector[minLocation.x][minLocation.y], inputVector);
boolean[][] locationChecked = new boolean[mNX][mNY];
locationChecked[minLocation.x][minLocation.y] = true;
boolean found;
do {
//System.out.print("["+minLocation.x+","+minLocation.y+"];");
Point p = minLocation;
found = false;
for (int xdif=-1; xdif<2; xdif++) {
int x = p.x + xdif;
if ((mMode & cModeTopologyUnlimited) != 0) {
if (x < 0)
x = mNX - 1;
else if (x >= mNX)
x = 0;
}
else if (x < 0 || x >= mNX)
continue;
for (int ydif=-1; ydif<2; ydif++) {
int y = p.y + ydif;
if ((mMode & cModeTopologyUnlimited) != 0) {
if (y < 0)
y = mNY - 1;
else if (y >= mNY)
y = 0;
}
else if (y < 0 || y >= mNY)
continue;
if (!locationChecked[x][y]) {
locationChecked[x][y] = true;
double dissimilarity = getDissimilarity(mReferenceVector[x][y], inputVector);
if (minDissimilarity > dissimilarity) {
minDissimilarity = dissimilarity;
minLocation = new Point(x, y);
found = true;
}
}
}
}
} while (found);
//System.out.println();
return minLocation;
}
public double[] findExactMatchLocation(Object inputVector) {
if (inputVector == null)
return null;
Point p = findBestMatchLocation(inputVector);
double[] location = new double[3];
location[0] = p.x;
location[1] = p.y;
int x1 = p.x - 1;
int x2 = p.x + 1;
int y1 = p.y - 1;
int y2 = p.y + 1;
if ((mMode & cModeTopologyUnlimited) != 0) {
if (x1 == -1)
x1 += mNX;
if (x2 == mNX)
x2 = 0;
if (y1 == -1)
y1 += mNY;
if (y2 == mNY)
y2 = 0;
}
double dis0 = Math.sqrt(getDissimilarity(mReferenceVector[p.x][p.y], inputVector));
if (dis0 > 0.0) {
if (x1 == -1)
location[0] += 0.5 * dis0 / Math.sqrt(getDissimilarity(mReferenceVector[x2][p.y], inputVector));
else if (x2 == mNX)
location[0] -= 0.5 * dis0 / Math.sqrt(getDissimilarity(mReferenceVector[x1][p.y], inputVector));
else {
double dis1 = Math.sqrt(getDissimilarity(mReferenceVector[x1][p.y], inputVector)) - dis0;
double dis2 = Math.sqrt(getDissimilarity(mReferenceVector[x2][p.y], inputVector)) - dis0;
if (dis1 + dis2 != 0)
location[0] += dis1 / (dis1 + dis2) - 0.5;
}
if (y1 == -1)
location[1] += 0.5 * dis0 / Math.sqrt(getDissimilarity(mReferenceVector[p.x][y2], inputVector));
else if (y2 == mNY)
location[1] -= 0.5 * dis0 / Math.sqrt(getDissimilarity(mReferenceVector[p.x][y1], inputVector));
else {
double dis1 = Math.sqrt(getDissimilarity(mReferenceVector[p.x][y1], inputVector)) - dis0;
double dis2 = Math.sqrt(getDissimilarity(mReferenceVector[p.x][y2], inputVector)) - dis0;
if (dis1 + dis2 != 0)
location[1] += dis1 / (dis1 + dis2) - 0.5;
}
}
location[2] = dis0; // dissimilarity of match
return location;
}
private void grow() {
// works currently only with unlimited SOMs
Object[][] oldReferenceVector = mReferenceVector;
mReferenceVector = new Object[mNX*2][mNY*2];
for (int x=0; x");
writer.newLine();
writer.write("");
writer.newLine();
writer.write("");
writer.newLine();
startProgress("Writing SOM Vectors...", 0, mNY);
for (int y=0; y");
writer.newLine();
}
}
stopProgress("SOM Vectors Written");
}
public void read(BufferedReader reader) throws Exception {
String theLine = reader.readLine();
boolean error = !theLine.startsWith(" dissimilarity) {
mMinDissimilarity = dissimilarity;
mLocation.x = x;
mLocation.y = y;
}
}
}
break;
case APPLY_INFLUENCES:
if ((mMode & cModeTopologyUnlimited) != 0) {
y1 = mSMPInfluenceIndex[mThreadIndex][1];
y2 = mSMPInfluenceIndex[mThreadIndex+1][1];
for (int yy=y1; yy<=y2; yy++) {
int x1 = (yy == y1) ? mSMPInfluenceIndex[mThreadIndex][0] : 0;
int x2 = (yy == y2) ? mSMPInfluenceIndex[mThreadIndex+1][0] : mSMPInfluenceRect.width;
int y = yy + mSMPInfluenceRect.y;
for (int xx=x1; xx mNX / 2)
dx = mNX - dx;
if (dy > mNY / 2)
dy = mNY - dy;
if (mInfluence[dx][dy] > 0.0)
updateReference(mInputVector, mReferenceVector[x<0?x+mNX:x 0.0)
updateReference(mInputVector, mReferenceVector[x][y], mInfluence[dx][dy]);
}
}
}
break;
}
mDoneSignal.countDown();
}
public Point getBestMatchLocation() {
return mLocation;
}
public double getBestMatchDissimilarity() {
return mMinDissimilarity;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy