/*-
* Copyright (c) 2013 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.fitting.functions;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IFunction;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IOperator;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IParameter;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.DoubleDataset;
/**
* Multiply several functions (missing functions are treated as unity)
*/
public class Multiply extends ANaryOperator implements IOperator {
private static final String NAME = "Multiply";
private static final String DESC = "Multiply several functions together";
public Multiply() {
super();
}
@Override
protected void setNames() {
setNames(NAME, DESC);
}
@Override
public double val(double... values) {
double y = 1;
for (int i = 0, imax = getNoOfFunctions(); i < imax; i++) {
IFunction f = getFunction(i);
if (f != null) {
y *= f.val(values);
}
}
return y;
}
@Override
public void fillWithValues(DoubleDataset data, CoordinatesIterator it) {
int imax = getNoOfFunctions();
if (imax < 1) {
data.fill(1);
return;
}
IFunction f = getFunction(0);
if (f != null) {
if (f instanceof AFunction) {
((AFunction) f).fillWithValues(data, it);
} else {
data.setSlice(DatasetUtils.convertToDataset(f.calculateValues(it.getValues())));
}
} else {
data.fill(1);
}
if (imax == 1)
return;
DoubleDataset temp = DatasetFactory.zeros(DoubleDataset.class, it.getShape());
for (int i = 1; i < imax; i++) {
f = getFunction(i);
if (f == null)
continue;
if (f instanceof AFunction) {
((AFunction) f).fillWithValues(temp, it);
data.imultiply(temp);
} else {
data.imultiply(DatasetUtils.convertToDataset(f.calculateValues(it.getValues())));
}
}
}
@Override
public double partialDeriv(IParameter param, double... values) {
double d = 0;
double m = 1;
for (int i = 0, imax = getNoOfFunctions(); i < imax; i++) {
IFunction f = getFunction(i);
if (f == null)
continue;
double r = f.partialDeriv(param, values);
double t = f.val(values);
m *= t;
if (r != 0) {
d += r / t;
}
}
return d * m;
}
@Override
public void fillWithPartialDerivativeValues(IParameter param, DoubleDataset data, CoordinatesIterator it) {
int imax = getNoOfFunctions();
if (imax < 1) {
data.fill(0);
return;
}
IFunction f = getFunction(0);
boolean hasParam = indexOfParameter(f, param) >= 0;
if (f != null && hasParam) {
if (f instanceof AFunction) {
((AFunction) f).fillWithPartialDerivativeValues(param, data, it);
} else {
data.setSlice(DatasetUtils.convertToDataset(f.calculatePartialDerivativeValues(param, it.getValues())));
}
} else {
data.fill(0);
}
if (imax == 1)
return;
DoubleDataset val = DatasetFactory.zeros(DoubleDataset.class, it.getShape());
DoubleDataset sum = DatasetFactory.zeros(DoubleDataset.class, it.getShape());
DoubleDataset dif;
if (f != null) {
dif = data.clone(); // copy derivatives and now store values
if (f instanceof AFunction) {
((AFunction) f).fillWithValues(data, it);
} else {
data.setSlice(DatasetUtils.convertToDataset(f.calculateValues(it.getValues())));
}
if (hasParam) {
dif.idivide(data);
sum.iadd(dif);
}
} else {
dif = DatasetFactory.zeros(DoubleDataset.class, it.getShape());
data.fill(1);
}
for (int i = 1; i < imax; i++) {
f = getFunction(i);
if (f == null)
continue;
hasParam = indexOfParameter(f, param) >= 0;
if (f instanceof AFunction) {
((AFunction) f).fillWithValues(val, it);
data.imultiply(val);
if (hasParam) {
((AFunction) f).fillWithPartialDerivativeValues(param, dif, it);
dif.idivide(val);
sum.iadd(dif);
}
} else {
Dataset v = DatasetUtils.convertToDataset(f.calculateValues(it.getValues()));
data.imultiply(v);
if (hasParam) {
Dataset d = DatasetUtils.convertToDataset(f.calculatePartialDerivativeValues(param, it.getValues()));
d.idivide(v);
sum.iadd(d);
}
}
}
data.imultiply(sum);
}
}