/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
package com.analog.lyric.dimple.model.domains;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jdt.annotation.Nullable;
/**
* A {@link JointDomainReindexer} that supports the splitting/joining of adjacent subdomains.
*/
public final class JointDomainIndexJoiner extends JointDomainReindexer
{
/*-------
* State
*/
private final int _hashCode;
private final int _offset;
private final int _length;
private final JointDomainIndexJoiner _inverse;
private final boolean _supportsJointIndexing;
/*--------------
* Construction
*/
public static JointDomainIndexJoiner createJoiner(JointDomainIndexer fromDomains, int offset, int length)
{
return new JointDomainIndexJoiner(fromDomains, offset, length);
}
public static JointDomainIndexJoiner createSplitter(JointDomainIndexer fromDomains, int offset)
{
return new JointDomainIndexJoiner(fromDomains, offset);
}
private JointDomainIndexJoiner(
JointDomainIndexer fromDomains,
JointDomainIndexer toDomains,
int offset,
int length,
JointDomainIndexJoiner inverse)
{
super(fromDomains, null, toDomains, null);
_hashCode = computeHashCode();
_offset = offset;
_length = length;
_inverse = inverse;
_supportsJointIndexing = fromDomains.supportsJointIndexing() & toDomains.supportsJointIndexing();
}
private JointDomainIndexJoiner(JointDomainIndexer fromDomains, int offset)
{
super(fromDomains, null, makeToDomains(fromDomains, offset), null);
_hashCode = computeHashCode();
_offset = offset;
_length = _fromDomains.size() - _toDomains.size() - 1;
_inverse = new JointDomainIndexJoiner(_toDomains, fromDomains, offset, -_length, this);
_supportsJointIndexing = fromDomains.supportsJointIndexing() & _toDomains.supportsJointIndexing();
}
private JointDomainIndexJoiner(JointDomainIndexer fromDomains, int offset, int length)
{
super(fromDomains, null, makeToDomains(fromDomains, offset, length), null);
_hashCode = computeHashCode();
_offset = offset;
_length = length;
_inverse = new JointDomainIndexJoiner(_toDomains, fromDomains, offset, -length, this);
_supportsJointIndexing = fromDomains.supportsJointIndexing() & _toDomains.supportsJointIndexing();
}
private static JointDomainIndexer makeToDomains(JointDomainIndexer fromDomains, int offset, int length)
{
final int fromSize = fromDomains.size();
final int toSize = fromSize + 1 - length;
final DiscreteDomain[] toDomains = new DiscreteDomain[toSize];
int from = 0, to = 0;
for (; from < offset; ++from, ++to)
{
toDomains[to] = fromDomains.get(from);
}
final DiscreteDomain[] joinedDomains = new DiscreteDomain[length];
for (int j = 0; j < length; ++j, ++from)
{
joinedDomains[j] = fromDomains.get(from);
}
toDomains[to++] = DiscreteDomain.joint(joinedDomains);
for (; from < fromSize; ++from, ++to)
{
toDomains[to] = fromDomains.get(from);
}
return JointDomainIndexer.create(toDomains);
}
private static JointDomainIndexer makeToDomains(JointDomainIndexer fromDomains, int offset)
{
JointDomainIndexer joinedDomainList = ((JointDiscreteDomain<?>)fromDomains.get(offset)).getDomainIndexer();
final int length = joinedDomainList.size();
final int fromSize = fromDomains.size();
final int toSize = fromSize - 1 + length;
final DiscreteDomain[] toDomains = new DiscreteDomain[toSize];
int from = 0, to = 0;
for (; from < offset; ++from, ++to)
{
toDomains[to] = fromDomains.get(from);
}
for (int j = 0; j < length; ++j, ++to)
{
toDomains[to] = joinedDomainList.get(j);
}
++from;
for (; from < fromSize; ++from, ++to)
{
toDomains[to] = fromDomains.get(from);
}
return JointDomainIndexer.create(toDomains);
}
/*----------------
* Object methods
*/
@Override
public boolean equals(@Nullable Object other)
{
if (this == other)
{
return true;
}
if (other instanceof JointDomainIndexJoiner)
{
JointDomainIndexJoiner that = (JointDomainIndexJoiner)other;
return _fromDomains.equals(that._fromDomains) && _toDomains.equals(that._toDomains);
}
return false;
}
@Override
public int hashCode()
{
return _hashCode;
}
/*-------------------------------------
* JointDomainReindexer methods
*/
@Override
public JointDomainIndexJoiner getInverse()
{
return _inverse;
}
@Override
public double[] convertDenseEnergies(double[] oldEnergies)
{
return oldEnergies.clone();
}
@Override
public double[] convertDenseWeights(double[] oldWeights)
{
return oldWeights.clone();
}
@Override
public void convertIndices(Indices indices)
{
if (_supportsJointIndexing)
{
// When joint indexing is supported, conversion is simply mapping from the domain indices to
// the joint index and back again for the new domains.
int index = _fromDomains.jointIndexFromIndices(indices.fromIndices);
_toDomains.jointIndexToIndices(index, indices.toIndices);
}
else
{
// Otherwise direct subindex copying is required.
if (_length > 0)
{
System.arraycopy(indices.fromIndices, 0, indices.toIndices, 0, _length);
}
int fromi, toi;
if (_length > 0)
{
// Joining
JointDiscreteDomain<?> joinedDomains = (JointDiscreteDomain<?>)_toDomains.get(_offset);
System.arraycopy(indices.fromIndices, _offset, indices.joinedIndices, 0, _length);
indices.toIndices[_offset] = joinedDomains.getIndexFromIndices(indices.joinedIndices);
fromi = _offset + _length;
toi = _offset + 1;
}
else
{
// Splitting
JointDiscreteDomain<?> joinedDomains = (JointDiscreteDomain<?>)_fromDomains.get(_offset);
joinedDomains.getElementIndices(indices.fromIndices[_offset], indices.joinedIndices);
System.arraycopy(indices.joinedIndices, 0, indices.toIndices, _offset, -_length);
fromi = _offset + 1;
toi = _offset - _length;
}
System.arraycopy(indices.fromIndices, fromi, indices.toIndices, toi, indices.toIndices.length - toi);
}
}
@Override
public int convertJointIndex(int oldJointIndex, int addedJointIndex, @Nullable AtomicInteger removedJointIndex)
{
return oldJointIndex;
}
@Override
public int convertJointIndex(int oldJointIndex, int addedJointIndex)
{
return oldJointIndex;
}
@Override
public int[][] convertSparseIndices(
int[][] oldSparseIndices, int[] oldSparseIndexToJointIndex, int[] sparseIndexToJointIndex)
{
return oldSparseIndices.clone();
}
@Override
public int[] convertSparseToJointIndex(int[] oldSparseToJointIndex)
{
return oldSparseToJointIndex.clone();
}
@Override
public double[] convertSparseWeights(double[] oldSparseWeights,
int[] oldSparseIndexToJointIndex, int[] sparseIndexToJointIndex)
{
return oldSparseWeights.clone();
}
@Override
public boolean hasFastJointIndexConversion()
{
return true;
}
@Override
protected boolean maintainsJointIndexOrder()
{
return true;
}
}