SearchLibrium 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,434 @@
1
+ import numpy as np
2
+ class LatentClassConstrained:
3
+ """
4
+ A class to manage lists for an arbitrary number of latent classes,
5
+ including their subsets.
6
+ """
7
+ def __init__(self, num_classes):
8
+ """
9
+ Initializes the latent classes with empty lists.
10
+
11
+ Args:
12
+ num_classes (int): Number of latent classes.
13
+ """
14
+ self.classes = {}
15
+
16
+ for i in range(1, num_classes + 1):
17
+ class_name = f"latent_class_{i}"
18
+ self.classes[class_name] = {
19
+ "asvar": [],
20
+ "isvars": [],
21
+ "randvars": [],
22
+ "memvars": [],
23
+ "sub_asvar": [],
24
+ "sub_isvars": [],
25
+ "sub_randvars": [],
26
+ "sub_memvars": []
27
+ }
28
+
29
+ def populate_class(self, class_name, asvar=None, isvars=None, randvars=None, memvars=None,
30
+ req_asvar=None, req_isvars=None, req_randvars=None, req_memvars=None):
31
+ """
32
+ Populates the lists for a specific latent class.
33
+
34
+ Args:
35
+ class_name (str): The name of the latent class to populate.
36
+ asvar (list): Values for the `asvar` list.
37
+ isvars (list): Values for the `isvars` list.
38
+ randvars (list): Values for the `randvars` list.
39
+ memvars (list): Values for the `memvars` list.
40
+ sub_asvar (list): Values for the `sub_asvar` list.
41
+ sub_isvars (list): Values for the `sub_isvars` list.
42
+ sub_randvars (list): Values for the `sub_randvars` list.
43
+ sub_memvars (list): Values for the `sub_memvars` list.
44
+ """
45
+ if class_name not in self.classes:
46
+ raise ValueError(f"Latent class {class_name} does not exist.")
47
+
48
+ # Update the lists; default to empty lists if not provided.
49
+ self.classes[class_name]["asvar"] = asvar or []
50
+ self.classes[class_name]["isvars"] = isvars or []
51
+ self.classes[class_name]["randvars"] = randvars or []
52
+ self.classes[class_name]["memvars"] = memvars or []
53
+ self.classes[class_name]["req_asvar"] = req_asvar or []
54
+ self.classes[class_name]["req_isvars"] = req_isvars or []
55
+ self.classes[class_name]["req_randvars"] = req_randvars or []
56
+ self.classes[class_name]["req_memvars"] = req_memvars or []
57
+
58
+ def get_class(self, class_name):
59
+ """
60
+ Retrieves the data for a specific latent class.
61
+
62
+ Args:
63
+ class_name (str): The name of the latent class to retrieve.
64
+
65
+ Returns:
66
+ dict: The data for the specified latent class.
67
+ """
68
+ if class_name not in self.classes:
69
+ raise ValueError(f"Latent class {class_name} does not exist.")
70
+ return self.classes[class_name]
71
+
72
+ def get_all_classes(self):
73
+ """
74
+ Retrieves all latent classes and their data.
75
+
76
+ Returns:
77
+ dict: A dictionary containing all latent classes and their data.
78
+ """
79
+ return self.classes
80
+
81
+ def get_global_asvars_randvars(self):
82
+ """
83
+ Aggregates the `asvar` and `randvars` across all latent classes.
84
+
85
+ Returns:
86
+ dict: A dictionary with global `asvars` and `randvars`.
87
+ """
88
+ global_asvars = []
89
+ global_randvars = []
90
+ global_isvars = []
91
+ global_memvars = []
92
+ for class_data in self.classes.values():
93
+ global_asvars.extend(class_data["asvar"])
94
+ global_randvars.extend(class_data["randvars"])
95
+ global_isvars.extend(class_data["isvars"])
96
+ global_memvars.extend(class_data["memvars"])
97
+
98
+
99
+ # Remove duplicates by converting to a set and back to a list
100
+ return {
101
+ "asvars": list(set(global_asvars)),
102
+ "randvars": list(set(global_randvars)),
103
+ "isvars": list(set(global_isvars)),
104
+ "memvars":list(set(global_memvars))
105
+
106
+ }
107
+
108
+
109
+ class LatentClassCoefficients:
110
+ """
111
+ A class to store and manage coefficients for variables in latent classes.
112
+ Each latent class will have coefficients based on the provided variables.
113
+ """
114
+
115
+ def __init__(self, num_alternatives, num_classes, asvars, isvars, memvars):
116
+ """
117
+ Initialize the coefficients for a specific latent class.
118
+
119
+ Args:
120
+ num_alternatives (int): The number of alternatives (used for `isvars` coefficients).
121
+ latent_class (dict): A dictionary representing a single latent class, containing
122
+ lists of `asvar`, `isvars`, `randvars`, and `memvars`.
123
+ """
124
+ self.obj = None
125
+ self.num_alternatives = num_alternatives
126
+ self.num_classes = num_classes
127
+ self.asvars = asvars
128
+ self.isvars = isvars
129
+ self.memvars = memvars
130
+ self.randvars = []
131
+ #self.coefficients = # Dictionary to store coefficients for variables
132
+ self.class_names = [f"class {str(i)}" for i in range(2, num_classes +1)] #start at 2
133
+ # Initialize coefficients for each type of variable
134
+ self.coefficients = self.initialize_coefficients()
135
+
136
+ def define_structure(self, list_as_vars, list_is_vars, list_memvars):
137
+ """
138
+ Define the structure of coefficients for each latent class based on current variables.
139
+
140
+ Args:
141
+ list_as_vars (list of lists): Current `asvar` variables for each class.
142
+ list_is_vars (list of lists): Current `isvars` variables for each class.
143
+ list_memvars (list of lists): Current `memvars` variables, for all classes except the last one.
144
+
145
+ Returns:
146
+ dict: A dictionary mapping each latent class to its variable coefficients.
147
+ """
148
+ if len(list_as_vars) != self.num_classes:
149
+ raise ValueError("Mismatch between the number of classes and the size of list_as_vars.")
150
+ if len(list_is_vars) != self.num_classes:
151
+ raise ValueError("Mismatch between the number of classes and the size of list_is_vars.")
152
+ if len(list_memvars) != self.num_classes - 1:
153
+ raise ValueError("Mismatch between the number of classes and the size of list_memvars.")
154
+
155
+ structure = {}
156
+
157
+ for i in range(self.num_classes):
158
+ # Initialize the structure for the current class
159
+ structure[i] = {
160
+ "asvar": {},
161
+ "isvars": {},
162
+ "memvars": {}
163
+ }
164
+
165
+ # Process `asvar` variables
166
+ for var in list_as_vars[i]:
167
+ if var in self.coefficients[i]:
168
+ structure[i]["asvar"][var] = self.coefficients[i][var]
169
+ else:
170
+ raise ValueError(f"Variable '{var}' not found in coefficients for latent class {i}.")
171
+
172
+ # Process `isvars` variables
173
+ for var in list_is_vars[i]:
174
+ if var in self.coefficients[i]:
175
+ structure[i]["isvars"][var] = self.coefficients[i][var]
176
+ else:
177
+ raise ValueError(f"Variable '{var}' not found in coefficients for latent class {i}.")
178
+
179
+ # Process `memvars` variables (only for classes 0 to num_classes - 2)
180
+ if i < self.num_classes - 1:
181
+ for var in list_memvars[i]:
182
+ if var in self.coefficients[i]:
183
+ structure[i]["memvars"][var] = self.coefficients[i][var]
184
+ else:
185
+ raise ValueError(f"Variable '{var}' not found in coefficients for latent class {i}.")
186
+
187
+ return structure
188
+
189
+ def arrange_coefficients(self, sol):
190
+ memvars = sol.get('memvars')
191
+ asvars = sol.get('asvars')
192
+ isvars = sol.get('isvars')
193
+
194
+ def initialize_coefficients(self):
195
+ """
196
+ Initialize the coefficients for all latent classes.
197
+
198
+ Returns:
199
+ dict: A dictionary where each latent class has its own dictionary of coefficients.
200
+ """
201
+ coefficients = {}
202
+
203
+ for i in range(self.num_classes):
204
+ coefficients[i] = {
205
+ 'isvars':{},
206
+ 'asvars':{},
207
+ 'memvars':{}
208
+ }
209
+
210
+ # Initialize `isvars` coefficients (array of zeros for each variable in `isvars`)
211
+ for var in self.isvars:
212
+ coefficients[i]['isvars'][var] = np.zeros(self.num_alternatives)
213
+
214
+ # Initialize `asvars` coefficients (single zero for each variable in `asvar`)
215
+ for var in self.asvars:
216
+ coefficients[i]['asvars'][var] = 0.0
217
+
218
+ # Initialize `randvars` coefficients (single zero for each variable in `randvars`)
219
+
220
+ for var in self.randvars:
221
+ pass #placeholder
222
+ #coefficients[i][var] = 0.0
223
+
224
+ # Initialize `memvars` coefficients (single zero for each variable in `memvars`)
225
+ if i >0: #ignore base line class
226
+ for var in self.class_names:
227
+ coefficients[i]['memvars'][var] = 0.0
228
+ for var in self.memvars:
229
+ coefficients[i]['memvars'][var] = 1.0
230
+
231
+ return coefficients
232
+ def update_coefficients(self, coeff, coeff_latent, isvars_list, asvars_list, memvars_list, obj):
233
+ """
234
+ Get the coefficients for a list of `isvars`, `asvars`, and `memvars` for each latent class.
235
+
236
+ Args:
237
+ coeff a list of the coefficients
238
+ isvars_list (list of lists): A list of lists of `isvars` for each latent class.
239
+ asvars_list (list of lists): A list of lists of `asvars` for each latent class.
240
+ memvars_list (list of lists): A list of lists of `memvars` for each latent class.
241
+
242
+ Returns:
243
+ dict: A dictionary containing the coefficients for each input variable type and latent class.
244
+ """
245
+ if self.obj is None or obj < self.obj:
246
+ print('Test: update')
247
+ self.obj = obj
248
+ else:
249
+ print('Test: no update')
250
+ return
251
+ result = {}
252
+ coeff_counter =0
253
+ coeff_counter_l = 0
254
+ for i in range(self.num_classes):
255
+ result[i] = {
256
+ 'isvars': {},
257
+ 'asvars': {},
258
+ 'memvars': {}
259
+ }
260
+
261
+ # Get `isvars` coefficients for the current latent class
262
+ for var in isvars_list[i]:
263
+ if var in self.coefficients[i]['isvars']:
264
+ self.coefficients[i]['isvars'][var] = coeff[coeff_counter:coeff_counter+self.num_alternatives]
265
+ coeff_counter +=self.num_alternatives-1
266
+
267
+ # Get `asvars` coefficients for the current latent class
268
+ for var in asvars_list[i]:
269
+ if var in self.coefficients[i]['asvars']:
270
+ self.coefficients[i]['asvars'][var] =coeff[coeff_counter]
271
+ coeff_counter += 1
272
+
273
+ # Get `memvars` coefficients for the current latent class
274
+ if i > 0:
275
+ for var in memvars_list[i-1]:
276
+ if var in self.coefficients[i]['memvars']:
277
+ self.coefficients[i]['memvars'][var] = coeff_latent[coeff_counter_l]
278
+ coeff_counter_l +=1
279
+ print("TODO CHECK ME HERE")
280
+ def get_thetas(self, memvars_list, theta_check = None):
281
+ result = {}
282
+ thetas = []
283
+ for i in range(self.num_classes):
284
+ result[i] = {
285
+
286
+ 'memvars': {}
287
+ }
288
+
289
+
290
+ # Get `memvars` coefficients for the current latent class
291
+ if i > 0:
292
+ for var in memvars_list[i-1]:
293
+ if var in self.coefficients[i]['memvars']:
294
+ #result[i]['memvars'][var] = self.coefficients[i]['memvars'][var]
295
+ thetas.append(self.coefficients[i]['memvars'][var])
296
+ ## sanity check
297
+ if theta_check is not None:
298
+ if len(theta_check) != len(thetas):
299
+ raise Warning('this should not be possibble')
300
+ thetas = np.array(thetas)
301
+ return thetas
302
+
303
+ def get_betas(self, isvars_list, asvars_list, theta_check = None):
304
+ result = {}
305
+ betas = []
306
+ for i in range(self.num_classes):
307
+ class_betas = []
308
+ result[i] = {
309
+ 'isvars':{},
310
+ 'asvars':{}
311
+
312
+ }
313
+
314
+ # Get `isvars` coefficients for the current latent class
315
+ for var in isvars_list[i]:
316
+ if var in self.coefficients[i]['isvars']:
317
+ #result[i]['isvars'][var] = self.coefficients[i]['isvars'][var]
318
+ class_betas.append(self.coefficients[i]['isvars'][var])
319
+ # Get `asvars` coefficients for the current latent class
320
+ for var in asvars_list[i]:
321
+ if var in self.coefficients[i]['asvars']:
322
+ #result[i]['asvars'][var] = self.coefficients[i]['asvars'][var]
323
+ class_betas.append(self.coefficients[i]['asvars'][var])
324
+ ## sanity check
325
+ class_betas = np.concatenate(
326
+ [x if isinstance(x, np.ndarray) else np.array([x]) for x in class_betas])
327
+
328
+ betas.append(np.array(class_betas))
329
+ if theta_check is not None:
330
+ if len(theta_check) != len(betas):
331
+ raise Warning('this should not be possibble')
332
+ #thetas = np.array(thetas)
333
+ return betas
334
+
335
+
336
+ def get_coefficients(self, coefficients, isvars_list, asvars_list, memvars_list):
337
+ """
338
+ Get the coefficients for a list of `isvars`, `asvars`, and `memvars` for each latent class.
339
+
340
+ Args:
341
+ coefficients (dict): A dictionary of coefficients for all latent classes.
342
+ isvars_list (list of lists): A list of lists of `isvars` for each latent class.
343
+ asvars_list (list of lists): A list of lists of `asvars` for each latent class.
344
+ memvars_list (list of lists): A list of lists of `memvars` for each latent class.
345
+
346
+ Returns:
347
+ dict: A dictionary containing the coefficients for each input variable type and latent class.
348
+ """
349
+ result = {}
350
+
351
+ for i in range(self.num_classes):
352
+ result[i] = {
353
+ 'isvars': {},
354
+ 'asvars': {},
355
+ 'memvars': {}
356
+ }
357
+
358
+ # Get `isvars` coefficients for the current latent class
359
+ for var in isvars_list[i]:
360
+ if var in coefficients[i]['isvars']:
361
+ result[i]['isvars'][var] = coefficients[i]['isvars'][var]
362
+
363
+ # Get `asvars` coefficients for the current latent class
364
+ for var in asvars_list[i]:
365
+ if var in coefficients[i]['asvars']:
366
+ result[i]['asvars'][var] = coefficients[i]['asvars'][var]
367
+
368
+ # Get `memvars` coefficients for the current latent class
369
+ if i >0:
370
+ for var in memvars_list[i-1]:
371
+
372
+ if var in coefficients[i-1]['memvars']:
373
+ result[i]['memvars'][var] = coefficients[i-1]['memvars'][var]
374
+
375
+ return result
376
+
377
+ def set_coefficients(self, variable, value, alternative_index=None):
378
+ """
379
+ Set the coefficient for a specific variable.
380
+
381
+ Args:
382
+ variable (str): The name of the variable.
383
+ value (float): The value of the coefficient.
384
+ alternative_index (int, optional): The index of the alternative (only for `isvars`).
385
+ """
386
+ if variable not in self.coefficients:
387
+ raise ValueError(f"Variable '{variable}' does not exist in the coefficients.")
388
+
389
+ if isinstance(self.coefficients[variable], list):
390
+ # Handle `isvars` coefficients (multiple alternatives)
391
+ if alternative_index is None:
392
+ raise ValueError(f"Alternative index must be provided for variable '{variable}'.")
393
+ self.coefficients[variable][alternative_index] = value
394
+ else:
395
+ # Handle `asvar`, `randvars`, and `memvars` coefficients
396
+ self.coefficients[variable] = value
397
+
398
+ def get_coefficient(self, variable, alternative_index=None):
399
+ """
400
+ Get the coefficient for a specific variable.
401
+
402
+ Args:
403
+ variable (str): The name of the variable.
404
+ alternative_index (int, optional): The index of the alternative (only for `isvars`).
405
+
406
+ Returns:
407
+ float: The coefficient value.
408
+ """
409
+ if variable not in self.coefficients:
410
+ raise ValueError(f"Variable '{variable}' does not exist in the coefficients.")
411
+
412
+ if isinstance(self.coefficients[variable], list):
413
+ # Handle `isvars` coefficients (multiple alternatives)
414
+ if alternative_index is None:
415
+ raise ValueError(f"Alternative index must be provided for variable '{variable}'.")
416
+ return self.coefficients[variable][alternative_index]
417
+ else:
418
+ # Handle `asvar`, `randvars`, and `memvars` coefficients
419
+ return self.coefficients[variable]
420
+
421
+ def get_all_coefficients(self):
422
+ """
423
+ Get all coefficients for the latent class.
424
+
425
+ Returns:
426
+ dict: A dictionary of all coefficients.
427
+ """
428
+ return self.coefficients
429
+ ''' Class that is based on the fitted models form latent class constrained
430
+ an as vars will have one coeffient for eeach variable in the list
431
+ and is vars will have how many alternatives therefore ,_init needs to have number alternrate
432
+ memvars will have one for each memevars
433
+ this is all for one individaul latent class, so the total number of coefficients will be these
434
+ plus the onese from all other classes, can you help write me code to store the coefficients for every variabel'''