Skip to content

CadetCareerProblem – Main Data Corrections Methods

make_all_initial_real_instance_modifications(printing=None, vp_defaults_filename=None)

Perform All Initial Modifications for Real Data Instances.

This method runs the full preprocessing pipeline to prepare a real cadet–AFSC instance for modeling. It imports default value parameters, constructs rated preferences, updates qualification matrices, and fills in missing data. It also normalizes preferences and utilities and ensures that rated cadets meet eligibility criteria.

Parameters

printing : bool, optional If True, print progress updates for each major processing step. Defaults to the instance's self.printing.

vp_defaults_filename : str, optional Path to the default value parameter file. If not provided, uses the standard fallback.

Source code in afccp/main.py
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
def make_all_initial_real_instance_modifications(self, printing=None, vp_defaults_filename=None):
    """
    Perform All Initial Modifications for Real Data Instances.

    This method runs the full preprocessing pipeline to prepare a real cadet–AFSC instance for modeling.
    It imports default value parameters, constructs rated preferences, updates qualification matrices,
    and fills in missing data. It also normalizes preferences and utilities and ensures that rated
    cadets meet eligibility criteria.

    Parameters
    ----------
    printing : bool, optional
        If True, print progress updates for each major processing step. Defaults to the instance's `self.printing`.

    vp_defaults_filename : str, optional
        Path to the default value parameter file. If not provided, uses the standard fallback.
    """

    # Should we print updates?
    if printing is None:
        printing = self.printing

    # Import default value parameters
    self.import_default_value_parameters(printing=printing, vp_defaults_filename=vp_defaults_filename)

    # Takes the two Rated OM datasets and re-calculates the AFSC rankings for Rated AFSCs for both SOCs
    self.construct_rated_preferences_from_om_by_soc(printing=printing)

    # Update qualification matrix from AFSC preferences (treating CFM lists as "gospel" except for Rated/USSF)
    self.update_qualification_matrix_from_afsc_preferences(printing=printing)

    # Fill in remaining choices
    self.fill_remaining_afsc_choices(printing=printing)

    # Removes ineligible cadets from all 3 matrices: degree qualifications, cadet preferences, AFSC preferences
    self.remove_ineligible_choices(printing=printing)

    # Take the preferences dictionaries and update the matrices from them (using cadet/AFSC indices)
    self.update_preference_matrices(printing=printing)  # 1, 2, 4, 6, 7 -> 1, 2, 3, 4, 5 (preferences omit gaps)

    # Force first choice utility values to be 100%
    self.update_first_choice_cadet_utility_to_one(printing=printing)

    # Convert AFSC preferences to percentiles (0 to 1)
    self.convert_afsc_preferences_to_percentiles(printing=printing)  # 1, 2, 3, 4, 5 -> 1, 0.8, 0.6, 0.4, 0.2

    # The "cadet columns" are located in Cadets.csv and contain the utilities/preferences in order of preference
    self.update_cadet_columns_from_matrices(
        printing=printing)  # We haven't touched "c_preferences" and "c_utilities" until now

    # Update utility matrix from columns (and create final cadet utility matrix)
    self.update_cadet_utility_matrices_from_cadets_data(printing=printing)

    # Modify rated eligibility by SOC, removing cadets that are on "Rated Cadets" list...
    self.modify_rated_cadet_lists_based_on_eligibility(printing=printing)  # ...but not eligible for any rated AFSC

import_default_value_parameters(no_constraints=False, num_breakpoints=24, generate_afsc_weights=True, vp_weight=100, printing=None, vp_defaults_filename=None)

Import default value parameter settings from Excel and generate instance-specific value parameters.

This method loads predefined "factory defaults" for the value-focused model from Excel and transforms them into a usable set of value parameters for this problem instance. These parameters govern how objectives are weighted, what targets and constraints exist, and how utility functions are shaped.

Parameters

no_constraints : bool, optional If True, disables all value-based constraints by zeroing out the constraint_type matrix.

num_breakpoints : int, optional Number of piecewise breakpoints used when linearizing nonlinear value functions. Defaults to 24.

generate_afsc_weights : bool, optional Whether to generate AFSC weights using the configured weight function, or use defaults. Defaults to True.

vp_weight : float, optional Overall weight assigned to this value parameter configuration (used in ensemble models). Defaults to 100.

printing : bool, optional Whether to print status updates during import and evaluation. Uses the instance default if None. vp_defaults_filename : str, optional

Optional filename for the Excel workbook to load defaults from. If not specified, uses an intelligent default based on self.data_name.

Returns

dict A dictionary of value_parameters customized for this instance. Keys include:

  • objective_weight, objective_target, constraint_type
  • value_functions, afsc_weight, cadet_weight
  • a, f^hat (linearized value functions), and other modeling sets like K^A, J^A, etc.
Notes
  • The value parameter defaults are imported from one of the following:

    • "Value_Parameters_Defaults_<data_name>.xlsx"
    • "Value_Parameters_Defaults_Perfect.xlsx"
    • "Value_Parameters_Defaults_Generated.xlsx"
  • If self.mdl_p["set_to_instance"] is True, the generated parameters are assigned to self.value_parameters.

  • If a solution already exists, it will be re-evaluated using the new value parameters.
  • If self.mdl_p["add_to_dict"] is True, the parameters are stored in self.vp_dict.
Example
instance = CadetCareerProblem(data_name="Random")
instance.import_default_value_parameters()
See Also
Source code in afccp/main.py
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
def import_default_value_parameters(self, no_constraints=False, num_breakpoints=24,
                                    generate_afsc_weights=True, vp_weight=100, printing=None,
                                    vp_defaults_filename=None):
    """
    Import default value parameter settings from Excel and generate instance-specific value parameters.

    This method loads predefined "factory defaults" for the value-focused model from Excel and transforms them
    into a usable set of value parameters for this problem instance. These parameters govern how objectives are
    weighted, what targets and constraints exist, and how utility functions are shaped.

    Parameters
    ----------
    no_constraints : bool, optional
    If True, disables all value-based constraints by zeroing out the `constraint_type` matrix.

    num_breakpoints : int, optional
    Number of piecewise breakpoints used when linearizing nonlinear value functions. Defaults to 24.

    generate_afsc_weights : bool, optional
    Whether to generate AFSC weights using the configured weight function, or use defaults. Defaults to True.

    vp_weight : float, optional
    Overall weight assigned to this value parameter configuration (used in ensemble models). Defaults to 100.

    printing : bool, optional
    Whether to print status updates during import and evaluation. Uses the instance default if None.
    vp_defaults_filename : str, optional

    Optional filename for the Excel workbook to load defaults from. If not specified, uses an intelligent default
    based on `self.data_name`.

    Returns
    -------
    dict
    A dictionary of `value_parameters` customized for this instance. Keys include:

    - `objective_weight`, `objective_target`, `constraint_type`
    - `value_functions`, `afsc_weight`, `cadet_weight`
    - `a`, `f^hat` (linearized value functions), and other modeling sets like `K^A`, `J^A`, etc.

    Notes
    -----
    - The value parameter defaults are imported from one of the following:

        - `"Value_Parameters_Defaults_<data_name>.xlsx"`
        - `"Value_Parameters_Defaults_Perfect.xlsx"`
        - `"Value_Parameters_Defaults_Generated.xlsx"`

    - If `self.mdl_p["set_to_instance"]` is True, the generated parameters are assigned to `self.value_parameters`.
    - If a solution already exists, it will be re-evaluated using the new value parameters.
    - If `self.mdl_p["add_to_dict"]` is True, the parameters are stored in `self.vp_dict`.

    Example
    -------
    ```python
    instance = CadetCareerProblem(data_name="Random")
    instance.import_default_value_parameters()
    ```

    See Also
    --------
    - [`default_value_parameters_from_excel()`](../../../../afccp/reference/data/values/#data.values.default_value_parameters_from_excel)
    - [`generate_value_parameters_from_defaults()`](../../../../afccp/reference/data/values/#data.values.generate_value_parameters_from_defaults)
    - [`value_parameters_sets_additions()`](../../../../afccp/reference/data/values/#data.values.value_parameters_sets_additions)
    - [`evaluate_solution()`](../../../../afccp/reference/solutions/handling/#solutions.handlling.evaluate_solution)
    """

    if printing is None:
        printing = self.printing

    # Folder/Files information
    folder_path = afccp.globals.paths["support"] + "value parameters defaults/"
    vp_defaults_folder = os.listdir(folder_path)

    if vp_defaults_filename is None:
        vp_defaults_filename = "Value_Parameters_Defaults_" + self.data_name + ".xlsx"

    # Determine the path to the default value parameters we need to import
    if vp_defaults_filename in vp_defaults_folder:
        filename = vp_defaults_filename
    elif len(self.data_name) == 4:
        filename = "Value_Parameters_Defaults.xlsx"
    elif "Perfect" in self.data_name:
        filename = "Value_Parameters_Defaults_Perfect.xlsx"
    else:
        filename = "Value_Parameters_Defaults_Generated.xlsx"
    filepath = folder_path + filename

    # Module shorthand
    afccp_vp = afccp.data.values

    # Import "default value parameters" from excel
    dvp = afccp_vp.default_value_parameters_from_excel(filepath, num_breakpoints=num_breakpoints, printing=printing)

    # Generate this instance's value parameters from the defaults
    value_parameters = afccp_vp.generate_value_parameters_from_defaults(
        self.parameters, generate_afsc_weights=generate_afsc_weights, default_value_parameters=dvp)

    # Add some additional components to the value parameters
    if no_constraints:
        value_parameters['constraint_type'] = np.zeros([self.parameters['M'], value_parameters['O']])

    # "Condense" the value functions by removing unnecessary zeros
    value_parameters = afccp_vp.condense_value_functions(self.parameters, value_parameters)

    # Add indexed sets and subsets of AFSCs and AFSC objectives
    value_parameters = afccp_vp.value_parameters_sets_additions(self.parameters, value_parameters)

    # Weight of the value parameters as a whole
    value_parameters['vp_weight'] = vp_weight

    # Set value parameters to instance attribute
    if self.mdl_p["set_to_instance"]:
        self.value_parameters = value_parameters
        if self.solution is not None:
            self.solution = afccp.solutions.handling.evaluate_solution(
                self.solution, self.parameters, self.value_parameters, printing=printing)

    # Save new set of value parameters to dictionary
    if self.mdl_p["add_to_dict"]:
        self._save_new_value_parameters_to_dict(value_parameters)

    if self.printing:
        print('Imported.')

    return value_parameters

construct_rated_preferences_from_om_by_soc(printing=None)

Construct Combined Rated AFSC Preferences Using Ordered Merit (OM) Data.

This method processes and merges the OM matrices from each Source of Commissioning (SOC) (e.g., USAFA, ROTC) to construct a unified "1-N" preference list for all Rated AFSCs. It updates both the AFSC preference lists (afsc_preferences) and the AFSC preference matrix (a_pref_matrix) in the parameters dictionary.

Parameters:

printing (bool, optional): If True, prints a log statement indicating the preference integration process. Defaults to self.printing.

Returns:

None

Example:
instance.construct_rated_preferences_from_om_by_soc(printing=True)
See Also:
Source code in afccp/main.py
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
def construct_rated_preferences_from_om_by_soc(self, printing=None):
    """
    Construct Combined Rated AFSC Preferences Using Ordered Merit (OM) Data.

    This method processes and merges the OM matrices from each Source of Commissioning (SOC) (e.g., USAFA, ROTC)
    to construct a unified "1-N" preference list for all Rated AFSCs. It updates both the AFSC preference lists
    (`afsc_preferences`) and the AFSC preference matrix (`a_pref_matrix`) in the `parameters` dictionary.

    Parameters:
    --------
    printing (bool, optional): If True, prints a log statement indicating the preference integration process.
        Defaults to `self.printing`.

    Returns:
    --------
    None

    Example:
    --------
    ```python
    instance.construct_rated_preferences_from_om_by_soc(printing=True)
    ```

    See Also:
    --------
    - [`construct_rated_preferences_from_om_by_soc`](../../../../afccp/reference/data/preferences/#data.preferences.construct_rated_preferences_from_om_by_soc):
      Underlying function that consolidates SOC-specific OM matrices into ranked preferences.
    - [`parameter_sets_additions`](../../../../afccp/reference/data/adjustments/#data.adjustments.parameter_sets_additions):
      Updates indexed subsets after modifying AFSC preferences.
    """

    if printing is None:
        printing = self.printing

    if printing:
        print("Integrating rated preferences from OM matrices for each SOC...")

    # Generate Rated Preferences
    self.parameters = afccp.data.preferences.construct_rated_preferences_from_om_by_soc(self.parameters)
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

update_qualification_matrix_from_afsc_preferences(printing=None)

This method updates the qualification matrix to reflect cadet eligibility for AFSCs based on their preferences.

It performs the following steps:

  1. Checks if there is an AFSC preference matrix ('a_pref_matrix') in the parameters. If not, it raises a ValueError.
  2. Iterates through each AFSC ('afscs') in the parameters.
  3. Determines cadet eligibility and ineligibility for each AFSC based on both AFSC preferences and degree qualifications.
  4. If cadet eligibility differs between preference and qualification lists, it prints a message indicating the mismatch.
  5. For Rated or USSF AFSCs, it updates the qualification matrix, making more cadets ineligible based on CFM lists.
  6. For NRL AFSCs, it handles cadets eligible based on CFM lists but not the AFOCD by giving them exceptions.
  7. For NRL AFSCs, it also handles cadets eligible based on the AFOCD but not the CFM lists by marking them as a warning.
  8. Updates the qualification matrix with these changes and updates additional sets and subsets in the parameters.

This method helps ensure that the qualification matrix aligns with cadet preferences and the AFOCD.

Args:

self: The class instance containing the qualification matrix and parameters.

Returns:

None

Raises:

ValueError: If there is no AFSC preference matrix ('a_pref_matrix') in the parameters.

Parameters:

Name Type Description Default
printing

print status updates

None
Source code in afccp/main.py
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
def update_qualification_matrix_from_afsc_preferences(self, printing=None):
    """
    This method updates the qualification matrix to reflect cadet eligibility for AFSCs based on their preferences.

    It performs the following steps:

    1. Checks if there is an AFSC preference matrix ('a_pref_matrix') in the parameters. If not, it raises a ValueError.
    2. Iterates through each AFSC ('afscs') in the parameters.
    3. Determines cadet eligibility and ineligibility for each AFSC based on both AFSC preferences and degree qualifications.
    4. If cadet eligibility differs between preference and qualification lists, it prints a message indicating the mismatch.
    5. For Rated or USSF AFSCs, it updates the qualification matrix, making more cadets ineligible based on CFM lists.
    6. For NRL AFSCs, it handles cadets eligible based on CFM lists but not the AFOCD by giving them exceptions.
    7. For NRL AFSCs, it also handles cadets eligible based on the AFOCD but not the CFM lists by marking them as a warning.
    8. Updates the qualification matrix with these changes and updates additional sets and subsets in the parameters.

    This method helps ensure that the qualification matrix aligns with cadet preferences and the AFOCD.

    Args:
    --------
    self: The class instance containing the qualification matrix and parameters.

    Returns:
    --------
    None

    Raises:
    --------
    ValueError: If there is no AFSC preference matrix ('a_pref_matrix') in the parameters.
    :param printing: print status updates
    """

    if printing is None:
        printing = self.printing

    # Shorthand
    p = self.parameters

    if 'a_pref_matrix' not in p:
        raise ValueError("No AFSC preference matrix.")

    # Loop through each AFSC
    for j, afsc in enumerate(p['afscs'][:p['M']]):

        # Eligible & Ineligible cadets based on the CFM preference lists
        preference_eligible_cadets = np.where(p['a_pref_matrix'][:, j] > 0)[0]
        preference_ineligible_cadets = np.where(p['a_pref_matrix'][:, j] == 0)[0]

        # Eligible cadets based on their degree qualifications (and later using exceptions)
        qual_eligible_cadets = np.where(p['eligible'][:, j])[0]

        # There's a difference between the two
        if len(preference_eligible_cadets) != len(qual_eligible_cadets) and printing:
            print(j, "AFSC '" + afsc + "' has", len(preference_eligible_cadets),
                  "eligible cadets according to the AFSC preference matrix but",
                  len(qual_eligible_cadets), "according to the qual matrix.")

        # If this is a Rated or USSF AFSC, we have to make more cadets ineligible based on CFM lists
        if p['acc_grp'][j] in ['Rated', 'USSF']:

            # Only do this if we have ineligible cadets here
            if len(preference_ineligible_cadets) > 0:

                # If there's already an ineligible tier in this AFSC, we use it
                if "I = 0" in p['Deg Tiers'][j]:
                    val = "I" + str(p['t_count'][j])
                else:
                    val = "I" + str(p['t_count'][j] + 1)
                    if printing:
                        print(j, "AFSC '" + afsc + "' doesn't have an ineligible tier in the Deg Tiers section"
                                                " of the AFSCs.csv file. Please add one.")

                # Update qual matrix if needed
                if len(preference_ineligible_cadets) > 0 and printing:
                    print(j, "Making", len(preference_ineligible_cadets), "cadets ineligible for '" + afsc +
                          "' by altering their qualification to '" + val + "'. ")
                    self.parameters['qual'][preference_ineligible_cadets, j] = val

        # NRL AFSC
        else:

            # Cadets that are "eligible" for the AFSC based on the CFM lists but not the AFOCD
            exception_cadets = np.array([i for i in preference_eligible_cadets if i not in qual_eligible_cadets])

            # Only do this if we have exception cadets here
            if len(exception_cadets) > 0:

                # If there's an ineligible tier, we use this tier for the cadets with the exception
                if "I = 0" in p['Deg Tiers'][j]:
                    val = "E" + str(p['t_count'][j])
                else:
                    val = "E" + str(p['t_count'][j] + 1)

                # Update qual matrix
                if printing:
                    print(j, "Giving", len(exception_cadets), "cadets an exception for '" + afsc +
                          "' by altering their qualification to '" + val + "'. ")
                self.parameters['qual'][exception_cadets, j] = val

            # Cadets that are eligible for the AFSC based on the AFOCD but not the CFM lists
            mistake_cadets = np.array([i for i in qual_eligible_cadets if i not in preference_eligible_cadets])

            if len(mistake_cadets) > 0 and printing:
                print(j, 'WARNING. There are', len(mistake_cadets), 'cadets that are eligible for AFSC', afsc,
                      ' according to the AFOCD but not the CFM lists. These are the cadets at indices',
                      mistake_cadets)

    # Update qual stuff
    self.parameters["ineligible"] = (np.core.defchararray.find(self.parameters['qual'], "I") != -1) * 1
    self.parameters["eligible"] = (self.parameters["ineligible"] == 0) * 1
    self.parameters["exception"] = (np.core.defchararray.find(self.parameters['qual'], "E") != -1) * 1

    # Update the additional sets and subsets for the parameters
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

fill_remaining_afsc_choices(printing=None)

Fill Remaining Cadet Preferences to Complete the Preference Matrix.

This method ensures that each cadet has a complete and ordered set of AFSC preferences by arbitrarily filling in any missing AFSC choices. The method preserves explicitly defined bottom choices (second-to-last and last) and appends any remaining eligible AFSCs not yet ranked by each cadet.

Parameters:

printing (bool, optional): If True, prints a status update. If None, defaults to the instance’s self.printing.

Returns:

None: Updates self.parameters in-place with a complete preference matrix.

Example:
instance.fill_remaining_afsc_choices()
See Also:
Source code in afccp/main.py
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
def fill_remaining_afsc_choices(self, printing=None):
    """
    Fill Remaining Cadet Preferences to Complete the Preference Matrix.

    This method ensures that each cadet has a complete and ordered set of AFSC preferences by arbitrarily filling in
    any missing AFSC choices. The method preserves explicitly defined bottom choices (second-to-last and last) and
    appends any remaining eligible AFSCs not yet ranked by each cadet.

    Parameters:
    --------
    printing (bool, optional): If True, prints a status update. If None, defaults to the instance’s `self.printing`.

    Returns:
    --------
    None: Updates `self.parameters` in-place with a complete preference matrix.

    Example:
    --------
    ```python
    instance.fill_remaining_afsc_choices()
    ```

    See Also:
    --------
    - [`fill_remaining_preferences`](../../../../afccp/reference/data/preferences/#data.preferences.fill_remaining_preferences):
      Underlying function that assigns missing cadet AFSC preferences.
    - [`parameter_sets_additions`](../../../../afccp/reference/data/adjustments/#data.adjustments.parameter_sets_additions):
      Updates parameter subsets after modifying the preference matrix.
    """

    if printing is None:
        printing = self.printing

    if printing:
        print("Filling remaining cadet preferences arbitrarily with the exception of the bottom choices")

    # Update parameters
    self.parameters = afccp.data.preferences.fill_remaining_preferences(self.parameters)
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

remove_ineligible_choices(printing=None)

Remove Ineligible Cadet-AFSC Pairings Based on Qualification Criteria.

This method scans both the cadet and AFSC preference matrices (c_pref_matrix and a_pref_matrix) and removes pairings that violate the qualification constraints defined in the qual matrix. It ensures that cadets are only considered for AFSCs for which they are qualified, and updates all three matrices to sync them all on eligibility (c_pref_matrix, a_pref_matrix, qual).

Parameters:

printing (bool, optional): If True, prints progress and debug information. If None (default), it uses the instance-level self.printing attribute.

Returns:

None: The method modifies the parameters attribute in-place.

Examples:
instance.remove_ineligible_choices(printing=True)
See Also:
Source code in afccp/main.py
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
def remove_ineligible_choices(self, printing=None):
    """
    Remove Ineligible Cadet-AFSC Pairings Based on Qualification Criteria.

    This method scans both the cadet and AFSC preference matrices (`c_pref_matrix` and `a_pref_matrix`)
    and removes pairings that violate the qualification constraints defined in the `qual` matrix. It ensures
    that cadets are only considered for AFSCs for which they are qualified, and updates all three matrices to sync
    them all on eligibility (`c_pref_matrix`, `a_pref_matrix`, `qual`).

    Parameters:
    --------
    printing (bool, optional): If True, prints progress and debug information. If None (default),
    it uses the instance-level `self.printing` attribute.

    Returns:
    --------
    None: The method modifies the `parameters` attribute in-place.

    Examples:
    --------
    ```python
    instance.remove_ineligible_choices(printing=True)
    ```

    See Also:
    --------
    - [`remove_ineligible_cadet_choices`](../../../../afccp/reference/data/preferences/#data.preferences.remove_ineligible_cadet_choices):
      Underlying function that performs the actual validation and cleanup of preference matrices.
    - [`parameter_sets_additions`](../../../../afccp/reference/data/adjustments/#data.adjustments.parameter_sets_additions):
      Rebuilds indexed sets and eligibility structures after editing cadet-AFSC pairings.
    """

    if printing is None:
        printing = self.printing

    if printing:
        print("Removing ineligible cadets based on any of the three eligibility sources "
              "(c_pref_matrix, a_pref_matrix, qual)...")

    self.parameters = afccp.data.preferences.remove_ineligible_cadet_choices(self.parameters, printing=printing)
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

update_preference_matrices(printing=None)

Update preference matrices from cadet and AFSC preference arrays.

This method reconstructs the cadet and AFSC preference matrices (c_pref_matrix and a_pref_matrix) by transforming indexed preference arrays into complete, gapless matrices. Any gaps in the ranking (e.g., preferences like 1, 2, 4, 6, 7) are renumbered to ensure a continuous ranking (1, 2, 3, 4, 5), which is required for consistent model input.

Parameters

printing : bool, optional Whether to print status updates during execution. Defaults to self.printing.

Returns

None This method updates the internal parameters attribute of the instance in place.

Examples
instance = CadetCareerProblem(parameters)
instance.update_preference_matrices(printing=True)
See Also

afccp.data.preferences.update_preference_matrices Underlying function that reconstructs preference matrices from dictionary of lists

Source code in afccp/main.py
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
def update_preference_matrices(self, printing=None):
    """
    Update preference matrices from cadet and AFSC preference arrays.

    This method reconstructs the cadet and AFSC preference matrices (`c_pref_matrix` and `a_pref_matrix`)
    by transforming indexed preference arrays into complete, gapless matrices. Any gaps in the ranking (e.g.,
    preferences like 1, 2, 4, 6, 7) are renumbered to ensure a continuous ranking (1, 2, 3, 4, 5), which is
    required for consistent model input.

    Parameters
    ----------
    printing : bool, optional
    Whether to print status updates during execution. Defaults to `self.printing`.

    Returns
    -------
    None
    This method updates the internal `parameters` attribute of the instance in place.

    Examples
    --------
    ```python
    instance = CadetCareerProblem(parameters)
    instance.update_preference_matrices(printing=True)
    ```

    See Also
    --------
    [`afccp.data.preferences.update_preference_matrices`](../../../../afccp/reference/data/preferences/#data.preferences.update_preference_matrices)
        Underlying function that reconstructs preference matrices from dictionary of lists
    """
    if printing is None:
        printing = self.printing

    if printing:
        print("Updating cadet preference matrices from the preference dictionaries. "
              "ie. 1, 2, 4, 6, 7 -> 1, 2, 3, 4, 5 (preference lists need to omit gaps)")

    # Update parameters
    self.parameters = afccp.data.preferences.update_preference_matrices(self.parameters)

update_first_choice_cadet_utility_to_one(printing=None)

Fix Cadet First-Choice Utility to 100%.

This method updates the utility matrix so that each cadet's top-ranked AFSC is assigned a utility value of 1. This normalization ensures that the first choice always represents the maximum utility (100%) for that cadet.

Parameters

printing : bool, optional If True, prints the number and indices of cadets whose utilities were updated. Defaults to self.printing if not explicitly provided.

Returns

None Updates self.parameters['utility'] in-place.

Examples
instance.update_first_choice_cadet_utility_to_one()
See Also

update_first_choice_cadet_utility_to_one

Source code in afccp/main.py
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
def update_first_choice_cadet_utility_to_one(self, printing=None):
    """
    Fix Cadet First-Choice Utility to 100%.

    This method updates the `utility` matrix so that each cadet's top-ranked AFSC is assigned a utility value of 1.
    This normalization ensures that the first choice always represents the maximum utility (100%) for that cadet.

    Parameters
    ----------
    printing : bool, optional
    If True, prints the number and indices of cadets whose utilities were updated.
    Defaults to `self.printing` if not explicitly provided.

    Returns
    -------
    None
    Updates `self.parameters['utility']` in-place.

    Examples
    --------
    ```python
    instance.update_first_choice_cadet_utility_to_one()
    ```

    See Also
    --------
    [`update_first_choice_cadet_utility_to_one`](../../../../afccp/reference/data/preferences/#data.preferences.update_first_choice_cadet_utility_to_one)
    """

    if printing is None:
        printing = self.printing

    if printing:
        print('Updating cadet first choice utility value to 100%...')

    # Update "utility" matrix
    self.parameters['utility'] = afccp.data.preferences.update_first_choice_cadet_utility_to_one(
        self.parameters, printing=printing)

convert_afsc_preferences_to_percentiles(printing=None)

Convert AFSC Preference Lists to Normalized Percentiles.

This method takes the AFSC preference lists (a_pref_matrix) and converts them into normalized percentiles representing how strongly each AFSC prefers each cadet relative to others. Higher-ranked cadets receive values closer to 1.0, while lower-ranked cadets receive values closer to 0.0.

The result is stored in afsc_utility and can be used for further utility-based calculations or optimization models. Results are also saved under "AFSCs Utility.csv".

Parameters

printing : bool, optional If True, prints a message about the conversion process. If None, defaults to the object's self.printing attribute.

Returns

None This method updates self.parameters in place with a new afsc_utility matrix.

Examples
instance.convert_afsc_preferences_to_percentiles(printing=True)
See Also
Source code in afccp/main.py
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
def convert_afsc_preferences_to_percentiles(self, printing=None):
    """
    Convert AFSC Preference Lists to Normalized Percentiles.

    This method takes the AFSC preference lists (`a_pref_matrix`) and converts them into normalized
    percentiles representing how strongly each AFSC prefers each cadet relative to others.
    Higher-ranked cadets receive values closer to 1.0, while lower-ranked cadets receive values closer to 0.0.

    The result is stored in `afsc_utility` and can be used for further utility-based calculations or
    optimization models. Results are also saved under "AFSCs Utility.csv".

    Parameters
    ----------
    printing : bool, optional
    If True, prints a message about the conversion process.
    If None, defaults to the object's `self.printing` attribute.

    Returns
    -------
    None
    This method updates `self.parameters` in place with a new `afsc_utility` matrix.

    Examples
    --------
    ```python
    instance.convert_afsc_preferences_to_percentiles(printing=True)
    ```

    See Also
    --------
    - [`convert_afsc_preferences_to_percentiles()`](../../../../afccp/reference/data/preferences/#data.preferences.convert_afsc_preferences_to_percentiles)
    """
    if printing is None:
        printing = self.printing

    if printing:
        print("Converting AFSC preferences (a_pref_matrix) into percentiles (afsc_utility on AFSCs Utility.csv)...")
    self.parameters = afccp.data.preferences.convert_afsc_preferences_to_percentiles(self.parameters)
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

update_cadet_columns_from_matrices(printing=None)

Update Cadet Columns from Preference Matrix.

This method updates cadet-level columns (c_preferences, c_utilities) by extracting them from the cadet preference matrix (c_pref_matrix). Each cadet's ranked AFSCs are transformed into a compact preference list, and the associated utility values are retrieved.

Parameters

printing : bool, optional If True, prints a message about the conversion process. If None, defaults to the object's self.printing attribute.

Returns

None: This method updates self.parameters in place with:

  • c_preferences : dict of lists Ranked AFSCs for each cadet (non-zero entries from c_pref_matrix)
  • c_utilities : dict of lists Corresponding utility values for each cadet’s preference list
Examples
instance.update_cadet_columns_from_matrices(printing=True)
See Also
Source code in afccp/main.py
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
def update_cadet_columns_from_matrices(self, printing=None):
    """
    Update Cadet Columns from Preference Matrix.

    This method updates cadet-level columns (`c_preferences`, `c_utilities`) by extracting them
    from the cadet preference matrix (`c_pref_matrix`). Each cadet's ranked AFSCs are transformed
    into a compact preference list, and the associated utility values are retrieved.

    Parameters
    ----------
    printing : bool, optional
    If True, prints a message about the conversion process.
    If None, defaults to the object's `self.printing` attribute.

    Returns
    -------
    None: This method updates `self.parameters` in place with:

    - `c_preferences` : dict of lists
        Ranked AFSCs for each cadet (non-zero entries from `c_pref_matrix`)
    - `c_utilities` : dict of lists
        Corresponding utility values for each cadet’s preference list

    Examples
    --------
    ```python
    instance.update_cadet_columns_from_matrices(printing=True)
    ```

    See Also
    --------
    - [`update_cadet_columns_from_matrices`](../../../../afccp/reference/data/preferences/#data.preferences.update_cadet_columns_from_matrices)
    """
    if printing is None:
        printing = self.printing

    if printing:
        print('Updating cadet columns (Cadets.csv...c_utilities, c_preferences) from the preference matrix '
              '(c_pref_matrix)...')

    # Update parameters
    self.parameters['c_preferences'], self.parameters['c_utilities'] = \
        afccp.data.preferences.update_cadet_columns_from_matrices(self.parameters)

update_cadet_utility_matrices_from_cadets_data(printing=None)

Update Cadet Utility Matrices from Cadets Data.

This method updates the utility and cadet_utility matrices using the cadet-reported utility values stored in the "Util_1" through "Util_P" columns of Cadets.csv. It first populates the raw utility matrix (utility) and then normalizes these values to construct the final cadet_utility matrix based on either ordinal rankings or a value-based transformation if the last_afsc parameter is provided.

Parameters

printing : bool, optional Whether to print progress information. Defaults to the instance's self.printing setting.

Returns

None: Updates the following attributes in-place:

  • self.parameters['utility'] : ndarray, cadet-reported utilities with an unmatched column
  • self.parameters['cadet_utility'] : ndarray, normalized utility matrix
Examples
instance.update_cadet_utility_matrices_from_cadets_data()
See Also
Source code in afccp/main.py
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
def update_cadet_utility_matrices_from_cadets_data(self, printing=None):
    """
    Update Cadet Utility Matrices from Cadets Data.

    This method updates the `utility` and `cadet_utility` matrices using the cadet-reported utility values stored in the
    `"Util_1"` through `"Util_P"` columns of `Cadets.csv`. It first populates the raw utility matrix (`utility`) and then
    normalizes these values to construct the final `cadet_utility` matrix based on either ordinal rankings or a value-based
    transformation if the `last_afsc` parameter is provided.

    Parameters
    ----------
    printing : bool, optional
        Whether to print progress information. Defaults to the instance's `self.printing` setting.

    Returns
    -------
    None: Updates the following attributes in-place:

    - `self.parameters['utility']` : ndarray, cadet-reported utilities with an unmatched column
    - `self.parameters['cadet_utility']` : ndarray, normalized utility matrix

    Examples
    --------
    ```python
    instance.update_cadet_utility_matrices_from_cadets_data()
    ```

    See Also
    --------
    - [`update_cadet_utility_matrices`](../../../../afccp/reference/data/preferences/#data.preferences.update_cadet_utility_matrices)
    - [`create_final_cadet_utility_matrix_from_new_formula`](../../../../afccp/reference/data/preferences/#data.preferences.create_final_cadet_utility_matrix_from_new_formula)
    - [`create_final_cadet_utility_matrix`](../../../../afccp/reference/data/preferences/#data.preferences.create_final_cadet_utility_matrix)
    - [`parameter_sets_additions`](../../../../afccp/reference/data/adjustments/#data.adjustments.parameter_sets_additions)
    """
    if printing is None:
        printing = self.printing

    if printing:
        print("Updating cadet utility matrices ('utility' and 'cadet_utility') from the 'c_utilities' matrix")

    # Update parameters
    self.parameters = afccp.data.preferences.update_cadet_utility_matrices(self.parameters)
    self.parameters = afccp.data.adjustments.parameter_sets_additions(self.parameters)

modify_rated_cadet_lists_based_on_eligibility(printing=None)

Modify Rated Eligibility Lists and Matrices by SOC.

This method removes cadets from each Source of Commissioning (SOC)'s rated cadet list if they lack any rated AFSC preferences. It also updates the corresponding rated order-of-merit matrix (e.g., 'rr_om_matrix') by removing the appropriate cadet rows.

This ensures that rated eligibility lists and matrices only contain cadets who actually have at least one rated AFSC preference, which is essential for valid downstream rated matching logic.

Parameters

printing : bool, optional If True (default is self.printing), prints a summary of removed cadets and updated matrices.

See Also
Source code in afccp/main.py
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
def modify_rated_cadet_lists_based_on_eligibility(self, printing=None):
    """
    Modify Rated Eligibility Lists and Matrices by SOC.

    This method removes cadets from each Source of Commissioning (SOC)'s rated cadet list if they lack any rated AFSC
    preferences. It also updates the corresponding rated order-of-merit matrix (e.g., 'rr_om_matrix') by removing the
    appropriate cadet rows.

    This ensures that rated eligibility lists and matrices only contain cadets who actually have at least one rated AFSC
    preference, which is essential for valid downstream rated matching logic.

    Parameters
    ----------
    printing : bool, optional
        If True (default is `self.printing`), prints a summary of removed cadets and updated matrices.

    See Also
    --------
    - [`modify_rated_cadet_lists_based_on_eligibility`](../../../../afccp/reference/data/preferences/#data.preferences.modify_rated_cadet_lists_based_on_eligibility)
    """

    if printing is None:
        printing = self.printing

    if printing:
        print('Modifying rated eligibiity lists/matrices by SOC... \n'
              '(Removing cadets that are on the lists but not eligible for any rated AFSC)')

    # Update rated eligibility lists
    self.parameters = afccp.data.preferences.modify_rated_cadet_lists_based_on_eligibility(
        self.parameters, printing=printing)