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 + -
显示快捷键?