/******************************************************************************* * Copyright 2012 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.lang.reflect.Array; import java.util.Arrays; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.collect.WeakInterner; import com.analog.lyric.dimple.model.values.Value; import com.google.common.collect.Interner; import net.jcip.annotations.Immutable; @Immutable public class RealJointDomain extends Domain { /*------- * State */ private static final long serialVersionUID = 1L; private final RealDomain [] _domains; private final int _size; /** * If true, then _domains will contain only one element representing the common domain * for all dimensions. */ private final boolean _homogeneous; private static enum InternedDomains { INSTANCE; private final Interner<RealJointDomain> interner = WeakInterner.create(); } /*-------------- * Construction */ protected RealJointDomain(RealDomain domain, int size) { super(43 + domain.hashCode() * size); _domains = new RealDomain[] { domain }; _size = size; _homogeneous = true; } protected RealJointDomain(RealDomain[] domains, boolean cloneDomains) { super(computeHashCode(domains)); if (allEqual(domains)) { _domains = new RealDomain[] { domains[0] }; _size = domains.length; _homogeneous = true; } else { _domains = cloneDomains ? domains.clone() : domains; _size = domains.length; _homogeneous = false; } } @Override protected RealJointDomain intern() { return InternedDomains.INSTANCE.interner.intern(this); } public static RealJointDomain create(RealDomain... domains) { if (domains.length < 1) { throw new IllegalArgumentException("RealJointDomain requires at least one domain"); } return new RealJointDomain(domains, true).intern(); } public static RealJointDomain create(int size) { return create(RealDomain.unbounded(), size); } public static RealJointDomain create(RealDomain domain, int size) { return new RealJointDomain(domain, size).intern(); } private static int computeHashCode(RealDomain[] domains) { int hashCode = 43; for (RealDomain domain : domains) { hashCode += domain.hashCode(); } return hashCode; } private static boolean allEqual(RealDomain[] domains) { RealDomain domain = domains[0]; for (int i = domains.length; --i>=1;) { if (!domain.equals(domains[i])) { return false; } } return true; } /*---------------- * Object methods */ @Override public boolean equals(@Nullable Object obj) { if (this == obj) return true; if ((obj instanceof RealJointDomain)) { RealJointDomain other = (RealJointDomain) obj; return _size == other._size && _homogeneous == other._homogeneous && Arrays.equals(this._domains, other._domains); } return false; } /*---------------- * Domain methods */ @Override public final RealJointDomain asRealJoint() { return this; } /** * @return true if value is an array of length matching {@link #getNumVars()} and whose * elements are contained in the correspond {@link RealDomain} in {@link #getRealDomains()}. */ @Override public boolean inDomain(@Nullable Object value) { if (value != null && value.getClass().isArray() && Array.getLength(value) == _size) { if (_homogeneous) { RealDomain domain = _domains[0]; for (int i = 0, end = _size; i < end; ++i) { if (! domain.inDomain(Array.get(value, i))) { return false; } } } else { for (int i = 0, end = _size; i < end; ++i) { if (! _domains[i].inDomain(Array.get(value, i))) { return false; } } } return true; } return false; } public boolean inDomain(double ... values) { int size = values.length; if (size != _size) return false; if (_homogeneous) { final RealDomain domain = _domains[0]; for (double value : values) if (!domain.inDomain(value)) return false; } else { for (int i = 0; i < size; i++) if (!_domains[i].inDomain(values[i])) return false; } return true; } /** * True if all {@link RealDomain} subdomains are equal. */ public final boolean isHomogeneous() { return _homogeneous; } @Override public final boolean isNumber() { return false; } @Override public final boolean isRealJoint() { return true; } @Override public final boolean isScalar() { return false; } @Override public boolean valueInDomain(Value value) { return inDomain(value.getDoubleArray()); } /*------------------------- * RealJointDomain methods */ /** * Returns the number of dimensions, or subdomains that make up this joint domain. */ @Override public final int getDimensions() { return _size; } /** * Returns copy of all of the subdomains making up this joint domain. * <p> * If you just want the size use {@link #getDimensions()} and if you just want * to access a domain at a given index use {@link #getRealDomain(int)} instead * to avoid the overhead of copying the array. */ public RealDomain [] getRealDomains() { if (_homogeneous) { RealDomain[] domains = new RealDomain[_size]; Arrays.fill(domains, _domains[0]); return domains; } else { return _domains.clone(); } } public RealDomain getRealDomain(int dimension) { return _domains[_homogeneous ? 0 : dimension]; } public int getNumVars() { return _size; } /** * True if values are confined to a subset of R<sup>n</sup> * <p> * True if at least one subdomain in {@link #getRealDomains()} is bounded. */ @Override public final boolean isBounded() { // True if any dimension is bounded for (int i = 0; i < _domains.length; i++) { if (_domains[i].isBounded()) return true; } return false; } }