1805d81a2080e700f182a859cf1df85781aa28ad
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.examples.adaptive.model.java;
23
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Random;
27 import org.onap.policy.apex.context.ContextException;
28 import org.onap.policy.apex.core.engine.executor.context.TaskSelectionExecutionContext;
29 import org.onap.policy.apex.examples.adaptive.concepts.AutoLearn;
30
31 /**
32  * The Class AutoLearnPolicyDecideTaskSelectionLogic.
33  */
34 public class AutoLearnPolicyDecideTaskSelectionLogic {
35     // Recurring string constants
36     private static final String AUTO_LEARN_ALBUM = "AutoLearnAlbum";
37     private static final String AUTO_LEARN = "AutoLearn";
38
39     /*
40      * This is not used for encryption/security, thus disabling sonar.
41      */
42     private static final Random RAND = new Random(System.currentTimeMillis());  // NOSONAR
43
44     private static final double WANT = 50.0;
45     private int size;
46
47     /**
48      * Gets the task.
49      *
50      * @param executor the executor
51      * @return the task
52      */
53     public boolean getTask(final TaskSelectionExecutionContext executor) {
54         String idString = executor.subject.getId();
55         executor.logger.debug(idString);
56
57         String inFieldsString = executor.inFields.toString();
58         executor.logger.debug(inFieldsString);
59
60         final List<String> tasks = executor.subject.getTaskNames();
61         size = tasks.size();
62
63         try {
64             executor.getContextAlbum(AUTO_LEARN_ALBUM).lockForWriting(AUTO_LEARN);
65         } catch (final ContextException e) {
66             executor.logger.error("Failed to acquire write lock on \"autoLearn\" context", e);
67             return false;
68         }
69
70         // Get the context object
71         AutoLearn autoLearn = (AutoLearn) executor.getContextAlbum(AUTO_LEARN_ALBUM).get(AUTO_LEARN);
72         if (autoLearn == null) {
73             autoLearn = new AutoLearn();
74         }
75
76         // Check the lists are initialized
77         if (!autoLearn.isInitialized()) {
78             autoLearn.init(size);
79         }
80
81         final double now = (Double) (executor.inFields.get("MonitoredValue"));
82         final double diff = now - WANT;
83         final int option = getOption(diff, autoLearn);
84         learn(option, diff, autoLearn);
85
86         executor.getContextAlbum(AUTO_LEARN_ALBUM).put(AUTO_LEARN_ALBUM, autoLearn);
87
88         try {
89             executor.getContextAlbum(AUTO_LEARN_ALBUM).unlockForWriting(AUTO_LEARN);
90         } catch (final ContextException e) {
91             executor.logger.error("Failed to acquire write lock on \"autoLearn\" context", e);
92             return false;
93         }
94
95         executor.subject.getTaskKey(tasks.get(option)).copyTo(executor.selectedTask);
96         return true;
97     }
98
99     /**
100      * Gets the option.
101      *
102      * @param diff the diff
103      * @param autoLearn the auto learn
104      * @return the option
105      */
106     private int getOption(final double diff, final AutoLearn autoLearn) {
107         final Double[] avdiffs = autoLearn.getAvDiffs().toArray(new Double[autoLearn.getAvDiffs().size()]);
108         final int r = RAND.nextInt(size);
109         int closestupi = -1;
110         int closestdowni = -1;
111         double closestup = Double.MAX_VALUE;
112         double closestdown = Double.MIN_VALUE;
113         for (int i = 0; i < size; i++) {
114             if (Double.isNaN(avdiffs[i])) {
115                 return r;
116             }
117             if (avdiffs[i] >= diff && avdiffs[i] <= closestup) {
118                 closestup = avdiffs[i];
119                 closestupi = i;
120             }
121             if (avdiffs[i] <= diff && avdiffs[i] >= closestdown) {
122                 closestdown = avdiffs[i];
123                 closestdowni = i;
124             }
125         }
126         return calculateReturnValue(diff, r, closestupi, closestdowni, closestup, closestdown);
127     }
128
129     /**
130      * Learn.
131      *
132      * @param option the option
133      * @param diff the diff
134      * @param autoLearn the auto learn
135      */
136     private void learn(final int option, final double diff, final AutoLearn autoLearn) {
137         final Double[] avdiffs = autoLearn.getAvDiffs().toArray(new Double[autoLearn.getAvDiffs().size()]);
138         final Long[] counts = autoLearn.getCounts().toArray(new Long[autoLearn.getCounts().size()]);
139         if (option < 0 || option >= avdiffs.length) {
140             throw new IllegalArgumentException("Error: option" + option);
141         }
142         counts[option]++;
143         if (Double.isNaN(avdiffs[option])) {
144             avdiffs[option] = diff;
145         } else {
146             avdiffs[option] = (avdiffs[option] * (counts[option] - 1) + diff) / counts[option];
147         }
148         autoLearn.setAvDiffs(Arrays.asList(avdiffs));
149         autoLearn.setCounts(Arrays.asList(counts));
150     }
151
152     /**
153      * Calculate the return value of the learning.
154      *
155      * @param diff the difference
156      * @param random the random value
157      * @param closestupi closest to i upwards
158      * @param closestdowni closest to i downwards
159      * @param closestup closest up value
160      * @param closestdown closest down value
161      * @return the return value
162      */
163     private int calculateReturnValue(final double diff, final int random, int closestupi, int closestdowni,
164         double closestup, double closestdown) {
165         if (closestupi == -1 || closestdowni == -1) {
166             return random;
167         }
168         if (closestupi == closestdowni) {
169             return closestupi;
170         }
171         if (Math.abs(closestdown - diff) > Math.abs(closestup - diff)) {
172             return closestupi;
173         } else {
174             return closestdowni;
175         }
176     }
177 }