def making_ball_contains(root, children,  addDim=[], word2vecDic=dict(),
                         wsChildrenDic=dict(), wscatCodeDic=dict(), word2ballDic=dict(),
                         outputPath=None, logFile=None):
    """
    :param root:
    :param children:
    :param addDim:
    :param wsChildrenDic:
    :param wscatCodeDic:
    :param word2ballDic:
    :param outputPath:
    :param logFile:
    :return:
    """
    maxL = -1
    flag = False
    while not flag:
        flag = True
        for childName in children:
            pBall, word2ballDic = training_P_by_name(childName, root,  addDim=addDim,
                                       wsChildrenDic=wsChildrenDic, word2vecDic=word2vecDic, wscatCodeDic=wscatCodeDic,
                                       word2ballDic=word2ballDic,
                                       outputPath=outputPath, logFile=logFile)
            assert pBall != -1
            if maxL == -1: # initialize maxL, minL_R
                maxL, minL_R = pBall[-2], decimal.Decimal(pBall[-2]) - decimal.Decimal(pBall[-1])
            if maxL < pBall[-2]:
                maxL = pBall[-2]
            delta = decimal.Decimal(pBall[-2]) - decimal.Decimal(pBall[-1])
            if delta <=0:
                print('Shifting...mbc', root)
                with open(logFile, 'a+') as wlog:
                    wlog.write(" ".join(["shifting",str(root)]+
                                         [str(ele) for ele in word2ballDic[root][:-2]] + [str(-delta)]))
                    wlog.write("\n")
                word2ballDic = shift_whole_tree_of(root, word2ballDic[root][:-2], -delta,
                                    wsChildrenDic=wsChildrenDic, word2ballDic=word2ballDic,
                                    outputPath=outputPath)
                flag = False
                break
            elif decimal.Decimal(pBall[-2]) - decimal.Decimal(pBall[-1]) < minL_R:
                minL_R = decimal.Decimal(pBall[-2]) - decimal.Decimal(pBall[-1])

            word2ballDic[root] = word2ballDic[root][:-2] + [maxL, maxL - minL_R + cgap]
            if outputPath:
                create_ball_file(root,  outputPath=outputPath,word2ballDic=word2ballDic)
    return word2ballDic
def training_P_by_name(childName, atreeName, addDim=[], wsChildrenDic=dict(),word2vecDic=dict(), wscatCodeDic=dict(),
                       word2ballDic=dict(), sep='.', outputPath="", logFile=None):
    """
    :param childName:
    :param atreeName:
    :param addDim:
    :param wsChildrenDic:
    :param word2vecDic:
    :param wscatCodeDic:
    :param word2ballDic:
    :param sep:
    :param outputPath:
    :param logFile:
    :return:
    """

    if childName.split(sep)[0] == atreeName.split(sep)[0]:
        BallLeaf = word2ballDic[childName]
        BallParent, word2ballDic = initialize_ball(atreeName, addDim=addDim, L0=L0, R0=R0, word2vecDic=word2vecDic,
                                                   wscatCodeDic=wscatCodeDic, word2ballDic=word2ballDic,
                                                   outputPath=outputPath)
        LeafO, ParentO = BallLeaf[:-2], BallParent[:-2]
        LeafL, LeafR = BallLeaf[-2],BallLeaf[-1]
        ParentL, ParentR = LeafL + LeafR + cgap, LeafR + LeafR + cgap + cgap
        BallParent = ParentO + [ParentL, ParentR]
        word2ballDic.update({atreeName: BallParent})
    else:
        targetsin0 = 0.6
        while True:
            BallLeaf = word2ballDic[childName]
            BallParent, word2ballDic = initialize_ball(atreeName, addDim=addDim, L0=L0, R0=R0, word2vecDic=word2vecDic,
                                                       wscatCodeDic=wscatCodeDic, word2ballDic=word2ballDic,
                                                       outputPath=outputPath)
            LeafO, ParentO = [decimal.Decimal(ele) for ele in BallLeaf[:-2]], \
                             [decimal.Decimal(ele) for ele in BallParent[:-2]]
            LeafL, LeafR = BallLeaf[-2],BallLeaf[-1]
            sin_beta = BallLeaf[-1] / BallLeaf[-2]

            delta = 1 - sin_beta * sin_beta
            if delta < 0:
                delta = 0
            cos_beta = np.sqrt(delta)
            cos_alpha = np.dot(LeafO, ParentO) / np.linalg.norm(LeafO)/ np.linalg.norm(ParentO)

            delta = 1 - cos_alpha * cos_alpha
            if delta < 0:
                delta = 0
            sin_alpha = np.sqrt(delta)

            # begin alpha --> xalpha
            xalpha = sin_alpha/25
            yalpha = np.sqrt(1 - xalpha*xalpha)
            sin_xalpha = xalpha*cos_alpha + yalpha*sin_alpha
            delta = 1 - sin_xalpha * sin_xalpha
            if delta < 0: delta = 0
            cos_xalpha = np.sqrt(delta)

            sin_alpha = sin_xalpha
            cos_alpha = cos_xalpha
            # end

            dOO = LeafL * decimal.Decimal(cos_beta)

            cos_alpha_beta = (decimal.Decimal(cos_beta) * decimal.Decimal(cos_alpha)
                          - decimal.Decimal(sin_beta) * decimal.Decimal(sin_alpha))
            if cos_alpha_beta <=0:
                # shift_one_family(root=childName, targetsin = targetsin0,  outputPath=outputPath)
                L, R = word2ballDic[childName][-2:]
                print('Shifting...', childName)
                LNew = R / decimal.Decimal(targetsin0)
                with open(logFile, 'a+') as wlog:
                    wlog.write(" ".join(["shifting",str(childName)]+
                                         [str(ele) for ele in word2ballDic[childName][:-2]] + [str(LNew - L)]))
                    wlog.write("\n")
                word2ballDic=shift_whole_tree_of(childName,  word2ballDic[childName][:-2], LNew - L,
                                                 wsChildrenDic=wsChildrenDic, word2ballDic=word2ballDic,
                                                 outputPath=outputPath)
                # check_P_for_child_parent_in_one_family(childName, ballPath=outputPath)
                checkResult = check_DC_for_sibilings_in_one_family(childName)
                if checkResult:
                    print("check_DC_for_sibilings_in_one_family", childName, checkResult)
                targetsin0 *= 0.9
            else:
                break

        ParentL = dOO / cos_alpha_beta
        assert ParentL > 0 and ParentL != np.inf

        ParentR = ParentL * (decimal.Decimal(sin_alpha) * decimal.Decimal(cos_beta)
                             + decimal.Decimal(cos_alpha) * decimal.Decimal(sin_beta)) + decimal.Decimal(0.1)
        BallParent = ParentO + [ParentL, ParentR]
        word2ballDic.update({atreeName: BallParent})

    count = 0
    while qsr_P_degree(word2ballDic[childName], word2ballDic[atreeName]) < 0:
        oldParentR, delta = ParentR, 10
        ParentR += decimal.Decimal(2) - qsr_P_degree(word2ballDic[childName], word2ballDic[atreeName])
        while oldParentR == ParentR:
            ParentR += delta
            delta *= 10
        BallParent = ParentO + [ParentL, ParentR]
        word2ballDic.update({atreeName: BallParent})
        # print('*', qsr_P_degree_by_name(childName, atreeName))
        # print("**", qsr_P_by_name(childName, atreeName))
        count += 1
        # print('count', count)

    # assert qsr_P_by_name(childName, atreeName), childName+" - "+atreeName+": "+str(qsr_P_degree_by_name(childName, atreeName))
    if outputPath:
        create_ball_file(atreeName,  outputPath=outputPath,word2ballDic=word2ballDic)
    return BallParent, word2ballDic
def training_DC_by_name(childrenNames, wsChildrenDic=dict(), word2ballDic=dict(),
                        outputPath=None, ordered = False, logFile=None):
    """
    :param childrenNames:
    :param wsChildrenDic:
    :param word2ballDic:
    :param outputPath:
    :param maxsize:
    :param mindim:
    :param logFile:
    :return:
    """
    dic = dict()
    for tree in childrenNames:
        dic[tree] = word2ballDic[tree][-2]
    dic0 = copy.deepcopy(dic)

    if ordered:
        lst = [(node, word2ballDic[node]) for node in childrenNames]
    else:
        lst = [(item[0], word2ballDic[item[0]]) for item in sorted(dic.items(), key=operator.itemgetter(1))]

    i = 0
    if "herd.n.02" in childrenNames and "gathering.n.01" in childrenNames:
        print('break')
    while i < len(lst) - 1:
        # print('i:', i, ' in', len(lst))
        j = i + 1
        refTreeName = lst[i][0]
        while j < len(lst):
            curTreeName = lst[j][0]
            # print(curTreeName, refTreeName)
            targetsin0 = 0.6
            while not qsr_DC(word2ballDic[curTreeName], word2ballDic[refTreeName]):
                ball1 = word2ballDic[curTreeName]
                l1, r1 = decimal.Decimal(ball1[-2]), decimal.Decimal(ball1[-1])
                k = r1 / l1
                if k == 1:
                    L, R = word2ballDic[curTreeName][-2:]
                    print('Shifting...', curTreeName)
                    LNew = R / decimal.Decimal(targetsin0)
                    with open(logFile, 'a+') as wlog:
                        wlog.write(" ".join(["shifting", str(tree)] +
                                            [str(ele) for ele in word2ballDic[tree][:-2]] + [str(LNew - L)]))
                        wlog.write("\n")
                    word2ballDic= shift_whole_tree_of(tree, word2ballDic[curTreeName][:-2], LNew - L,
                                                      wsChildrenDic=wsChildrenDic, word2ballDic=word2ballDic,
                                                      outputPath=outputPath)
                    # check_P_for_child_parent_in_one_family(tree, ballPath=outputPath)
                    checkResult=check_DC_for_sibilings_in_one_family(tree)
                    if checkResult:
                        print("check_DC_for_sibilings_in_one_family", tree, checkResult)
                    targetsin0 *= 0.9

                ratio0, word2ballDic = ratio_homothetic_DC_transform(curTreeName, refTreeName,
                                                                             wsChildrenDic=wsChildrenDic,
                                                                             word2ballDic=word2ballDic,
                                                                             outputPath=outputPath,
                                                                             logFile=logFile)
                assert ratio0 != -1

            # assert qsr_DC_by_name(curTreeName, refTreeName, outputPath=outputPath)
            if outputPath:
                create_ball_file(curTreeName, outputPath=outputPath, word2ballDic=word2ballDic)
            j += 1
        for tree in childrenNames:
            dic[tree] = word2ballDic[tree][-2]
        lst = [(item[0], word2ballDic[item[0]]) for item in sorted(dic.items(), key=operator.itemgetter(1))]
        i += 1

    if "herd.n.02" in childrenNames and "gathering.n.01" in childrenNames:
        print('break')

    #####
    # homothetic transformation
    #####
    for child in childrenNames:
        ratio = word2ballDic[child][-2]/decimal.Decimal(dic0[child])
        word2ballDic = homothetic_recursive_transform_of_decendents(child, root=child, rate=ratio,
                                                                    wsChildrenDic=wsChildrenDic,
                                                                    word2ballDic=word2ballDic, outputPath=outputPath)
    return word2ballDic