Get all possible combinations of the following tree data structures

Later, you will see a data structure that is very similar to a simplified version of the function model (there is a view for them here ) and is some version of the tree. I have implemented a data structure in Java and now I am trying to parse it. In particular, I want to get all the combinations of elements that are possible if a specific feature model was provided.

Suppose we have the following feature model: Simplified function model

Items are fields. Circles that are not filled indicate optional items (remember o for optional), filled for required items . The root element must be included. Due to these rules, the following combinations or lists of elements are possible:

  • [1,3,5,6]
  • [1,2,3,5,6]
  • [1,3,4,5,6,7]
  • [1,2,3,4,5,6,7]

Now I want to get them not through visual search, but through Java program. For this, I have implemented several classes:

  • Tree

    stores the entire model of the object (figure).
  • Element

    is one of the rectangles.
  • Edge

    describes lines and circles.
  • Combination

    contains one possible combination (combination list).

In the class, Element

I have implemented a function to get all combinations named recursiveConfiguration

:

public List<Combination> recursiveCombination(List<Combination> combinations){

    for(Combination c: combinations){
        c.add(this);
    }

    // Iterate through all edges of the current element
    for(Edge e: getEdges()){

        int type = e.getType();         

        // In this case getChildren always returns only one feature.
        Element child = e.getChildren().get(0);             
        List<Combination> childCombinations = child.recursiveCombination(combinations);

        if(type == 1){
            // If type is mandatory
            combinations = childCombinations; // Line with compiler error
        }else{
            // If type is optional
            combinations.addAll(childCombinations);
        }    
    }   
    return combinations;
}

      

Algorithm explanation: It calls a list of combinations of one element, which is an empty list. The function is called on the root element 1

. It adds the first loop of the loop 1

to the combinations (it uses DFS to traverse the tree). Second, the method calls itself starting at the element 2

, passing in the original list (containing 1

). From here the configuration is returned, consisting of elements 1

and 2

. The returned list is processed depending on the type of edge (required or optional and added according to the original list). In this particular case, the list should consist of two combinations of 1

and 1,2

. When the subtree under the first edge (in this case only the element 2

) is complete, the next subtree is processed (3

, 5

, 6

).

The next is not important anymore, look in the horizontal bar.

But at the moment I am confused with recursion because when I call this the returned list is combinations

empty. I believe it has to do with the way the leaves are treated. Because they are not being processed properly at the moment (see bold text above). Anyone have an idea? Of course, I will try to explain the problem in more detail if necessary, and thanks for the thoughts you asked in this question.


Specification of the original question: Suppose the algorithm works at all (I checked it several times). Therefore, I assume that my understanding of Java is wrong in some part of the program. Two thoughts might be interesting:

  • After I turned on all the compiler warnings (thanks Prune), it remains to leave The parameter configurations should not be assigned

    and show Configure problem severity

    for the line combinations = childCombinations;

    . Perhaps this is the problem?
  • Is it possible that the variable combinations

    that is always passed to the function changes in the second / third / ... recursive call directly and not after returning?

Currently, the output generated by the program is returning the following combinations (which is clearly not correct):

  • [1, 2, 3, 3, 5, 5, 6, 6, 4, 4, 7, 7]
  • [1, 2, 3, 3, 5, 5, 6, 6, 4, 4, 7, 7]
  • [1, 2, 3, 3, 5, 5, 6, 6, 4, 4, 7, 7]
  • [1, 2, 3, 3, 5, 5, 6, 6, 4, 4, 7, 7]

Thanks for your time and effort!

+3


source to share


2 answers


Since I was not able to clearly explain the problem, you were unable to post a solution. I will now post the solution. First, spoiled the surprise: the algorithm was correct as I understood it, but the same variable combinations

was changed during the entire recursion process. Because of this, the same combination was produced four times.

The solution is to use the method clone

and therefore change List

to LinkedList

.



private LinkedList<Combination> recursiveConfiguration(LinkedList<Combination> combinations){

    for(Combination c: combinations){
        c.add(this);
    }

    // Iterate through all edges of the current node
    for(Edge e: getEdges()){

        int type = e.getType();     

        if((type == 1) || (type == 2)){
            // If type is mandatory or optional.

            // In this case getChildren always returns only one feature.
            LinkedList<Combination> copyConfig = new LinkedList<>();

            for(Combination c: configurations){
                @SuppressWarnings("unchecked")
                LinkedList<FeatureNode3> copy = (LinkedList<FeatureNode3>) c.getFeatureList().clone();
                Combination config = new Combination();
                config.setFeatureList(copy);
                copyConfig.add(config);
            }

            FeatureNode3 child = e.getChildren().get(0);    
            LinkedList<Combination> childCombinations = child.recursiveConfiguration(copyConfig);

            if(type == 1){
                // If type is mandatory
                combinations = childCombinations;
            }else{
                // If type is optional
                combinations.addAll(childCombinations);
            }   
        }
    }           
    return combinations;
}

      

Thanks for your time and advice!

0


source


I think your logic of adding a node for each combination in the list at the beginning is wrong, this should be done later.

The correct algorithm might look like this:



  • Call your recursive function using the root node. Return a list of combinations.

  • If it's a leaf node, return a list of combinations with just the node inside.

  • For each edge: call the recursive function with the child node and store the results.

  • Create all possible combinations of obligatory children. For example. with two obligatory children, one has 11 combinations, the other has 7, you get 11 * 7 = 77 combinations. You are basically building a cross product of all the required combinations, this is an easier step. If a node has no required children, then it is a list of combinations with one empty combination inside (to which the current node will be appended).

  • Combine with extra kids combinations. For example. with two extra extra children with 3 and 5 combinations, you get 77 + 77 * 3 + 77 * 5 + 77 * 3 * 5 = 1848 combinations. Here you have the option to choose whether you take an optional branch or not and so it blows up pretty quickly, with 3 branches a, b, c and x required combinations, you get x + ax + bx + cx + abx + acx + bcx + abcx (all combinations of taking and not taking a, b or c).

  • Add a node function to call with each combination and return the result.

0


source







All Articles