## ams_version=1.0

Model Main_TwoLevel {
    Comment: {
        "Keywords:
        Evironmental Economics, Stackelberg Games, Nonlinear Programming, NLP."
    }
    Section Two_Level_Decision_Problem {
        Section Quantities_and_Units {
            DeclarationSection Quantity_Declarations {
                Quantity Monetary {
                    BaseUnit: $;
                }
                Quantity SI_Mass {
                    BaseUnit: kg;
                    Comment: "Expresses the value for the amount of matter.";
                }
                Quantity SI_Volume {
                    BaseUnit: m3;
                }
            }
        }
        Section Two_Level_Model {
            DeclarationSection Model_Declarations {
                Set Companies {
                    Index: j;
                    Parameter: Co;
                }
                Parameter MonitoringCosts {
                    Range: [200, 2000];
                    Unit: 1000 * $;
                }
                Parameter WasteTargetLevel {
                    Range: [WasteTargetLowerBound, TotalWasteWithoutRemoval];
                    Unit: 1000 * kg;
                }
                Parameter TaxLowerBound {
                    Range: nonnegative;
                    Unit: $/kg;
                }
                Parameter TaxUpperBound {
                    Unit: $/kg;
                }
                Parameter TaxRate {
                    Range: [TaxRateLowerBound, TaxRateUpperBound];
                    Unit: $/kg;
                }
                Parameter SubsidyRate {
                    Range: nonnegative;
                    Unit: $/kg;
                }
                Parameter TaxRateLowerBound {
                    Range: nonnegative;
                    Unit: $/kg;
                    Definition: MonitoringCosts / WasteTargetLevel;
                }
                Parameter TaxRateUpperBound {
                    Range: nonnegative;
                    Unit: $/kg;
                    Definition: 1000*TaxRateLowerBound;
                }
                Parameter AmountWasteWater {
                    IndexDomain: (j);
                    Unit: 1000 * m3;
                }
                Parameter WasteConcentration {
                    IndexDomain: j;
                    Unit: kg/m3;
                }
                Parameter EfficiencyCoefficient {
                    IndexDomain: (j);
                    Unit: $*kg/m3^2;
                }
                Parameter TotalWasteWithoutRemoval {
                    Unit: 1000 * kg;
                    Definition: Sum(j,AmountWasteWater(j)*WasteConcentration(j));
                }
                Parameter WasteTargetLowerBound {
                    Range: nonnegative;
                    Unit: 1000 * kg;
                    Definition: TotalWasteWithoutRemoval/5;
                }
                Parameter WasteRemovalRateUpperBound {
                    IndexDomain: j;
                    Unit: kg/m3;
                    Definition: WasteConcentration(j)*0.95;
                }
                Parameter WasteRemoved {
                    IndexDomain: (j);
                    Unit: 1000 * kg;
                    Definition: AmountWasteWater(j) * WasteRemovalRate(j);
                }
                Parameter TaxMinusSubsidy {
                    IndexDomain: (j);
                    Unit: 1000 * $;
                    Definition: AmountWasteWater(j) * ( TaxRate * ( WasteConcentration(j) - WasteRemovalRate(j) ) - SubsidyRate * WasteRemovalRate(j) );
                }
                Parameter TotalCost {
                    IndexDomain: (j);
                    Unit: 1000 * $;
                    Definition: {
                        AmountWasteWater(j) * [ ( EfficiencyCoefficient(j) / ( WasteConcentration(j) - WasteRemovalRate(j) )
                                - EfficiencyCoefficient(j) / WasteConcentration(j) ) + TaxRate * ( WasteConcentration(j) - WasteRemovalRate(j) )
                                - SubsidyRate * WasteRemovalRate(j) ]
                    }
                }
                Parameter TotalWasteAfterRemoval {
                    Unit: 1000 * kg;
                    Definition: TotalWasteWithoutRemoval - TotalWasteRemoved;
                }
                Parameter TotalWasteRemoved {
                    Unit: 1000 * kg;
                    Definition: sum (j,WasteRemoved(j));
                }
                Parameter TotalTaxIncome {
                    Unit: 1000 * $;
                    Definition: TaxRate * TotalWasteAfterRemoval;
                }
                Parameter TotalSubsidyExpense {
                    Unit: 1000 * $;
                    Definition: SubsidyRate * TotalWasteRemoved;
                }
                Parameter CleaningCost {
                    IndexDomain: (j);
                    Unit: 1000 * $;
                    Definition: {
                        AmountWasteWater(j) *
                        (EfficiencyCoefficient(j) / (WasteConcentration(j) - WasteRemovalRate(j)) - EfficiencyCoefficient(j) / WasteConcentration(j))
                    }
                }
                Variable WasteRemovalRate {
                    IndexDomain: (j);
                    Range: [0, WasteRemovalRateUpperBound(j)];
                    Unit: kg/m3;
                }
                Variable CompanyCosts {
                    Unit: 1000 * $;
                    Definition: {
                        AmountWasteWater(Co) * [ ( EfficiencyCoefficient(Co) / ( WasteConcentration(Co) - WasteRemovalRate(Co) )
                                - EfficiencyCoefficient(Co) / WasteConcentration(Co) ) + TaxRate * ( WasteConcentration(Co) - WasteRemovalRate(Co) )
                                - SubsidyRate * WasteRemovalRate(Co) ]
                    }
                }
                MathematicalProgram TwoLevel {
                    Objective: CompanyCosts;
                    Direction: minimize;
                    Constraints: AllConstraints;
                    Variables: AllVariables;
                    Type: NLP;
                }
            }
            Procedure ReadModelData {
                Body: {
                    read from file "Initial Data Files\\datacase.txt";
                }
            }
        }
        Section Solving_Procedures {
            DeclarationSection Solving_Declarations {
                Parameter Tollerance {
                    Unit: 1000 * kg;
                }
            }
            Procedure SolveSubmodelsForFixedTax {
                Arguments: (FixedTaxRate);
                Body: {
                    if (FixedTaxRate=0[$/kg] ) then
                    
                       DialogMessage( FormatString("Tax rate should be a value between %5.2n and %5.2n", TaxRateLowerBound, TaxRateUpperBound ) );
                    
                    else
                    
                       TaxRate := FixedTaxRate;
                       SubsidyRate := (TaxRate * WasteTargetLevel - MonitoringCosts) / (TotalWasteWithoutRemoval - WasteTargetLevel);
                    
                       Tax_and_Subsidy('Tax') := TaxRate;
                       Tax_and_Subsidy('Subsidy') := SubsidyRate;
                    
                       /*Initialize WasteRemovalRate to guide the algorithm to search away from WasteRemovalRateUpperBound(j)*/
                       WasteRemovalRate(j) := WasteRemovalRateUpperBound(j) / 2;
                    
                       FOR j DO
                            Co := j;
                            Solve TwoLevel in merge mode;
                       ENDFOR;
                    
                    endif;
                }
                Parameter FixedTaxRate {
                    Unit: $/kg;
                    Property: Input;
                }
            }
            Procedure SolveSubmodelsForGivenTax {
                Body: {
                    SolveSubmodelsForFixedTax(TaxRate);
                }
            }
            Procedure HuntPhase {
                Body: {
                    TaxLowerBound := MonitoringCosts / WasteTargetLevel;
                    
                    REPEAT
                            TaxRate := 2 * TaxLowerBound;
                    
                            SolveSubmodelsForFixedTax(TaxRate);
                    
                            BREAK WHEN (TotalWasteAfterRemoval < WasteTargetLevel);
                    
                            TaxLowerBound := TaxRate;
                    
                    ENDREPEAT;
                    
                    TaxUpperBound := TaxRate;
                }
            }
            Procedure Bisection {
                Body: {
                    REPEAT
                            TaxRate := (TaxLowerBound + TaxUpperBound) / 2;
                    
                            SolveSubmodelsForFixedTax(TaxRate);
                    
                            Tax_and_Subsidy('Tax') := TaxRate;
                            Tax_and_Subsidy('Subsidy') := SubsidyRate;
                    
                            BREAK WHEN Abs(TotalWasteAfterRemoval - WasteTargetLevel) < Tollerance;
                    
                            IF (TotalWasteAfterRemoval < WasteTargetLevel)
                                THEN TaxUpperBound := TaxRate;
                            ENDIF;
                    
                            IF (TotalWasteAfterRemoval > WasteTargetLevel)
                                THEN TaxLowerBound:=TaxRate;
                            ENDIF;
                    
                    ENDREPEAT;
                }
            }
            Procedure SolveTwoLevelModel {
                Body: {
                    empty TaxRate, SubsidyRate;
                    
                    HuntPhase;
                    Bisection;
                }
            }
        }
    }
    Section User_Interface {
        StringParameter ExplanationsFiles_submodels {
            Definition: "Explanations Files\\submodels.txt";
        }
        Set TaxesSubsidies {
            Index: i;
            Parameter: TorS;
        }
        Parameter Tax_and_Subsidy {
            IndexDomain: (i);
            Range: nonnegative;
            Unit: $/kg;
        }
        ElementParameter TaxSubsidyColor {
            IndexDomain: (i);
            Range: AllColors;
        }
        ElementParameter TotalCostsColor {
            IndexDomain: (j);
            Range: AllColors;
        }
        Set SensitivityGraphs {
            Index: g;
        }
        ElementParameter GraphToShow {
            Range: SensitivityGraphs;
        }
        StringParameter GraphName {
            IndexDomain: (g);
        }
        Parameter HideIndicator {
            IndexDomain: (g);
            Range: binary;
            Definition: if ( g = GraphToShow ) then 0 else 1 endif;
        }
        Parameter GraphsXUpperBound {
            Range: nonnegative;
            Unit: 1000 * kg;
            Definition: TotalWasteWithoutRemoval - 0.1 [1000 * kg];
        }
        ElementParameter ACase {
            Range: AllCases;
        }
        Procedure InitializeInterfaceParameters {
            Body: {
                read from file "Initial Data Files\\interface.txt";
            }
        }
        Procedure UpdateAllData {
            Body: {
                update;
            }
        }
        Procedure UpdateSensivityAnalysisGraphs;
    }
    Procedure MainInitialization {
        Body: {
            ReadModelData;
            InitializeInterfaceParameters;
            TaxRate := 0.2;
            update;
        }
    }
    Procedure MainExecution {
        Body: {
            SolveTwoLevelModel;
        }
    }
    Procedure MainTermination {
        Body: {
            return 1;
        }
    }
}