package splar.core.fm.randomization; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Random; import java.util.Vector; import splar.core.constraints.BooleanVariableInterface; import splar.core.constraints.PropositionalFormula; import splar.core.fm.FeatureGroup; import splar.core.fm.FeatureModel; import splar.core.fm.FeatureModelException; import splar.core.fm.FeatureTreeNode; import splar.core.fm.GroupedFeature; import splar.core.fm.RootNode; import splar.core.fm.SolitaireFeature; import splar.core.fm.TreeNodeRendererFactory; public class RandomFeatureTreeModel extends FeatureModel { private int numberOfFeatures; // total number of features in the feature model not counting feature group nodes private int childFeaturesOdds; // max number of children for a given node (opt, mand, and group count as one) private int minChildFeature; // min number of children for a given node (opt, mand, and group count as one) private int solitaireOdds; // odds for solitaire features private int groupOdds; // odds for feature groups private int minGroupCard; // min number of grouped features in a group private int maxGroupCard; // max number of grouped features in a group public RandomFeatureTreeModel(int numberOfFeatures, int solitaireOdds, int groupOdds, int minChildFeature, int minGroupCard, int maxGroupCard) { super(); // feature tree parameters this.numberOfFeatures = numberOfFeatures; this.childFeaturesOdds = solitaireOdds + groupOdds; this.minChildFeature = minChildFeature; this.solitaireOdds = solitaireOdds; this.groupOdds = groupOdds; this.minGroupCard = minGroupCard; this.maxGroupCard = maxGroupCard; } protected FeatureTreeNode createNodes() throws FeatureModelException { int countFeatures = 1; Vector<FeatureTreeNode> fmNodes = new Vector<FeatureTreeNode>(); String featureName = "R"; countFeatures++; RootNode root = new RootNode( featureName, featureName, TreeNodeRendererFactory.createRootRenderer()); fmNodes.add(root); FeatureTreeNode parentNode = null; while ( countFeatures <= numberOfFeatures ) { parentNode = fmNodes.firstElement(); fmNodes.removeElement(parentNode); int numberOfChildNodesToCreate = Math.min(numberOfFeatures-countFeatures+1, (Math.abs(new Random().nextInt())%(childFeaturesOdds-minChildFeature+1))+minChildFeature); // prevents an early end of the recursion when all nodes happen to have no children if ( numberOfChildNodesToCreate == 0 ) { if ( fmNodes.size() == 0 ) { numberOfChildNodesToCreate = 1; } } if ( numberOfChildNodesToCreate > 0 ) { for( int i = 0 ; i < numberOfChildNodesToCreate && countFeatures <= numberOfFeatures ; i++ ) { String childFeatureName = parentNode.getID().substring(1) + (i+1); FeatureTreeNode randomNode = createRandomNode(childFeatureName,solitaireOdds, groupOdds, minGroupCard, maxGroupCard); parentNode.add(randomNode); if ( randomNode instanceof FeatureGroup ) { FeatureGroup groupRandomNode = (FeatureGroup)randomNode; int countGroupedNodes = groupRandomNode.getChildCount(); for( int j = 0 ; j < countGroupedNodes ; j++ ) { fmNodes.add((FeatureTreeNode)groupRandomNode.getChildAt(j)); } countFeatures += (countGroupedNodes); } else { fmNodes.add(randomNode); countFeatures++; } } } } return root; } private FeatureTreeNode createRandomNode(String childFeatureName, int solitaireOdds, int groupOdds, int minGroupCard, int maxGroupCard) { int solitaireOrGroupRandom = (new Random().nextInt()%childFeaturesOdds)+1; FeatureTreeNode node = null; String featureName = ""; // should create a solitaire feature (optional/mandatory)? if ( solitaireOrGroupRandom <= solitaireOdds ) { featureName = "S" + childFeatureName; // 50% odds for mandatory and optional features // int solitaireOptorMandRandom = (new Random().nextInt()%2); // should create an optional feature? // if ( solitaireOptorMandRandom == 0 ) { node = new SolitaireFeature( true, featureName, featureName, TreeNodeRendererFactory.createOptionalRenderer()); // } // should create a mandatory feature? // else { // node = new SolitaireFeature( true, featureName, featureName, TreeNodeRendererFactory.createMandatoryRenderer()); // } } // should create a feature group? else { // number of grouped features int groupSize = (Math.abs(new Random().nextInt())%(maxGroupCard-minGroupCard+1))+minGroupCard; // 50% odds for [1..*] and [1] group cardinality int groupTypeOdds = (new Random().nextInt()%2); // [1..*] or [1] cardinality int lower = 1; int upper = 1; if ( groupTypeOdds == 0 ) { // [1..*] = [1,-1] upper = -1; } String groupName = "_G" + childFeatureName;; // create group parent node node = new FeatureGroup( groupName, groupName, lower,upper,TreeNodeRendererFactory.createFeatureGroupRenderer() ); // create grouped feature nodes for( int i = 0 ; i < groupSize ; i++ ) { featureName = "g" + childFeatureName + (i+1); node.add( new GroupedFeature( featureName, featureName, TreeNodeRendererFactory.createGroupedRenderer() )); } } return node; } public static Vector<PropositionalFormula> createExtraConstraints(FeatureModel fm, int numVars, int numConstraints, int minVarsLeft, int maxVarsLeft, int minVarsRight, int maxVarsRight) { Vector<PropositionalFormula> pfs = new Vector<PropositionalFormula>(); if ( fm != null ) { if ( numConstraints > 0 && numVars > 1) { ArrayList<BooleanVariableInterface> vars = chooseVariablesForConstraints(fm, numVars); int varIndex = 0; for( int i = 0 ; i < numConstraints ; i++ ) { String constraint = ""; int leftVarsToPick = (new Random().nextInt()%(maxVarsLeft-minVarsLeft+1))+minVarsLeft; int RightVarsToPick = (new Random().nextInt()%(maxVarsRight-minVarsLeft+1))+minVarsRight; int leftOp = new Random().nextInt()%2; // 0 = OR, 1 = AND int RightOp = new Random().nextInt()%2; String v; int form; constraint += "("; for( int j = 0 ; j < leftVarsToPick-1 ; j++ ) { v = vars.get(varIndex).getID(); form = new Random().nextInt()%2; // 0 = positive, 1 = negative if ( form == 0 ) { constraint += "" + v; } else { constraint += "~" + v; } if (leftOp == 0) { constraint += " OR "; } else { // constraint += " AND "; constraint += " OR "; // enforce CNF } varIndex = (varIndex < (numVars-1) ? varIndex+1 : 0); if ( varIndex == 0 ) scrumbleVars(vars); } v = vars.get(varIndex).getID(); form = new Random().nextInt()%2; // 0 = positive, 1 = negative if ( form == 0 ) { constraint += "" + v; } else { constraint += "~" + v; } // constraint += ") IMP ("; constraint += ") OR ("; // enforce CNF varIndex = (varIndex < (numVars-1) ? varIndex+1 : 0); if ( varIndex == 0 ) scrumbleVars(vars); for( int j = 0 ; j < RightVarsToPick-1 ; j++ ) { v = vars.get(varIndex).getID(); form = new Random().nextInt()%2; // 0 = positive, 1 = negative if ( form == 0 ) { constraint += "" + v; } else { constraint += "~" + v; } if (RightOp == 0) { constraint += " OR "; } else { // constraint += " AND "; // enforce CNF constraint += " OR "; } varIndex = (varIndex < (numVars-1) ? varIndex+1 : 0); if ( varIndex == 0 ) scrumbleVars(vars); } v = vars.get(varIndex).getID(); form = new Random().nextInt()%2; // 0 = positive, 1 = negative if ( form == 0 ) { constraint += "" + v; } else { constraint += "~" + v; } constraint += ")"; varIndex = (varIndex < (numVars-1) ? varIndex+1 : 0); if ( varIndex == 0 ) scrumbleVars(vars); try { pfs.add(new PropositionalFormula("C"+(i+1),constraint)); } catch(Exception e) { e.printStackTrace(); } } } } return pfs; } private static void scrumbleVars(ArrayList<BooleanVariableInterface> vars) { int numVars = vars.size(); for( int i = 0 ; i < numVars ; i++ ) { int index = Math.abs(new Random().nextInt()%numVars); BooleanVariableInterface temp = vars.get(index); vars.set(index, vars.get(i)); vars.set(i, temp); } // System.out.println("scrambled ==>"); // for( int i = 0 ; i < numVars ; i++ ) { // System.out.print(vars.get(i).getName()+","); // } // System.out.println(""); } private static ArrayList<BooleanVariableInterface> chooseVariablesForConstraints(FeatureModel fm, int numVars) { ArrayList<BooleanVariableInterface> vars = new ArrayList<BooleanVariableInterface>(numVars); Collection<FeatureTreeNode> nodes = fm.getNodes(); int numNodes = nodes.size(); int varsGen = 0; while( varsGen < numVars ) { int random = Math.abs(new Random().nextInt()%numNodes); Iterator<FeatureTreeNode> it = nodes.iterator(); for( int i = 0 ; i < (random-1) ; i++ ) { it.next(); } FeatureTreeNode node = it.next(); if ( !(node instanceof FeatureGroup) && !(node instanceof RootNode) ) { if ( !vars.contains(node) ) { vars.add(node); varsGen++; } } } // System.out.println("choosen ==>"); // for( int i = 0 ; i < vars.size() ; i++ ) { // System.out.print(vars.get(i).getName()+","); // } // System.out.println(""); return vars; } public void saveNodes() {} }