From ef636b90adcf5577192119df7359667cb646df6b Mon Sep 17 00:00:00 2001 From: mandd Date: Fri, 5 Feb 2021 18:26:11 -0700 Subject: [PATCH 01/18] added src files and tests --- src/knapsack/MultipleKnapsackModel.py | 119 ++++++++++++++++++++++++ tests/gold/MultipleKnapsack/PrintPS.csv | 11 +++ 2 files changed, 130 insertions(+) create mode 100644 src/knapsack/MultipleKnapsackModel.py create mode 100644 tests/gold/MultipleKnapsack/PrintPS.csv diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py new file mode 100644 index 0000000..f4e6420 --- /dev/null +++ b/src/knapsack/MultipleKnapsackModel.py @@ -0,0 +1,119 @@ +# Copyright 2020, Battelle Energy Alliance, LLC +# ALL RIGHTS RESERVED +""" +Created on February 2, 2021 + +@author: mandd +""" + +#External Modules--------------------------------------------------------------- +import numpy as np +import math +import copy +#External Modules End----------------------------------------------------------- + +#Internal Modules--------------------------------------------------------------- +from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase +#Internal Modules End----------------------------------------------------------- + + +class MultipleKnapsackModel(ExternalModelPluginBase): + """ + This class is designed to create the MultipleKnapsack model + """ + def __init__(self): + """ + Constructor + @ In, None + @ Out, None + """ + ExternalModelPluginBase.__init__(self) + + self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied + self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint + self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements + self.N = None # number of knapsacks + + def _readMoreXML(self, container, xmlNode): + """ + Method to read the portion of the XML that belongs to the MultipleKnapsack model + @ In, container, object, self-like object where all the variables can be stored + @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read + @ Out, None + """ + container.mapping = {} + self.knapsackSet = {} + + for child in xmlNode: + if child.tag == 'penaltyFactor': + self.penaltyFactor = float(child.text.strip()) + elif child.tag == 'outcome': + self.outcome = child.text.strip() + elif child.tag == 'choiceValue': + self.choiceValue = child.text.strip() + elif child.tag == 'knapsack': + self.knapsackSet[child.get('ID')] = child.text.strip() + elif child.tag == 'map': + container.mapping[child.text.strip()] = [child.get('value'),child.get('cost')] + elif child.tag == 'variables': + variables = [str(var.strip()) for var in child.text.split(",")] + else: + raise IOError("MultipleKnapsackModel: xml node " + str (child.tag) + " is not allowed") + + + def initialize(self, container, runInfoDict, inputFiles): + """ + Method to initialize the MultipleKnapsack model + @ In, container, object, self-like object where all the variables can be stored + @ In, runInfoDict, dict, dictionary containing all the RunInfo parameters (XML node ) + @ In, inputFiles, list, list of input files (if any) + @ Out, None + """ + pass + + + def run(self, container, inputDict): + """ + This method calculates the sum of the chosen element values and check if the capacity constraints + for all knapsacks are satisfied + @ In, container, object, self-like object where all the variables can be stored + @ In, inputDict, dict, dictionary of inputs from RAVEN + """ + totalValue = 0.0 + print(self.knapsackSet) + knapsackSetValues={} + + # knapsackSetValues is a dictionary in the form {knapsackID: knapsackValue} + for knapsack in self.knapsackSet.keys(): + knapsackSetValues[knapsack] = inputDict[self.knapsackSet[knapsack]][0] + + # List of allowed knapsack IDs + elementAllowedValues = list(map(float, self.knapsackSet.keys())) + # Add 0.0 which implies that element has not been assign to any knapsack + elementAllowedValues.append(0.0) + + for key in container.mapping: + if key in inputDict.keys() and inputDict[key] in elementAllowedValues: + if inputDict[key] > 0.0: + knapsackChosen = str(int(inputDict[key][0])) + testValue = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] + if testValue >= 0: + knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] + totalValue = totalValue + inputDict[container.mapping[key][0]] + else: + knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] + totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor + else: + raise IOError("MultipleKnapsackModel: variable " + str(key) + " is either not found in the set of input variables or its values is not allowed.") + + numberUnsatConstraints = 0.0 + for knapsack in container.mapping.keys(): + if knapsackSetValues[knapsackChosen] < 0: + numberUnsatConstraints = numberUnsatConstraints + 1. + + if numberUnsatConstraints > 0.0 : + container.__dict__[self.outcome] = 1. + else: + container.__dict__[self.outcome] = 0. + + container.__dict__[self.choiceValue] = totalValue \ No newline at end of file diff --git a/tests/gold/MultipleKnapsack/PrintPS.csv b/tests/gold/MultipleKnapsack/PrintPS.csv new file mode 100644 index 0000000..89302fd --- /dev/null +++ b/tests/gold/MultipleKnapsack/PrintPS.csv @@ -0,0 +1,11 @@ +e1Status,e2Status,e3Status,e4Status,e5Status,e1Val,e2Val,e3Val,e4Val,e5Val,e1Cost,e2Cost,e3Cost,e4Cost,e5Cost,K1_cap,K2_cap,K3_cap,validity,totalValue +2.0,0.0,2.0,3.0,3.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,13.0 +3.0,2.0,2.0,1.0,0.0,1,2,3,4,5,2,3,3,4,4,5,5,5,0.0,10.0 +0.0,2.0,2.0,2.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,14.0 +3.0,1.0,2.0,2.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,15.0 +1.0,0.0,3.0,3.0,3.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,13.0 +2.0,3.0,0.0,3.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,12.0 +2.0,1.0,1.0,0.0,1.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,11.0 +3.0,2.0,2.0,2.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,15.0 +0.0,1.0,3.0,3.0,1.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,14.0 +2.0,2.0,0.0,1.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,12.0 From 251920cb01e64f414a70c38a6dafb1c4c9eafeac Mon Sep 17 00:00:00 2001 From: mandd Date: Fri, 5 Feb 2021 18:26:43 -0700 Subject: [PATCH 02/18] added test files --- tests/test_MultipleKnapsackModel.xml | 122 +++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tests/test_MultipleKnapsackModel.xml diff --git a/tests/test_MultipleKnapsackModel.xml b/tests/test_MultipleKnapsackModel.xml new file mode 100644 index 0000000..fbabed8 --- /dev/null +++ b/tests/test_MultipleKnapsackModel.xml @@ -0,0 +1,122 @@ + + + framework.MultipleKnapsack + mandd + 2021-02-02 + Models.ExternalModel.LOGOS.MultipleKnapsackModel + + This test is aimed to test the MultipleKnapsackModel class + + + + + MultipleKnapsack + Run + 1 + + + + + e1Status,e2Status,e3Status,e4Status,e5Status, + e1Val ,e2Val ,e3Val ,e4Val ,e5Val, + e1Cost ,e2Cost ,e3Cost ,e4Cost ,e5Cost, + validity,totalValue, + K1_cap,K2_cap,K3_cap + K1_cap + K2_cap + K3_cap + -1. + validity + totalValue + e1Status + e2Status + e3Status + e4Status + e5Status + + + + + + 0.25 + 0.25 + 0.25 + 0.25 + + + + + + + 10 + + + categorical + + + categorical + + + categorical + + + categorical + + + categorical + + + 1 + 2 + 3 + 4 + 5 + + 2 + 3 + 3 + 4 + 4 + + 5 + 5 + 5 + + + + + + dummyPS + knapsack + MC_external + dataPS + PrintPS + + + + + + csv + dataPS + input,output + + + + + + e1Status,e2Status,e3Status,e4Status,e5Status, + e1Val ,e2Val ,e3Val ,e4Val ,e5Val, + e1Cost ,e2Cost ,e3Cost ,e4Cost ,e5Cost, + K1_cap,K2_cap,K3_cap + OutputPlaceHolder + + + e1Status,e2Status,e3Status,e4Status,e5Status, + e1Val ,e2Val ,e3Val ,e4Val ,e5Val, + e1Cost ,e2Cost ,e3Cost ,e4Cost ,e5Cost, + K1_cap,K2_cap,K3_cap + validity,totalValue + + + + From 9356a641f81a4d13caea3b5e92b2f5c4fc0451cb Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 11:54:46 -0700 Subject: [PATCH 03/18] fixed files --- __init__.py | 1 + src/knapsack/MultipleKnapsackModel.py | 40 +++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/__init__.py b/__init__.py index 010e691..d6ef648 100644 --- a/__init__.py +++ b/__init__.py @@ -8,3 +8,4 @@ from LOGOS.src import CapitalInvestmentModel from LOGOS.src import BatteryReplacementCashFlowModel from LOGOS.src import IncrementalNPV +from LOGOS.src.knapsack import MultipleKnapsackModel \ No newline at end of file diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index f4e6420..a0d3285 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -14,6 +14,7 @@ #Internal Modules--------------------------------------------------------------- from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase +from utils import InputData, InputTypes #Internal Modules End----------------------------------------------------------- @@ -21,6 +22,33 @@ class MultipleKnapsackModel(ExternalModelPluginBase): """ This class is designed to create the MultipleKnapsack model """ + + @classmethod + def getInputSpecs(cls): + """ + Collects input specifications for this class. + @ In, None + @ Out, inputSpecs, InputData, input specifications + """ + inputSpecs = InputData.parameterInputFactory('ExternalModel') + inputSpecs.addParam('name' , param_type=InputTypes.StringType, required=True) + inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) + + inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) + inputSpecs.addSub(InputData.parameterInputFactory('outcome' , contentType=InputTypes.StringType), required=True) + inputSpecs.addSub(InputData.parameterInputFactory('choiceValue' , contentType=InputTypes.StringType), required=True) + + knapsack = InputData.parameterInputFactory('knapsack', contentType=InputTypes.StringType) + knapsack.addParam('ID', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(knapsack) + + mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) + mapping.addParam('value', param_type=InputTypes.StringType, required=True) + mapping.addParam('cost', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(mapping) + + return inputSpecs + def __init__(self): """ Constructor @@ -80,7 +108,6 @@ def run(self, container, inputDict): @ In, inputDict, dict, dictionary of inputs from RAVEN """ totalValue = 0.0 - print(self.knapsackSet) knapsackSetValues={} # knapsackSetValues is a dictionary in the form {knapsackID: knapsackValue} @@ -98,22 +125,23 @@ def run(self, container, inputDict): knapsackChosen = str(int(inputDict[key][0])) testValue = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] if testValue >= 0: - knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] + knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] totalValue = totalValue + inputDict[container.mapping[key][0]] else: - knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] + knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor else: raise IOError("MultipleKnapsackModel: variable " + str(key) + " is either not found in the set of input variables or its values is not allowed.") numberUnsatConstraints = 0.0 - for knapsack in container.mapping.keys(): - if knapsackSetValues[knapsackChosen] < 0: + for knapsack in knapsackSetValues.keys(): + if knapsackSetValues[knapsack] < 0: numberUnsatConstraints = numberUnsatConstraints + 1. if numberUnsatConstraints > 0.0 : container.__dict__[self.outcome] = 1. else: container.__dict__[self.outcome] = 0. - + + print(knapsackSetValues) container.__dict__[self.choiceValue] = totalValue \ No newline at end of file From c37bbc662f7ea5e7ddec605450ff94347f3f6d78 Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 13:10:04 -0700 Subject: [PATCH 04/18] added doc section --- doc/user_manual/include/Knapsack.tex | 55 +++++++++++++++++++++++++-- src/knapsack/BaseKnapsackModel.py | 4 +- src/knapsack/MultipleKnapsackModel.py | 2 +- tests/test_BaseKnapsackModel.xml | 16 +++++--- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/doc/user_manual/include/Knapsack.tex b/doc/user_manual/include/Knapsack.tex index 9965f8f..e8a1cc7 100644 --- a/doc/user_manual/include/Knapsack.tex +++ b/doc/user_manual/include/Knapsack.tex @@ -9,12 +9,13 @@ \section{Knapsack Models} find the optimal solution. -\subsection{BaseKnapsackModel} +\subsection{BaseKnapsack Model} \label{subsec:BaseKnapsackModel} This model considers the classical Knapsack Model characterized by a set of elements that can be chosen (or not). The goal is to maximize the sum of the chosen element values provided that the sum of -element cost values satisfy capacity constraint (specified in the \xmlNode{capacity} node). +element cost values satisfy capacity constraint (specified in the variable defined +in the \xmlNode{capacity} node). The ID of the variables that represent cost, value, and choice of each element are indicated in the \xmlNode{map} node. @@ -30,7 +31,7 @@ \subsection{BaseKnapsackModel} is not satisfied, then the \xmlNode{choiceValue} variable is penalized by multiplying the project value by -\xmlNode{penaltyFactor}. -Example LOGOS input XML for DRO: +Example LOGOS input XML for BaseKnapsack Model: \begin{lstlisting}[style=XML] @@ -48,3 +49,51 @@ \subsection{BaseKnapsackModel} \end{lstlisting} + + +\subsection{MultipleKnapsack Model} +\label{subsec:MultipleKnapsackModel} +This model considers the Multiple Knapsack Model characterized by a set of elements +that can be chosen (or not) over a set of multiple knapsacks. +The goal is to maximize the sum of the chosen element values provided that the sum of +element cost values satisfy capacity constraints of each knapsack. + +The capacity of each knapsack is defined in the \xmlNode{knapsack} node. + +The ID of the variables that represent cost, value, and choice of each element are +indicated in the \xmlNode{map} node. +The model generates two variables: +\begin{itemize} + \item the validity of the chosen solution (specified in the \xmlNode{outcome} node): either + valid (i.e., 0), or invalid (i.e., 1) if the capacity constraint is not satisfied, + \item totalValue (specified in the \xmlNode{choiceValue} node): sum of the values of the + chosen elements +\end{itemize} + +When calculating the \xmlNode{choiceValue} variable, if the capacity constraints +are not satisfied, then the \xmlNode{choiceValue} variable is penalized by multiplying the +project value by -\xmlNode{penaltyFactor}. + +Example LOGOS input XML for MultipleKnapsack Model: +\begin{lstlisting}[style=XML] + + + e1Status,e2Status,e3Status,e4Status,e5Status, + e1Val ,e2Val ,e3Val ,e4Val ,e5Val, + e1Cost ,e2Cost ,e3Cost ,e4Cost ,e5Cost, + validity,totalValue, + K1_cap,K2_cap,K3_cap + K1_cap + K2_cap + K3_cap + 1. + validity + totalValue + e1Status + e2Status + e3Status + e4Status + e5Status + + +\end{lstlisting} diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 965db9f..d0b67ac 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -45,7 +45,7 @@ def _readMoreXML(self, container, xmlNode): for child in xmlNode: if child.tag == 'capacity': - self.capacity = float(child.text.strip()) + self.capacityID = child.text.strip() elif child.tag == 'penaltyFactor': self.penaltyFactor = float(child.text.strip()) elif child.tag == 'outcome': @@ -80,6 +80,8 @@ def run(self, container, inputDict): """ totalValue = 0.0 + self.capacity = inputDict[self.capacityID] + for key in container.mapping: if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: if inputDict[key] == 1.0: diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index a0d3285..dadfbcf 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -116,7 +116,7 @@ def run(self, container, inputDict): # List of allowed knapsack IDs elementAllowedValues = list(map(float, self.knapsackSet.keys())) - # Add 0.0 which implies that element has not been assign to any knapsack + # Add 0.0 which implies that the element has not been assigned to any knapsack elementAllowedValues.append(0.0) for key in container.mapping: diff --git a/tests/test_BaseKnapsackModel.xml b/tests/test_BaseKnapsackModel.xml index 43645b8..a2eba08 100644 --- a/tests/test_BaseKnapsackModel.xml +++ b/tests/test_BaseKnapsackModel.xml @@ -18,10 +18,10 @@ element1Status,element2Status,element3Status,element4Status,element5Status, - element1Val,element2Val,element3Val,element4Val,element5Val, - element1Cost,element2Cost,element3Cost,element4Cost,element5Cost, - validity,totalValue - 10 + element1Val ,element2Val ,element3Val ,element4Val ,element5Val, + element1Cost ,element2Cost ,element3Cost ,element4Cost,element5Cost, + validity,totalValue,capacityID + capacityID 1. validity totalValue @@ -71,6 +71,8 @@ 1 1 1 + + 10 @@ -96,13 +98,15 @@ element1Status,element2Status,element3Status,element4Status,element5Status, element1Val,element2Val,element3Val,element4Val,element5Val, - element1Cost,element2Cost,element3Cost,element4Cost,element5Cost + element1Cost,element2Cost,element3Cost,element4Cost,element5Cost, + OutputPlaceHolder element1Status,element2Status,element3Status,element4Status,element5Status, element1Val,element2Val,element3Val,element4Val,element5Val, - element1Cost,element2Cost,element3Cost,element4Cost,element5Cost + element1Cost,element2Cost,element3Cost,element4Cost,element5Cost, + capacityID validity,totalValue From c65556e45160054d2115dcef0611789c764e713d Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 13:31:52 -0700 Subject: [PATCH 05/18] delete whitespaces --- src/knapsack/BaseKnapsackModel.py | 8 ++--- src/knapsack/MultipleKnapsackModel.py | 52 +++++++++++++-------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 2bc727a..ab7df5b 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -107,11 +107,11 @@ def run(self, container, inputDict): is satisfied @ In, container, object, self-like object where all the variables can be stored @ In, inputDict, dict, dictionary of inputs from RAVEN - """ - totalValue = 0.0 - + """ + totalValue = 0.0 + self.capacity = inputDict[self.capacityID] - + for key in container.mapping: if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: if inputDict[key] == 1.0: diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index dadfbcf..1c7213f 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -1,7 +1,7 @@ # Copyright 2020, Battelle Energy Alliance, LLC # ALL RIGHTS RESERVED """ -Created on February 2, 2021 +Created on February 7, 2021 @author: mandd """ @@ -22,7 +22,7 @@ class MultipleKnapsackModel(ExternalModelPluginBase): """ This class is designed to create the MultipleKnapsack model """ - + @classmethod def getInputSpecs(cls): """ @@ -33,22 +33,22 @@ def getInputSpecs(cls): inputSpecs = InputData.parameterInputFactory('ExternalModel') inputSpecs.addParam('name' , param_type=InputTypes.StringType, required=True) inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) - + inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) inputSpecs.addSub(InputData.parameterInputFactory('outcome' , contentType=InputTypes.StringType), required=True) inputSpecs.addSub(InputData.parameterInputFactory('choiceValue' , contentType=InputTypes.StringType), required=True) - + knapsack = InputData.parameterInputFactory('knapsack', contentType=InputTypes.StringType) knapsack.addParam('ID', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(knapsack) - + mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) mapping.addParam('value', param_type=InputTypes.StringType, required=True) mapping.addParam('cost', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(mapping) - + return inputSpecs - + def __init__(self): """ Constructor @@ -56,12 +56,12 @@ def __init__(self): @ Out, None """ ExternalModelPluginBase.__init__(self) - + self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements self.N = None # number of knapsacks - + def _readMoreXML(self, container, xmlNode): """ Method to read the portion of the XML that belongs to the MultipleKnapsack model @@ -71,7 +71,7 @@ def _readMoreXML(self, container, xmlNode): """ container.mapping = {} self.knapsackSet = {} - + for child in xmlNode: if child.tag == 'penaltyFactor': self.penaltyFactor = float(child.text.strip()) @@ -87,8 +87,8 @@ def _readMoreXML(self, container, xmlNode): variables = [str(var.strip()) for var in child.text.split(",")] else: raise IOError("MultipleKnapsackModel: xml node " + str (child.tag) + " is not allowed") - - + + def initialize(self, container, runInfoDict, inputFiles): """ Method to initialize the MultipleKnapsack model @@ -97,28 +97,28 @@ def initialize(self, container, runInfoDict, inputFiles): @ In, inputFiles, list, list of input files (if any) @ Out, None """ - pass - - + pass + + def run(self, container, inputDict): """ This method calculates the sum of the chosen element values and check if the capacity constraints for all knapsacks are satisfied @ In, container, object, self-like object where all the variables can be stored @ In, inputDict, dict, dictionary of inputs from RAVEN - """ - totalValue = 0.0 + """ + totalValue = 0.0 knapsackSetValues={} - + # knapsackSetValues is a dictionary in the form {knapsackID: knapsackValue} for knapsack in self.knapsackSet.keys(): knapsackSetValues[knapsack] = inputDict[self.knapsackSet[knapsack]][0] - + # List of allowed knapsack IDs elementAllowedValues = list(map(float, self.knapsackSet.keys())) # Add 0.0 which implies that the element has not been assigned to any knapsack elementAllowedValues.append(0.0) - + for key in container.mapping: if key in inputDict.keys() and inputDict[key] in elementAllowedValues: if inputDict[key] > 0.0: @@ -132,16 +132,16 @@ def run(self, container, inputDict): totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor else: raise IOError("MultipleKnapsackModel: variable " + str(key) + " is either not found in the set of input variables or its values is not allowed.") - + numberUnsatConstraints = 0.0 - for knapsack in knapsackSetValues.keys(): + for knapsack in knapsackSetValues.keys(): if knapsackSetValues[knapsack] < 0: numberUnsatConstraints = numberUnsatConstraints + 1. - + if numberUnsatConstraints > 0.0 : container.__dict__[self.outcome] = 1. else: - container.__dict__[self.outcome] = 0. + container.__dict__[self.outcome] = 0. - print(knapsackSetValues) - container.__dict__[self.choiceValue] = totalValue \ No newline at end of file + print(knapsackSetValues) + container.__dict__[self.choiceValue] = totalValue From fe314aca4ff52758dec56195e17625a6f0e34bdc Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 13:49:40 -0700 Subject: [PATCH 06/18] fixed files --- doc/user_manual/include/Knapsack.tex | 14 +++++++------- src/knapsack/BaseKnapsackModel.py | 12 ++++++------ src/knapsack/MultipleKnapsackModel.py | 1 - tests/test_BaseKnapsackModel.xml | 1 + 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/user_manual/include/Knapsack.tex b/doc/user_manual/include/Knapsack.tex index e8a1cc7..2994570 100644 --- a/doc/user_manual/include/Knapsack.tex +++ b/doc/user_manual/include/Knapsack.tex @@ -33,21 +33,21 @@ \subsection{BaseKnapsack Model} Example LOGOS input XML for BaseKnapsack Model: \begin{lstlisting}[style=XML] - - element1Status,element2Status,element3Status, - element1Val ,element2Val ,element3Val, - element1Cost ,element2Cost ,element3Cost, - validity ,totalValue - 10 + element1Status,element2Status,element3Status,element4Status,element5Status, + element1Val ,element2Val ,element3Val ,element4Val ,element5Val, + element1Cost ,element2Cost ,element3Cost ,element4Cost,element5Cost, + validity,totalValue,capacityID + capacityID 1. validity totalValue element1Status element2Status element3Status + element4Status + element5Status - \end{lstlisting} diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index ab7df5b..f233d4e 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -22,6 +22,7 @@ class BaseKnapsackModel(ExternalModelPluginBase): """ This class is designed to create the BaseKnapsack model """ + @classmethod def getInputSpecs(cls): """ @@ -109,18 +110,17 @@ def run(self, container, inputDict): @ In, inputDict, dict, dictionary of inputs from RAVEN """ totalValue = 0.0 - - self.capacity = inputDict[self.capacityID] + capacity = inputDict[self.capacity][0] for key in container.mapping: if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: if inputDict[key] == 1.0: - testValue = self.capacity - inputDict[container.mapping[key][1]] + testValue = capacity - inputDict[container.mapping[key][1]] if testValue >= 0: - self.capacity = self.capacity - inputDict[container.mapping[key][1]] + capacity = capacity - inputDict[container.mapping[key][1]] totalValue = totalValue + inputDict[container.mapping[key][0]] else: - self.capacity = self.capacity - inputDict[container.mapping[key][1]] + capacity = capacity - inputDict[container.mapping[key][1]] totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor elif inputDict[key] == 0.0: pass @@ -129,7 +129,7 @@ def run(self, container, inputDict): else: raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") - if self.capacity>=0: + if capacity>=0: container.__dict__[self.outcome] = 0. else: container.__dict__[self.outcome] = 1. diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index 1c7213f..f20e145 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -60,7 +60,6 @@ def __init__(self): self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements - self.N = None # number of knapsacks def _readMoreXML(self, container, xmlNode): """ diff --git a/tests/test_BaseKnapsackModel.xml b/tests/test_BaseKnapsackModel.xml index a2eba08..fb3caf7 100644 --- a/tests/test_BaseKnapsackModel.xml +++ b/tests/test_BaseKnapsackModel.xml @@ -99,6 +99,7 @@ element1Status,element2Status,element3Status,element4Status,element5Status, element1Val,element2Val,element3Val,element4Val,element5Val, element1Cost,element2Cost,element3Cost,element4Cost,element5Cost, + capacityID OutputPlaceHolder From eee6250040ad2dcf398d7a0c7b623c5ca8ab33bc Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 13:52:14 -0700 Subject: [PATCH 07/18] delete whitespaces --- src/knapsack/BaseKnapsackModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index f233d4e..b2d642c 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -22,7 +22,7 @@ class BaseKnapsackModel(ExternalModelPluginBase): """ This class is designed to create the BaseKnapsack model """ - + @classmethod def getInputSpecs(cls): """ From 72c5a32dc5b68cde6caa0113c036f82054274ec0 Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 14:19:58 -0700 Subject: [PATCH 08/18] fixed error --- src/knapsack/BaseKnapsackModel.py | 2 ++ tests/gold/BaseKnapsack/PrintPS.csv | 22 +++++++++++----------- tests/test_BaseKnapsackModel.xml | 10 +++++----- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index b2d642c..853d0d4 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -111,6 +111,7 @@ def run(self, container, inputDict): """ totalValue = 0.0 capacity = inputDict[self.capacity][0] + print(capacity) for key in container.mapping: if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: @@ -120,6 +121,7 @@ def run(self, container, inputDict): capacity = capacity - inputDict[container.mapping[key][1]] totalValue = totalValue + inputDict[container.mapping[key][0]] else: + print('======') capacity = capacity - inputDict[container.mapping[key][1]] totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor elif inputDict[key] == 0.0: diff --git a/tests/gold/BaseKnapsack/PrintPS.csv b/tests/gold/BaseKnapsack/PrintPS.csv index 06518d7..b960dfb 100644 --- a/tests/gold/BaseKnapsack/PrintPS.csv +++ b/tests/gold/BaseKnapsack/PrintPS.csv @@ -1,11 +1,11 @@ -element1Status,element2Status,element3Status,element4Status,element5Status,element1Val,element2Val,element3Val,element4Val,element5Val,element1Cost,element2Cost,element3Cost,element4Cost,element5Cost,validity,totalValue -1.0,0.0,1.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,0.0,13.0 -1.0,1.0,1.0,0.0,0.0,1,2,3,4,5,1,1,1,1,1,0.0,6.0 -0.0,1.0,1.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,4.0 -1.0,0.0,1.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,-13.0 -0.0,0.0,1.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,-12.0 -1.0,1.0,0.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,-12.0 -1.0,0.0,0.0,0.0,0.0,1,2,3,4,5,1,1,1,1,1,1.0,-1.0 -1.0,1.0,1.0,1.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,-15.0 -0.0,0.0,1.0,1.0,0.0,1,2,3,4,5,1,1,1,1,1,1.0,-7.0 -1.0,1.0,0.0,0.0,1.0,1,2,3,4,5,1,1,1,1,1,1.0,-8.0 +element1Status,element2Status,element3Status,element4Status,element5Status,element1Val,element2Val,element3Val,element4Val,element5Val,element1Cost,element2Cost,element3Cost,element4Cost,element5Cost,capacityID,validity,totalValue +1.0,0.0,1.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,3.0 +1.0,1.0,1.0,0.0,0.0,1,2,3,4,5,2,3,3,4,4,10,0.0,6.0 +0.0,1.0,1.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,4.0 +1.0,0.0,1.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,3.0 +0.0,0.0,1.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,2.0 +1.0,1.0,0.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,2.0 +1.0,0.0,0.0,0.0,0.0,1,2,3,4,5,2,3,3,4,4,10,0.0,1.0 +1.0,1.0,1.0,1.0,1.0,1,2,3,4,5,2,3,3,4,4,10,1.0,-3.0 +0.0,0.0,1.0,1.0,0.0,1,2,3,4,5,2,3,3,4,4,10,0.0,7.0 +1.0,1.0,0.0,0.0,1.0,1,2,3,4,5,2,3,3,4,4,10,0.0,8.0 diff --git a/tests/test_BaseKnapsackModel.xml b/tests/test_BaseKnapsackModel.xml index fb3caf7..750a6ec 100644 --- a/tests/test_BaseKnapsackModel.xml +++ b/tests/test_BaseKnapsackModel.xml @@ -66,11 +66,11 @@ 4 5 - 1 - 1 - 1 - 1 - 1 + 2 + 3 + 3 + 4 + 4 10 From 6141ab1bda015ff6ad238481258429eb2d284c8a Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 18:06:46 -0700 Subject: [PATCH 09/18] addressing reviewer's comments --- src/knapsack/BaseKnapsackModel.py | 10 ++-- src/knapsack/MultipleKnapsackModel.py | 65 ++++++++++++++----------- tests/gold/MultipleKnapsack/PrintPS.csv | 2 +- tests/tests | 6 +++ 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 853d0d4..5297aca 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -111,18 +111,14 @@ def run(self, container, inputDict): """ totalValue = 0.0 capacity = inputDict[self.capacity][0] - print(capacity) for key in container.mapping: if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: if inputDict[key] == 1.0: - testValue = capacity - inputDict[container.mapping[key][1]] - if testValue >= 0: - capacity = capacity - inputDict[container.mapping[key][1]] + capacity = capacity - inputDict[container.mapping[key][1]][0] + if capacity >= 0: totalValue = totalValue + inputDict[container.mapping[key][0]] else: - print('======') - capacity = capacity - inputDict[container.mapping[key][1]] totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor elif inputDict[key] == 0.0: pass @@ -130,7 +126,7 @@ def run(self, container, inputDict): raise IOError("BaseKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") else: raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") - + if capacity>=0: container.__dict__[self.outcome] = 0. else: diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index f20e145..fc06744 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -35,8 +35,8 @@ def getInputSpecs(cls): inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) - inputSpecs.addSub(InputData.parameterInputFactory('outcome' , contentType=InputTypes.StringType), required=True) - inputSpecs.addSub(InputData.parameterInputFactory('choiceValue' , contentType=InputTypes.StringType), required=True) + inputSpecs.addSub(InputData.parameterInputFactory('outcome' , contentType=InputTypes.StringType)) + inputSpecs.addSub(InputData.parameterInputFactory('choiceValue' , contentType=InputTypes.StringType)) knapsack = InputData.parameterInputFactory('knapsack', contentType=InputTypes.StringType) knapsack.addParam('ID', param_type=InputTypes.StringType, required=True) @@ -46,6 +46,12 @@ def getInputSpecs(cls): mapping.addParam('value', param_type=InputTypes.StringType, required=True) mapping.addParam('cost', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(mapping) + + inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) + map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) + map.addParam('value', param_type=InputTypes.StringType, required=True) + map.addParam('cost', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(map) return inputSpecs @@ -71,21 +77,26 @@ def _readMoreXML(self, container, xmlNode): container.mapping = {} self.knapsackSet = {} - for child in xmlNode: - if child.tag == 'penaltyFactor': - self.penaltyFactor = float(child.text.strip()) - elif child.tag == 'outcome': - self.outcome = child.text.strip() - elif child.tag == 'choiceValue': - self.choiceValue = child.text.strip() - elif child.tag == 'knapsack': - self.knapsackSet[child.get('ID')] = child.text.strip() - elif child.tag == 'map': - container.mapping[child.text.strip()] = [child.get('value'),child.get('cost')] - elif child.tag == 'variables': - variables = [str(var.strip()) for var in child.text.split(",")] + specs = self.getInputSpecs()() + specs.parseNode(xmlNode) + + for node in specs.subparts: + name = node.getName() + val = node.value + if name == 'penaltyFactor': + self.penaltyFactor = val + elif name == 'outcome': + self.outcome = val + elif name == 'choiceValue': + self.choiceValue = val + elif name == 'knapsack': + self.knapsackSet[node.parameterValues['ID']] = val + elif name == 'map': + container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] + elif name == 'variables': + variables = val else: - raise IOError("MultipleKnapsackModel: xml node " + str (child.tag) + " is not allowed") + raise IOError("MultipleKnapsackModel: xml node " + str(name) + " is not allowed") def initialize(self, container, runInfoDict, inputFiles): @@ -111,36 +122,34 @@ def run(self, container, inputDict): # knapsackSetValues is a dictionary in the form {knapsackID: knapsackValue} for knapsack in self.knapsackSet.keys(): - knapsackSetValues[knapsack] = inputDict[self.knapsackSet[knapsack]][0] + if self.knapsackSet[knapsack] in inputDict.keys(): + knapsackSetValues[knapsack] = inputDict[self.knapsackSet[knapsack]][0] + else: + raise IOError("MultipleKnapsackModel: variable " + str(self.knapsackSet[knapsack]) + " has not been found in the input dataObject.") # List of allowed knapsack IDs elementAllowedValues = list(map(float, self.knapsackSet.keys())) # Add 0.0 which implies that the element has not been assigned to any knapsack elementAllowedValues.append(0.0) + + numberUnsatConstraints = 0.0 for key in container.mapping: if key in inputDict.keys() and inputDict[key] in elementAllowedValues: if inputDict[key] > 0.0: knapsackChosen = str(int(inputDict[key][0])) - testValue = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]] - if testValue >= 0: - knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] + knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] + if knapsackSetValues[knapsackChosen] >= 0: totalValue = totalValue + inputDict[container.mapping[key][0]] else: - knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor + numberUnsatConstraints = numberUnsatConstraints + 1. else: raise IOError("MultipleKnapsackModel: variable " + str(key) + " is either not found in the set of input variables or its values is not allowed.") - numberUnsatConstraints = 0.0 - for knapsack in knapsackSetValues.keys(): - if knapsackSetValues[knapsack] < 0: - numberUnsatConstraints = numberUnsatConstraints + 1. - if numberUnsatConstraints > 0.0 : container.__dict__[self.outcome] = 1. else: container.__dict__[self.outcome] = 0. - - print(knapsackSetValues) + container.__dict__[self.choiceValue] = totalValue diff --git a/tests/gold/MultipleKnapsack/PrintPS.csv b/tests/gold/MultipleKnapsack/PrintPS.csv index 89302fd..6211060 100644 --- a/tests/gold/MultipleKnapsack/PrintPS.csv +++ b/tests/gold/MultipleKnapsack/PrintPS.csv @@ -1,6 +1,6 @@ e1Status,e2Status,e3Status,e4Status,e5Status,e1Val,e2Val,e3Val,e4Val,e5Val,e1Cost,e2Cost,e3Cost,e4Cost,e5Cost,K1_cap,K2_cap,K3_cap,validity,totalValue 2.0,0.0,2.0,3.0,3.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,13.0 -3.0,2.0,2.0,1.0,0.0,1,2,3,4,5,2,3,3,4,4,5,5,5,0.0,10.0 +3.0,2.0,2.0,1.0,0.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,10.0 0.0,2.0,2.0,2.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,14.0 3.0,1.0,2.0,2.0,2.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,15.0 1.0,0.0,3.0,3.0,3.0,1,2,3,4,5,2,3,3,4,4,5,5,5,1.0,13.0 diff --git a/tests/tests b/tests/tests index f9639f1..8998a78 100644 --- a/tests/tests +++ b/tests/tests @@ -49,4 +49,10 @@ UnorderedCsv = 'BaseKnapsack/PrintPS.csv' [../] + [./MultipleKnapsack] + type = 'RavenFramework' + input = 'test_MultipleKnapsackModel.xml' + UnorderedCsv = 'MultipleKnapsack/PrintPS.csv' + [../] + [] From b4dd50f4b3f185b6add9e76e6a2daef5a27c9496 Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 18:19:43 -0700 Subject: [PATCH 10/18] delete whitespaces --- src/knapsack/BaseKnapsackModel.py | 2 +- src/knapsack/MultipleKnapsackModel.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 5297aca..d71fc2c 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -126,7 +126,7 @@ def run(self, container, inputDict): raise IOError("BaseKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") else: raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") - + if capacity>=0: container.__dict__[self.outcome] = 0. else: diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index fc06744..82c39f9 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -46,7 +46,7 @@ def getInputSpecs(cls): mapping.addParam('value', param_type=InputTypes.StringType, required=True) mapping.addParam('cost', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(mapping) - + inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) map.addParam('value', param_type=InputTypes.StringType, required=True) @@ -79,7 +79,7 @@ def _readMoreXML(self, container, xmlNode): specs = self.getInputSpecs()() specs.parseNode(xmlNode) - + for node in specs.subparts: name = node.getName() val = node.value @@ -131,7 +131,7 @@ def run(self, container, inputDict): elementAllowedValues = list(map(float, self.knapsackSet.keys())) # Add 0.0 which implies that the element has not been assigned to any knapsack elementAllowedValues.append(0.0) - + numberUnsatConstraints = 0.0 for key in container.mapping: @@ -139,7 +139,7 @@ def run(self, container, inputDict): if inputDict[key] > 0.0: knapsackChosen = str(int(inputDict[key][0])) knapsackSetValues[knapsackChosen] = knapsackSetValues[knapsackChosen] - inputDict[container.mapping[key][1]][0] - if knapsackSetValues[knapsackChosen] >= 0: + if knapsackSetValues[knapsackChosen] >= 0: totalValue = totalValue + inputDict[container.mapping[key][0]] else: totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor @@ -151,5 +151,5 @@ def run(self, container, inputDict): container.__dict__[self.outcome] = 1. else: container.__dict__[self.outcome] = 0. - + container.__dict__[self.choiceValue] = totalValue From cb3b3b31bc038d6c1dfdcd074a4156a7614218cd Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 18:33:41 -0700 Subject: [PATCH 11/18] fixed typos --- src/CapitalInvestments/PyomoModels/MultipleKnapsack.py | 2 +- src/knapsack/BaseKnapsackModel.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CapitalInvestments/PyomoModels/MultipleKnapsack.py b/src/CapitalInvestments/PyomoModels/MultipleKnapsack.py index b8c0831..a55bb0d 100644 --- a/src/CapitalInvestments/PyomoModels/MultipleKnapsack.py +++ b/src/CapitalInvestments/PyomoModels/MultipleKnapsack.py @@ -147,7 +147,7 @@ def addVariables(self, model): """ model = KnapsackBase.addVariables(self, model) def boundsExpression(model, i, j): - """ set the bounds for soluion variable x using lowerBounds and upperBounds""" + """ set the bounds for solution variable x using lowerBounds and upperBounds""" return (self.lowerBounds[i], self.upperBounds[i]) model.x = pyomo.Var(model.investments, model.capitals, domain=pyomo.NonNegativeIntegers, bounds=boundsExpression) return model diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index d71fc2c..8eaa5ec 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -33,15 +33,18 @@ def getInputSpecs(cls): inputSpecs = InputData.parameterInputFactory('ExternalModel') inputSpecs.addParam('name', param_type=InputTypes.StringType, required=True) inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) inputSpecs.addSub(InputData.parameterInputFactory('outcome', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('choiceValue', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) + map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) map.addParam('value', param_type=InputTypes.StringType, required=True) map.addParam('cost', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(map) + alias = InputData.parameterInputFactory('alias', contentType=InputTypes.StringType) alias.addParam('variable', param_type=InputTypes.StringType, required=True) alias.addParam('type', param_type=InputTypes.StringType, required=True) From 465135ee95c27662124aebaedecdc1ddf313c801 Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 8 Feb 2021 20:37:39 -0700 Subject: [PATCH 12/18] delete whitespaces --- src/knapsack/BaseKnapsackModel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 8eaa5ec..ba0e0bc 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -33,18 +33,18 @@ def getInputSpecs(cls): inputSpecs = InputData.parameterInputFactory('ExternalModel') inputSpecs.addParam('name', param_type=InputTypes.StringType, required=True) inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) - + inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) inputSpecs.addSub(InputData.parameterInputFactory('outcome', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('choiceValue', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) - + map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) map.addParam('value', param_type=InputTypes.StringType, required=True) map.addParam('cost', param_type=InputTypes.StringType, required=True) inputSpecs.addSub(map) - + alias = InputData.parameterInputFactory('alias', contentType=InputTypes.StringType) alias.addParam('variable', param_type=InputTypes.StringType, required=True) alias.addParam('type', param_type=InputTypes.StringType, required=True) From 639ba75a1ef94bd0e41679d574122eee76818812 Mon Sep 17 00:00:00 2001 From: mandd Date: Mon, 15 Feb 2021 18:12:08 -0700 Subject: [PATCH 13/18] added base class --- src/knapsack/BaseKnapsackModel.py | 50 ++--------- src/knapsack/SimpleKnapsackModel.py | 131 ++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 42 deletions(-) create mode 100644 src/knapsack/SimpleKnapsackModel.py diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index ba0e0bc..b57ea84 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -7,9 +7,7 @@ """ #External Modules--------------------------------------------------------------- -import numpy as np -import math -import copy + #External Modules End----------------------------------------------------------- #Internal Modules--------------------------------------------------------------- @@ -20,7 +18,7 @@ class BaseKnapsackModel(ExternalModelPluginBase): """ - This class is designed to create the BaseKnapsack model + This class is designed to create the base class for the knapsack models """ @classmethod @@ -34,21 +32,15 @@ def getInputSpecs(cls): inputSpecs.addParam('name', param_type=InputTypes.StringType, required=True) inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) inputSpecs.addSub(InputData.parameterInputFactory('outcome', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('choiceValue', contentType=InputTypes.StringType)) inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) - map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) - map.addParam('value', param_type=InputTypes.StringType, required=True) - map.addParam('cost', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(map) - - alias = InputData.parameterInputFactory('alias', contentType=InputTypes.StringType) - alias.addParam('variable', param_type=InputTypes.StringType, required=True) - alias.addParam('type', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(alias) + mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) + mapping.addParam('value', param_type=InputTypes.StringType, required=True) + mapping.addParam('cost', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(mapping) return inputSpecs @@ -60,7 +52,6 @@ def __init__(self): """ ExternalModelPluginBase.__init__(self) - self.capacity = None # capacity value of the knapsack self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements @@ -79,9 +70,7 @@ def _readMoreXML(self, container, xmlNode): for node in specs.subparts: name = node.getName() val = node.value - if name == 'capacity': - self.capacity = val - elif name == 'penaltyFactor': + if name == 'penaltyFactor': self.penaltyFactor = val elif name == 'outcome': self.outcome = val @@ -112,27 +101,4 @@ def run(self, container, inputDict): @ In, container, object, self-like object where all the variables can be stored @ In, inputDict, dict, dictionary of inputs from RAVEN """ - totalValue = 0.0 - capacity = inputDict[self.capacity][0] - - for key in container.mapping: - if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: - if inputDict[key] == 1.0: - capacity = capacity - inputDict[container.mapping[key][1]][0] - if capacity >= 0: - totalValue = totalValue + inputDict[container.mapping[key][0]] - else: - totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor - elif inputDict[key] == 0.0: - pass - else: - raise IOError("BaseKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") - else: - raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") - - if capacity>=0: - container.__dict__[self.outcome] = 0. - else: - container.__dict__[self.outcome] = 1. - - container.__dict__[self.choiceValue] = totalValue + pass diff --git a/src/knapsack/SimpleKnapsackModel.py b/src/knapsack/SimpleKnapsackModel.py new file mode 100644 index 0000000..89946df --- /dev/null +++ b/src/knapsack/SimpleKnapsackModel.py @@ -0,0 +1,131 @@ +# Copyright 2020, Battelle Energy Alliance, LLC +# ALL RIGHTS RESERVED +""" +Created on February 2, 2021 + +@author: mandd +""" + +#External Modules--------------------------------------------------------------- + +#External Modules End----------------------------------------------------------- + +#Internal Modules--------------------------------------------------------------- +from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase +from utils import InputData, InputTypes +#Internal Modules End----------------------------------------------------------- + + +class SimpleKnapsackModel(ExternalModelPluginBase): + """ + This class is designed to create the BaseKnapsack model + """ + + @classmethod + def getInputSpecs(cls): + """ + Collects input specifications for this class. + @ In, None + @ Out, inputSpecs, InputData, input specifications + """ + inputSpecs = InputData.parameterInputFactory('ExternalModel') + inputSpecs.addParam('name', param_type=InputTypes.StringType, required=True) + inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) + + inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) + inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) + inputSpecs.addSub(InputData.parameterInputFactory('outcome', contentType=InputTypes.StringType)) + inputSpecs.addSub(InputData.parameterInputFactory('choiceValue', contentType=InputTypes.StringType)) + inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) + + map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) + map.addParam('value', param_type=InputTypes.StringType, required=True) + map.addParam('cost', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(map) + + return inputSpecs + + def __init__(self): + """ + Constructor + @ In, None + @ Out, None + """ + ExternalModelPluginBase.__init__(self) + + self.capacity = None # capacity value of the knapsack + self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied + self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint + self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements + + def _readMoreXML(self, container, xmlNode): + """ + Method to read the portion of the XML that belongs to the BaseKnapsack model + @ In, container, object, self-like object where all the variables can be stored + @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read + @ Out, None + """ + container.mapping = {} + + specs = self.getInputSpecs()() + specs.parseNode(xmlNode) + for node in specs.subparts: + name = node.getName() + val = node.value + if name == 'capacity': + self.capacity = val + elif name == 'penaltyFactor': + self.penaltyFactor = val + elif name == 'outcome': + self.outcome = val + elif name == 'choiceValue': + self.choiceValue = val + elif name == 'map': + container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] + elif name == 'variables': + variables = val + else: + raise IOError("BaseKnapsackModel: xml node " + name + " is not allowed") + + def initialize(self, container, runInfoDict, inputFiles): + """ + Method to initialize the BaseKnapsack model + @ In, container, object, self-like object where all the variables can be stored + @ In, runInfoDict, dict, dictionary containing all the RunInfo parameters (XML node ) + @ In, inputFiles, list, list of input files (if any) + @ Out, None + """ + pass + + + def run(self, container, inputDict): + """ + This method calculates the sum of the chosen element values and check if the capacity constraint + is satisfied + @ In, container, object, self-like object where all the variables can be stored + @ In, inputDict, dict, dictionary of inputs from RAVEN + """ + totalValue = 0.0 + capacity = inputDict[self.capacity][0] + + for key in container.mapping: + if key in inputDict.keys() and inputDict[key] in [0.0,1.0]: + if inputDict[key] == 1.0: + capacity = capacity - inputDict[container.mapping[key][1]][0] + if capacity >= 0: + totalValue = totalValue + inputDict[container.mapping[key][0]] + else: + totalValue = totalValue - inputDict[container.mapping[key][0]] * self.penaltyFactor + elif inputDict[key] == 0.0: + pass + else: + raise IOError("BaseKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") + else: + raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") + + if capacity>=0: + container.__dict__[self.outcome] = 0. + else: + container.__dict__[self.outcome] = 1. + + container.__dict__[self.choiceValue] = totalValue From 5e01fe318cd924f528b2edd6cbd30443332e7fe3 Mon Sep 17 00:00:00 2001 From: mandd Date: Tue, 16 Feb 2021 09:23:58 -0700 Subject: [PATCH 14/18] edits from base class --- src/knapsack/BaseKnapsackModel.py | 37 ++++++++------- src/knapsack/MultipleKnapsackModel.py | 10 +--- src/knapsack/SimpleKnapsackModel.py | 67 +++++++-------------------- 3 files changed, 40 insertions(+), 74 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index b57ea84..02e2c8f 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -7,7 +7,7 @@ """ #External Modules--------------------------------------------------------------- - +import abc #External Modules End----------------------------------------------------------- #Internal Modules--------------------------------------------------------------- @@ -20,6 +20,18 @@ class BaseKnapsackModel(ExternalModelPluginBase): """ This class is designed to create the base class for the knapsack models """ + def __init__(self): + """ + Constructor + @ In, None + @ Out, None + """ + ExternalModelPluginBase.__init__(self) + + self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied + self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint + self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements + @classmethod def getInputSpecs(cls): @@ -40,21 +52,15 @@ def getInputSpecs(cls): mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) mapping.addParam('value', param_type=InputTypes.StringType, required=True) mapping.addParam('cost', param_type=InputTypes.StringType, required=True) + + alias = InputData.parameterInputFactory('alias', contentType=InputTypes.StringType) + alias.addParam('variable', param_type=InputTypes.StringType, required=True) + alias.addParam('type', param_type=InputTypes.StringType, required=True) + inputSpecs.addSub(mapping) return inputSpecs - def __init__(self): - """ - Constructor - @ In, None - @ Out, None - """ - ExternalModelPluginBase.__init__(self) - - self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied - self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint - self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements def _readMoreXML(self, container, xmlNode): """ @@ -63,7 +69,7 @@ def _readMoreXML(self, container, xmlNode): @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read @ Out, None """ - container.mapping = {} + container.mapping = {} specs = self.getInputSpecs()() specs.parseNode(xmlNode) @@ -80,8 +86,7 @@ def _readMoreXML(self, container, xmlNode): container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] elif name == 'variables': variables = val - else: - raise IOError("BaseKnapsackModel: xml node " + name + " is not allowed") + def initialize(self, container, runInfoDict, inputFiles): """ @@ -93,7 +98,7 @@ def initialize(self, container, runInfoDict, inputFiles): """ pass - + @abc.abstractmethod def run(self, container, inputDict): """ This method calculates the sum of the chosen element values and check if the capacity constraint diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index 82c39f9..cb231a9 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -7,9 +7,7 @@ """ #External Modules--------------------------------------------------------------- -import numpy as np -import math -import copy + #External Modules End----------------------------------------------------------- #Internal Modules--------------------------------------------------------------- @@ -48,11 +46,7 @@ def getInputSpecs(cls): inputSpecs.addSub(mapping) inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) - map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) - map.addParam('value', param_type=InputTypes.StringType, required=True) - map.addParam('cost', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(map) - + return inputSpecs def __init__(self): diff --git a/src/knapsack/SimpleKnapsackModel.py b/src/knapsack/SimpleKnapsackModel.py index 89946df..4a99864 100644 --- a/src/knapsack/SimpleKnapsackModel.py +++ b/src/knapsack/SimpleKnapsackModel.py @@ -13,13 +13,24 @@ #Internal Modules--------------------------------------------------------------- from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase from utils import InputData, InputTypes +from BaseKnapsackModel import BaseKnapsackModel #Internal Modules End----------------------------------------------------------- -class SimpleKnapsackModel(ExternalModelPluginBase): +class SimpleKnapsackModel(BaseKnapsackModel): """ - This class is designed to create the BaseKnapsack model + This class is designed to create the simple Knapsack model """ + + def __init__(self): + """ + Constructor + @ In, None + @ Out, None + """ + BaseKnapsackModel.__init__(self) + self.capacity = None # capacity value of the knapsack + @classmethod def getInputSpecs(cls): @@ -28,35 +39,12 @@ def getInputSpecs(cls): @ In, None @ Out, inputSpecs, InputData, input specifications """ + BaseKnapsackModel.getInputSpecs(self) inputSpecs = InputData.parameterInputFactory('ExternalModel') - inputSpecs.addParam('name', param_type=InputTypes.StringType, required=True) - inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) - inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) - inputSpecs.addSub(InputData.parameterInputFactory('outcome', contentType=InputTypes.StringType)) - inputSpecs.addSub(InputData.parameterInputFactory('choiceValue', contentType=InputTypes.StringType)) - inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) - - map = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) - map.addParam('value', param_type=InputTypes.StringType, required=True) - map.addParam('cost', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(map) return inputSpecs - def __init__(self): - """ - Constructor - @ In, None - @ Out, None - """ - ExternalModelPluginBase.__init__(self) - - self.capacity = None # capacity value of the knapsack - self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied - self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint - self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements def _readMoreXML(self, container, xmlNode): """ @@ -65,7 +53,8 @@ def _readMoreXML(self, container, xmlNode): @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read @ Out, None """ - container.mapping = {} + BaseKnapsackModel._readMoreXML(self, container, xmlNode) + container.mapping = {} specs = self.getInputSpecs()() specs.parseNode(xmlNode) @@ -74,29 +63,7 @@ def _readMoreXML(self, container, xmlNode): val = node.value if name == 'capacity': self.capacity = val - elif name == 'penaltyFactor': - self.penaltyFactor = val - elif name == 'outcome': - self.outcome = val - elif name == 'choiceValue': - self.choiceValue = val - elif name == 'map': - container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] - elif name == 'variables': - variables = val - else: - raise IOError("BaseKnapsackModel: xml node " + name + " is not allowed") - - def initialize(self, container, runInfoDict, inputFiles): - """ - Method to initialize the BaseKnapsack model - @ In, container, object, self-like object where all the variables can be stored - @ In, runInfoDict, dict, dictionary containing all the RunInfo parameters (XML node ) - @ In, inputFiles, list, list of input files (if any) - @ Out, None - """ - pass - + def run(self, container, inputDict): """ From b072c6450345d92b749f78d67d22bbcf3da2c8e1 Mon Sep 17 00:00:00 2001 From: mandd Date: Tue, 16 Feb 2021 10:58:27 -0700 Subject: [PATCH 15/18] works on base class --- __init__.py | 1 + src/knapsack/BaseKnapsackModel.py | 2 +- src/knapsack/MultipleKnapsackModel.py | 72 ++++++--------------------- src/knapsack/SimpleKnapsackModel.py | 16 +++--- tests/test_BaseKnapsackModel.xml | 2 +- 5 files changed, 26 insertions(+), 67 deletions(-) diff --git a/__init__.py b/__init__.py index 695643a..1ff67b7 100644 --- a/__init__.py +++ b/__init__.py @@ -10,3 +10,4 @@ from LOGOS.src import IncrementalNPV from LOGOS.src.knapsack import MultipleKnapsackModel from LOGOS.src.knapsack import BaseKnapsackModel +from LOGOS.src.knapsack import SimpleKnapsackModel diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 02e2c8f..8a9e845 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -86,7 +86,7 @@ def _readMoreXML(self, container, xmlNode): container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] elif name == 'variables': variables = val - + def initialize(self, container, runInfoDict, inputFiles): """ diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index cb231a9..ec42eb6 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -13,14 +13,24 @@ #Internal Modules--------------------------------------------------------------- from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase from utils import InputData, InputTypes +from LOGOS.src.knapsack.BaseKnapsackModel import BaseKnapsackModel #Internal Modules End----------------------------------------------------------- -class MultipleKnapsackModel(ExternalModelPluginBase): +class MultipleKnapsackModel(BaseKnapsackModel): """ This class is designed to create the MultipleKnapsack model """ + def __init__(self): + """ + Constructor + @ In, None + @ Out, None + """ + BaseKnapsackModel.__init__(self) + self.knapsackSet = {} + @classmethod def getInputSpecs(cls): """ @@ -28,38 +38,13 @@ def getInputSpecs(cls): @ In, None @ Out, inputSpecs, InputData, input specifications """ - inputSpecs = InputData.parameterInputFactory('ExternalModel') - inputSpecs.addParam('name' , param_type=InputTypes.StringType, required=True) - inputSpecs.addParam('subType', param_type=InputTypes.StringType, required=True) - - inputSpecs.addSub(InputData.parameterInputFactory('penaltyFactor', contentType=InputTypes.FloatType)) - inputSpecs.addSub(InputData.parameterInputFactory('outcome' , contentType=InputTypes.StringType)) - inputSpecs.addSub(InputData.parameterInputFactory('choiceValue' , contentType=InputTypes.StringType)) - + inputSpecs= BaseKnapsackModel.getInputSpecs() + knapsack = InputData.parameterInputFactory('knapsack', contentType=InputTypes.StringType) knapsack.addParam('ID', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(knapsack) - - mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) - mapping.addParam('value', param_type=InputTypes.StringType, required=True) - mapping.addParam('cost', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(mapping) - - inputSpecs.addSub(InputData.parameterInputFactory('variables', contentType=InputTypes.StringListType)) - + inputSpecs.addSub(knapsack) return inputSpecs - def __init__(self): - """ - Constructor - @ In, None - @ Out, None - """ - ExternalModelPluginBase.__init__(self) - - self.penaltyFactor = 1.0 # penalty factor that is used when the capacity constraint is not satisfied - self.outcome = None # ID of the variable which indicates if the chosen elements satisfy the capacity constraint - self.choiceValue = None # ID of the variable which indicates the sum of the values of the chosen project elements def _readMoreXML(self, container, xmlNode): """ @@ -68,40 +53,15 @@ def _readMoreXML(self, container, xmlNode): @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read @ Out, None """ - container.mapping = {} - self.knapsackSet = {} - + BaseKnapsackModel._readMoreXML(self, container, xmlNode) specs = self.getInputSpecs()() specs.parseNode(xmlNode) for node in specs.subparts: name = node.getName() val = node.value - if name == 'penaltyFactor': - self.penaltyFactor = val - elif name == 'outcome': - self.outcome = val - elif name == 'choiceValue': - self.choiceValue = val - elif name == 'knapsack': + if name == 'knapsack': self.knapsackSet[node.parameterValues['ID']] = val - elif name == 'map': - container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] - elif name == 'variables': - variables = val - else: - raise IOError("MultipleKnapsackModel: xml node " + str(name) + " is not allowed") - - - def initialize(self, container, runInfoDict, inputFiles): - """ - Method to initialize the MultipleKnapsack model - @ In, container, object, self-like object where all the variables can be stored - @ In, runInfoDict, dict, dictionary containing all the RunInfo parameters (XML node ) - @ In, inputFiles, list, list of input files (if any) - @ Out, None - """ - pass def run(self, container, inputDict): diff --git a/src/knapsack/SimpleKnapsackModel.py b/src/knapsack/SimpleKnapsackModel.py index 4a99864..036455d 100644 --- a/src/knapsack/SimpleKnapsackModel.py +++ b/src/knapsack/SimpleKnapsackModel.py @@ -13,7 +13,7 @@ #Internal Modules--------------------------------------------------------------- from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase from utils import InputData, InputTypes -from BaseKnapsackModel import BaseKnapsackModel +from LOGOS.src.knapsack.BaseKnapsackModel import BaseKnapsackModel #Internal Modules End----------------------------------------------------------- @@ -29,7 +29,7 @@ def __init__(self): @ Out, None """ BaseKnapsackModel.__init__(self) - self.capacity = None # capacity value of the knapsack + self.capacity = None # capacity value of the knapsack @classmethod @@ -39,10 +39,8 @@ def getInputSpecs(cls): @ In, None @ Out, inputSpecs, InputData, input specifications """ - BaseKnapsackModel.getInputSpecs(self) - inputSpecs = InputData.parameterInputFactory('ExternalModel') + inputSpecs= BaseKnapsackModel.getInputSpecs() inputSpecs.addSub(InputData.parameterInputFactory('capacity', contentType=InputTypes.StringType)) - return inputSpecs @@ -54,15 +52,15 @@ def _readMoreXML(self, container, xmlNode): @ Out, None """ BaseKnapsackModel._readMoreXML(self, container, xmlNode) - container.mapping = {} - specs = self.getInputSpecs()() specs.parseNode(xmlNode) + for node in specs.subparts: name = node.getName() val = node.value if name == 'capacity': self.capacity = val + def run(self, container, inputDict): @@ -86,9 +84,9 @@ def run(self, container, inputDict): elif inputDict[key] == 0.0: pass else: - raise IOError("BaseKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") + raise IOError("SimpleKnapsackModel: variable " + str(key) + " does not have a 0/1 value.") else: - raise IOError("BaseKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") + raise IOError("SimpleKnapsackModel: variable " + str(key) + " is not found in the set of input variables.") if capacity>=0: container.__dict__[self.outcome] = 0. diff --git a/tests/test_BaseKnapsackModel.xml b/tests/test_BaseKnapsackModel.xml index 750a6ec..6a6f688 100644 --- a/tests/test_BaseKnapsackModel.xml +++ b/tests/test_BaseKnapsackModel.xml @@ -16,7 +16,7 @@ - + element1Status,element2Status,element3Status,element4Status,element5Status, element1Val ,element2Val ,element3Val ,element4Val ,element5Val, element1Cost ,element2Cost ,element3Cost ,element4Cost,element5Cost, From f6ab6a5a2cbf79b108d89319095916299ef5a771 Mon Sep 17 00:00:00 2001 From: mandd Date: Tue, 16 Feb 2021 11:11:52 -0700 Subject: [PATCH 16/18] edit tests file --- tests/tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests b/tests/tests index 8998a78..af66f22 100644 --- a/tests/tests +++ b/tests/tests @@ -43,7 +43,7 @@ UnorderedCsv = 'IncrementalNPV_options/dumpCostOutput.csv' [../] - [./BaseKnapsack] + [./SimpleKnapsack] type = 'RavenFramework' input = 'test_BaseKnapsackModel.xml' UnorderedCsv = 'BaseKnapsack/PrintPS.csv' From 9710ed2ddd090c961fb9099106a4c7de6429d02b Mon Sep 17 00:00:00 2001 From: mandd Date: Tue, 16 Feb 2021 11:33:00 -0700 Subject: [PATCH 17/18] delete whitespaces --- src/knapsack/BaseKnapsackModel.py | 6 +++--- src/knapsack/MultipleKnapsackModel.py | 4 ++-- src/knapsack/SimpleKnapsackModel.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/knapsack/BaseKnapsackModel.py b/src/knapsack/BaseKnapsackModel.py index 8a9e845..8af3150 100644 --- a/src/knapsack/BaseKnapsackModel.py +++ b/src/knapsack/BaseKnapsackModel.py @@ -52,11 +52,11 @@ def getInputSpecs(cls): mapping = InputData.parameterInputFactory('map', contentType=InputTypes.StringType) mapping.addParam('value', param_type=InputTypes.StringType, required=True) mapping.addParam('cost', param_type=InputTypes.StringType, required=True) - + alias = InputData.parameterInputFactory('alias', contentType=InputTypes.StringType) alias.addParam('variable', param_type=InputTypes.StringType, required=True) alias.addParam('type', param_type=InputTypes.StringType, required=True) - + inputSpecs.addSub(mapping) return inputSpecs @@ -86,7 +86,7 @@ def _readMoreXML(self, container, xmlNode): container.mapping[val] = [node.parameterValues['value'],node.parameterValues['cost']] elif name == 'variables': variables = val - + def initialize(self, container, runInfoDict, inputFiles): """ diff --git a/src/knapsack/MultipleKnapsackModel.py b/src/knapsack/MultipleKnapsackModel.py index ec42eb6..d131d03 100644 --- a/src/knapsack/MultipleKnapsackModel.py +++ b/src/knapsack/MultipleKnapsackModel.py @@ -39,10 +39,10 @@ def getInputSpecs(cls): @ Out, inputSpecs, InputData, input specifications """ inputSpecs= BaseKnapsackModel.getInputSpecs() - + knapsack = InputData.parameterInputFactory('knapsack', contentType=InputTypes.StringType) knapsack.addParam('ID', param_type=InputTypes.StringType, required=True) - inputSpecs.addSub(knapsack) + inputSpecs.addSub(knapsack) return inputSpecs diff --git a/src/knapsack/SimpleKnapsackModel.py b/src/knapsack/SimpleKnapsackModel.py index 036455d..30b99f7 100644 --- a/src/knapsack/SimpleKnapsackModel.py +++ b/src/knapsack/SimpleKnapsackModel.py @@ -21,7 +21,7 @@ class SimpleKnapsackModel(BaseKnapsackModel): """ This class is designed to create the simple Knapsack model """ - + def __init__(self): """ Constructor @@ -54,14 +54,14 @@ def _readMoreXML(self, container, xmlNode): BaseKnapsackModel._readMoreXML(self, container, xmlNode) specs = self.getInputSpecs()() specs.parseNode(xmlNode) - + for node in specs.subparts: name = node.getName() val = node.value if name == 'capacity': self.capacity = val - + def run(self, container, inputDict): """ From d4b0b12e466190705f06b43636f7c89ffa9ceb4c Mon Sep 17 00:00:00 2001 From: mandd Date: Tue, 16 Feb 2021 13:30:54 -0700 Subject: [PATCH 18/18] addressing comments --- __init__.py | 1 - doc/user_manual/include/Knapsack.tex | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/__init__.py b/__init__.py index 1ff67b7..6ec4e88 100644 --- a/__init__.py +++ b/__init__.py @@ -9,5 +9,4 @@ from LOGOS.src import BatteryReplacementCashFlowModel from LOGOS.src import IncrementalNPV from LOGOS.src.knapsack import MultipleKnapsackModel -from LOGOS.src.knapsack import BaseKnapsackModel from LOGOS.src.knapsack import SimpleKnapsackModel diff --git a/doc/user_manual/include/Knapsack.tex b/doc/user_manual/include/Knapsack.tex index 2994570..6aca3b6 100644 --- a/doc/user_manual/include/Knapsack.tex +++ b/doc/user_manual/include/Knapsack.tex @@ -9,8 +9,8 @@ \section{Knapsack Models} find the optimal solution. -\subsection{BaseKnapsack Model} -\label{subsec:BaseKnapsackModel} +\subsection{Simple Knapsack Model} +\label{subsec:SimpleKnapsackModel} This model considers the classical Knapsack Model characterized by a set of elements that can be chosen (or not). The goal is to maximize the sum of the chosen element values provided that the sum of @@ -31,9 +31,9 @@ \subsection{BaseKnapsack Model} is not satisfied, then the \xmlNode{choiceValue} variable is penalized by multiplying the project value by -\xmlNode{penaltyFactor}. -Example LOGOS input XML for BaseKnapsack Model: +Example LOGOS input XML for SimpleKnapsackModel Model: \begin{lstlisting}[style=XML] - + element1Status,element2Status,element3Status,element4Status,element5Status, element1Val ,element2Val ,element3Val ,element4Val ,element5Val, element1Cost ,element2Cost ,element3Cost ,element4Cost,element5Cost,