funutil.java
来自「数据仓库展示程序」· Java 代码 · 共 1,808 行 · 第 1/5 页
JAVA
1,808 行
static Object correlation(Evaluator evaluator,
List members,
ExpBase exp1,
ExpBase exp2) {
SetWrapper sw1 = evaluateSet(evaluator, members, exp1);
SetWrapper sw2 = evaluateSet(evaluator, members, exp2);
Object covar = _covariance(sw1, sw2, false);
Object var1 = _var(sw1, false); //this should be false, yes?
Object var2 = _var(sw2, false);
if ((covar instanceof Double) &&
(var1 instanceof Double) &&
(var2 instanceof Double)) {
return new Double(((Double) covar).doubleValue() /
Math.sqrt(((Double) var1).doubleValue() *
((Double) var2).doubleValue()));
} else {
return Util.nullValue;
}
}
static Object covariance(Evaluator evaluator, List members, ExpBase exp1, ExpBase exp2, boolean biased) {
SetWrapper sw1 = evaluateSet(evaluator.push(), members, exp1);
SetWrapper sw2 = evaluateSet(evaluator.push(), members, exp2);
// todo: because evaluateSet does not add nulls to the SetWrapper, this
// solution may lead to mismatched lists and is therefore not robust
return _covariance(sw1, sw2, biased);
}
private static Object _covariance(SetWrapper sw1,
SetWrapper sw2,
boolean biased) {
if (sw1.v.size() != sw2.v.size()) {
return Util.nullValue;
}
double avg1 = _avg(sw1);
double avg2 = _avg(sw2);
double covar = 0.0;
for (int i = 0; i < sw1.v.size(); i++) {
//all of this casting seems inefficient - can we make SetWrapper
//contain an array of double instead?
double diff1 = (((Double) sw1.v.get(i)).doubleValue() - avg1);
double diff2 = (((Double) sw2.v.get(i)).doubleValue() - avg2);
covar += (diff1 * diff2);
}
int n = sw1.v.size();
if (!biased) {
n--;
}
return new Double(covar / (double) n);
}
static Object stdev(Evaluator evaluator,
List members,
ExpBase exp,
boolean biased) {
Object o = var(evaluator, members, exp, biased);
return (o instanceof Double)
? new Double(Math.sqrt(((Double) o).doubleValue()))
: o;
}
public static Object avg(Evaluator evaluator, List members, Exp exp) {
SetWrapper sw = evaluateSet(evaluator, members, (ExpBase) exp);
return (sw.errorCount > 0)
? new Double(Double.NaN)
: (sw.v.size() == 0)
? Util.nullValue
: new Double(_avg(sw));
}
//todo: parameterize inclusion of nulls
//also, maybe make _avg a method of setwrapper, so we can cache the result (i.e. for correl)
private static double _avg(SetWrapper sw) {
double sum = 0.0;
for (int i = 0; i < sw.v.size(); i++) {
sum += ((Double) sw.v.get(i)).doubleValue();
}
//todo: should look at context and optionally include nulls
return sum / (double) sw.v.size();
}
public static Object sum(Evaluator evaluator, List members, Exp exp) {
SetWrapper sw = evaluateSet(evaluator, members, (ExpBase) exp);
if (sw.errorCount > 0) {
if (false) {
return new MondrianEvaluationException(
sw.errorCount + " error(s) while computing sum");
}
return new Double(Double.NaN);
} else if (sw.v.size() == 0) {
return Util.nullValue;
} else {
double sum = 0.0;
for (int i = 0; i < sw.v.size(); i++) {
sum += ((Double) sw.v.get(i)).doubleValue();
}
return new Double(sum);
}
}
public static Object count(Evaluator evaluator,
List members,
boolean includeEmpty) {
if (members == null) {
return new Double(0);
}
if (includeEmpty) {
return new Double(members.size());
} else {
int retval = 0;
for (int i = 0; i < members.size(); i++) {
final Object member = members.get(i);
if (member instanceof Member) {
evaluator.setContext((Member) member);
} else {
evaluator.setContext((Member[]) member);
}
Object o = evaluator.evaluateCurrent();
if (o != Util.nullValue && o != null) {
retval++;
}
}
return new Double(retval);
}
}
/**
* Evaluates <code>exp</code> (if defined) over <code>members</code> to
* generate a {@link List} of {@link SetWrapper} objects, which contains
* a {@link Double} value and meta information, unlike
* {@link #evaluateMembers}, which only produces values.
*
* @pre exp != null
*/
static SetWrapper evaluateSet(Evaluator evaluator,
List members,
ExpBase exp) {
Util.assertPrecondition(exp != null, "exp != null");
// todo: treat constant exps as evaluateMembers() does
SetWrapper retval = new SetWrapper();
for (Iterator it = members.iterator(); it.hasNext();) {
Object obj = it.next();
if (obj instanceof Member[]) {
evaluator.setContext((Member[])obj);
} else {
evaluator.setContext((Member)obj);
}
Object o = exp.evaluateScalar(evaluator);
if (o == null || o == Util.nullValue) {
retval.nullCount++;
} else if (o instanceof Throwable) {
// Carry on summing, so that if we are running in a
// BatchingCellReader, we find out all the dependent cells we
// need
retval.errorCount++;
} else if (o instanceof Double) {
retval.v.add(o);
} else if (o instanceof Number) {
retval.v.add(new Double(((Number) o).doubleValue()));
} else {
retval.v.add(o);
}
}
return retval;
}
/**
* This evaluates one or more ExpBases against the member list returning
* a SetWrapper array. Where this differs very significantly from the
* above evaluateSet methods is how it count null values and Throwables;
* this method adds nulls to the SetWrapper Vector rather than not adding
* anything - as the above method does. The impact of this is that if, for
* example, one was creating a list of x,y values then each list will have
* the same number of values (though some might be null) - this allows
* higher level code to determine how to handle the lack of data rather than
* having a non-equal number (if one is plotting x,y values it helps to
* have the same number and know where a potential gap is the data is.
*
* @param evaluator
* @param members
* @param exps
* @return
*/
static SetWrapper[] evaluateSet(Evaluator evaluator,
List members,
ExpBase[] exps) {
Util.assertPrecondition(exps != null, "exps != null");
// todo: treat constant exps as evaluateMembers() does
SetWrapper[] retvals = new SetWrapper[exps.length];
for (int i = 0; i < exps.length; i++) {
retvals[i] = new SetWrapper();
}
for (Iterator it = members.iterator(); it.hasNext();) {
Object obj = it.next();
if (obj instanceof Member[]) {
evaluator.setContext((Member[])obj);
} else {
evaluator.setContext((Member)obj);
}
for (int i = 0; i < exps.length; i++) {
ExpBase exp = exps[i];
SetWrapper retval = retvals[i];
Object o = exp.evaluateScalar(evaluator);
if (o == null || o == Util.nullValue) {
retval.nullCount++;
retval.v.add(null);
} else if (o instanceof Throwable) {
// Carry on summing, so that if we are running in a
// BatchingCellReader, we find out all the dependent cells
// we
// need
retval.errorCount++;
retval.v.add(null);
} else if (o instanceof Double) {
retval.v.add(o);
} else if (o instanceof Number) {
retval.v.add(new Double(((Number) o).doubleValue()));
} else {
retval.v.add(o);
}
}
}
return retvals;
}
static List periodsToDate(
Evaluator evaluator,
Level level,
Member member) {
if (member == null) {
member = evaluator.getContext(level.getHierarchy().getDimension());
}
Member m = member;
while (m != null) {
if (m.getLevel() == level) {
break;
}
m = m.getParentMember();
}
// If m == null, then "level" was lower than member's level.
// periodsToDate( [Time].[Quarter], [Time].[1997] is valid,
// but will return an empty List
List members = new ArrayList();
if (m != null) {
// e.g. m is [Time].[1997] and member is [Time].[1997].[Q1].[3]
// we now have to make m to be the first member of the range,
// so m becomes [Time].[1997].[Q1].[1]
SchemaReader reader = evaluator.getSchemaReader();
m = Util.getFirstDescendantOnLevel(reader, m, member.getLevel());
reader.getMemberRange(level, m, member, members);
}
return members;
}
static List memberRange(Evaluator evaluator,
Member startMember,
Member endMember) {
final Level level = startMember.getLevel();
assertTrue(level == endMember.getLevel());
List members = new ArrayList();
evaluator.getSchemaReader().getMemberRange(level,
startMember, endMember, members);
if (members.isEmpty()) {
// The result is empty, so maybe the members are reversed. This is
// cheaper than comparing the members before we call getMemberRange.
evaluator.getSchemaReader().getMemberRange(level,
endMember, startMember, members);
}
return members;
}
/**
* Returns the member under ancestorMember having the same relative position
* under member's parent.
* <p>For exmaple, cousin([Feb 2001], [Q3 2001]) is [August 2001].
* @param schemaReader The reader to use
* @param member The member for which we'll find the cousin.
* @param ancestorMember The cousin's ancestor.
* @return The child of <code>ancestorMember</code> in the same position under
* <code>ancestorMember</code> as <code>member</code> is under its parent.
*/
static Member cousin(SchemaReader schemaReader,
Member member,
Member ancestorMember) {
if (ancestorMember.isNull()) {
return ancestorMember;
}
if (member.getHierarchy() != ancestorMember.getHierarchy()) {
throw MondrianResource.instance().CousinHierarchyMismatch.ex(
member.getUniqueName(), ancestorMember.getUniqueName());
}
if (member.getLevel().getDepth() < ancestorMember.getLevel().getDepth()) {
return member.getHierarchy().getNullMember();
}
Member cousin = cousin2(schemaReader, member, ancestorMember);
if (cousin == null) {
cousin = member.getHierarchy().getNullMember();
}
return cousin;
}
static private Member cousin2(SchemaReader schemaReader,
Member member1,
Member member2) {
if (member1.getLevel() == member2.getLevel()) {
return member2;
}
Member uncle = cousin2(schemaReader, member1.getParentMember(), member2);
if (uncle == null) {
return null;
}
int ordinal = Util.getMemberOrdinalInParent(schemaReader, member1);
Member[] cousins = schemaReader.getMemberChildren(uncle);
if (cousins.length <= ordinal) {
return null;
}
return cousins[ordinal];
}
/**
* Returns the ancestor of <code>member</code> at the given level
* or distance. It is assumed that any error checking required
* has been done prior to calling this function.
* <p>This method takes into consideration the fact that there
* may be intervening hidden members between <code>member</code>
* and the ancestor. If <code>targetLevel</code> is not null, then
* the method will only return a member if the level at
* <code>distance</code> from the member is actually the
* <code>targetLevel</code> specified.
* @param evaluator The evaluation context
* @param member The member for which the ancestor is to be found
* @param distance The distance up the chain the ancestor is to
* be found.
* @param targetLevel The desired targetLevel of the ancestor. If <code>null</code>,
* then the distance completely determines the desired ancestor.
* @return The ancestor member, or <code>null</code> if no such
* ancestor exists.
*/
static Member ancestor(Evaluator evaluator,
Member member,
int distance,
Level targetLevel) {
if ((targetLevel != null) &&
(member.getHierarchy() != targetLevel.getHierarchy())) {
throw MondrianResource.instance().MemberNotInLevelHierarchy.ex(
member.getUniqueName(), targetLevel.getUniqueName());
}
if (distance == 0) {
/*
* Shortcut if there's nowhere to go.
*/
return member;
} else if (distance < 0) {
/*
* Can't go backwards.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?