Search code examples
javaarraysjava-streamoptaplannerelementwise-operations

Adding up arrays inside optaplanner constraint


In an Optaplanner constraint, I iterate over a set of planning entities that contain an attribute which is a time series of fixed size. I want to add up all the time series and check that the sum is always below a certain threshold.

In Optaplanner, the constraint would look like:

    public Constraint ResourceOverocupation(ConstraintFactory constraintFactory) {

    return constraintFactory
            .forEach(Operation.class)
            .map(operation -> operation.resourceUsage) 
            // operation.resourceUsage is an Array of fixed size, representing a time series
            // Now I want to add all the resourceUsage into an array of the same size.
            // Then I want to count how many items of the array are bigger than a value X and
            // add +1 to the score to optimize.
            .
            .penalize("Overocupation", HardMediumSoftScore.ONE_MEDIUM);
}

Outside Optaplanner, I guess the problem would be how to stream a list of objects, each of which contains a series of integers of the same size, and do an element-wise sum of these objects. This should result in a single list of the same size. It should be something like this...

Example:

Object object1;
ArrayList<int> array1 = Arrays.asList(1, 1, 1);
object1.ArrayOfInts = array1;

Object object2;
ArrayList<int> array2 = Arrays.asList(2, 2, 2);
object2.ArrayOfInts = array2; 


ArrayList<Object> listOfObjects = Arrays.asList(object1, object2);


ArrayList<Integer> result = listOfObjects.stream().map(object -> object.ArrayOfInts).sum(...

"result" would be [3, 3, 3].

Any help is welcome!


Solution

  •         MyObject object1 = new MyObject();
            object1.arrayOfInts = Arrays.asList(1, 1, 1);
    
            MyObject object2 = new MyObject();
            object2.arrayOfInts = Arrays.asList(2, 2, 2);
    
    
            List<MyObject> listOfObjects = Arrays.asList(object1, object2);
    
            List<Integer> sumList = IntStream.range(0, listOfObjects.get(0).arrayOfInts.size())
                    .mapToObj(i -> listOfObjects.stream()
                            .mapToInt(l -> l.arrayOfInts.get(i))
                            .sum())
                    .collect(Collectors.toList());
    

    Having MyObject to simply be:

    public class MyObject {
        List<Integer> arrayOfInts;
    }
    

    just for the purpose of compiling and testing, but you can adapt to your solution