org.n52.matlab.control.link.MatlabNumber Maven / Gradle / Ivy
The newest version!
package org.n52.matlab.control.link;
/*
* Copyright (c) 2013, Joshua Kaplan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of matlabcontrol nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import org.n52.matlab.control.MatlabInvocationException;
import org.n52.matlab.control.MatlabOperations;
/**
* Corresponds to a MATLAB number with real and imaginary components.
*
* @since 4.2.0
* @author Joshua Kaplan
*/
abstract class MatlabNumber extends MatlabType
{
final T _real;
final T _imag;
/**
* The default value for {@code T}.
*/
private final T _default;
MatlabNumber(T defaultValue, T real, T imag)
{
_default = defaultValue;
_real = real;
_imag = imag;
}
/**
* Returns {@code true} if the imaginary value is equivalent to the default value for the numeric type,
* {@code false} otherwise. Equivalent to the MATLAB {@code isreal} function.
*
* @return
*/
public boolean isReal()
{
return _default.equals(_imag);
}
/**
* Returns a {@code String} representation of the number. If the number is real the String representation is
* real. If an imaginary component is present, the format is real + imagi
if the
* imaginary component is non-negative and real - imagi
if the imaginary component is
* negative.
*
* @return
*/
@Override
public String toString()
{
String fullStr;
String realStr = _real.toString();
if(this.isReal())
{
fullStr = realStr;
}
else
{
String imagStr = _imag.toString();
if(imagStr.startsWith("-"))
{
fullStr = realStr + " - " + imagStr.substring(1, imagStr.length()) + "i";
}
else
{
fullStr = realStr + " + " + imagStr + "i";
}
}
return fullStr;
}
/**
* Returns {@code true} if and only if the other object is of the same class and its component real and imaginary
* parts are both equal. The definition of equality for the component parts is defined by the {@code equals(...)}
* method of the boxed numeric class of its components.
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj)
{
boolean equal = false;
if(obj != null && this.getClass().equals(obj.getClass()))
{
MatlabNumber other = (MatlabNumber) obj;
equal = _real.equals(other._real) && _imag.equals(other._imag);
}
return equal;
}
/**
* Returns a hash code compatible with {@code equals(...)}.
*
* @return
*/
@Override
public int hashCode()
{
int hash = 5;
hash = 79 * hash + _real.hashCode();
hash = 79 * hash + _imag.hashCode();
return hash;
}
@Override
MatlabTypeSetter getSetter()
{
return new MatlabNumberSetter(_real, _imag);
}
//This is very non-object oriented to have this here instead of each subclass, but it saves a lot of boilerplate
private static class MatlabNumberSetter implements MatlabTypeSetter
{
private final Number _real;
private final Number _imag;
private MatlabNumberSetter(Number real, Number imag)
{
_real = real;
_imag = imag;
}
@Override
public void setInMatlab(MatlabOperations ops, String name) throws MatlabInvocationException
{
//Avoids limitation that MATLAB cannot multiply an integer stored in a variable by i
if(_real instanceof Byte)
{
ops.eval(name + "=int8(" + _real.byteValue() + "+" + _imag.byteValue() + "i);");
}
else if(_real instanceof Short)
{
ops.eval(name + "=int16(" + _real.shortValue() + "+" + _imag.shortValue() + "i);");
}
else if(_real instanceof Integer)
{
ops.eval(name + "=int32(" + _real.intValue() + "+" + _imag.intValue() + "i);");
}
else if(_real instanceof Long)
{
ops.eval(name + "=int64(" + _real.longValue() + "+" + _imag.longValue() + "i);");
}
// Set value through an array to avoid values being converted to MATLAB double
else if(_real instanceof Float)
{
ops.setVariable(name, new float[] { _real.floatValue(), _imag.floatValue() });
ops.eval(name + "=" + name + "(1)+" + name + "(2)*i;");
}
else if(_real instanceof Double)
{
ops.setVariable(name, new double[] { _real.doubleValue(), _imag.doubleValue() });
ops.eval(name + "=" + name + "(1)+" + name + "(2)*i;");
}
}
}
static class MatlabNumberGetter implements MatlabTypeGetter
{
private Object _real;
private Object _imag;
private boolean _retrieved;
@Override
public MatlabNumber> retrieve()
{
if(!_retrieved)
{
throw new IllegalStateException("complex number has not been retrieved");
}
MatlabNumber num;
if(_real.getClass().equals(Byte.class))
{
num = new MatlabInt8((Byte) _real, (Byte) _imag);
}
else if(_real.getClass().equals(Short.class))
{
num = new MatlabInt16((Short) _real, (Short) _imag);
}
else if(_real.getClass().equals(Integer.class))
{
num = new MatlabInt32((Integer) _real, (Integer) _imag);
}
else if(_real.getClass().equals(Long.class))
{
num = new MatlabInt64((Long) _real, (Long) _imag);
}
else if(_real.getClass().equals(Float.class))
{
num = new MatlabSingle((Float) _real, (Float) _imag);
}
else if(_real.getClass().equals(Double.class))
{
num = new MatlabDouble((Double) _real, (Double) _imag);
}
else
{
throw new IllegalStateException("unsupported numeric type: " + _real.getClass().getCanonicalName());
}
return num;
}
@Override
public void getInMatlab(MatlabOperations ops, String variableName) throws MatlabInvocationException
{
String receiverName = (String) ops.returningEval("genvarname('complex_receiver_', who);", 1)[0];
try
{
ops.setVariable(receiverName, this);
ops.eval(receiverName + ".setReal(real(" + variableName + "));");
ops.eval(receiverName + ".setImaginary(imag(" + variableName + "));");
}
finally
{
ops.eval("clear " + receiverName);
}
_retrieved = true;
}
/**
* Sets the real value. Only meant to be called from MATLAB. In order for MATLAB to pass in the number, this
* method must have {@code Object} as its parameter, not {@code Number}.
*
* @param real
*/
public void setReal(Object real)
{
_real = real;
}
/**
* Sets the imaginary value. Only meant to be called from MATLAB. In order for MATLAB to pass in the number,
* this method must have {@code Object} as its parameter, not {@code Number}.
*
* @param imag
*/
public void setImaginary(Object imag)
{
_imag = imag;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy