View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.experiment.results;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import p3j.misc.Misc;
25  import p3j.misc.math.Matrix2D;
26  
27  /**
28   * Simple helper class to define the result aggregation.
29   * 
30   * Use only for a *single* export!
31   * 
32   * @author Christina Bohk
33   * @author Roland Ewald
34   */
35  public class ResultAggregation {
36  
37  	/** The number of generations. */
38  	private final int generations;
39  
40  	/** The number of years. */
41  	private final int numOfYears;
42  
43  	/**
44  	 * Map to easily access selectors for different subpopulations. Map format:
45  	 * SUB-POPULATION (immigrants || emigrants) => ( [END_X_M || END_X_F] =>
46  	 * List[Generation_0, ..., Generation_n] )
47  	 */
48  	private final Map<ISubPopulationSelector, Map<IOutputVariableSelector, List<AbstractAggregationSelector>>> subPopSelectorMap;
49  
50  	// Several default selectors, for further usage:
51  
52  	/** End population of male natives. */
53  	private final AbstractAggregationSelector nativesEndXm;
54  
55  	/** End population of female natives. */
56  	private final AbstractAggregationSelector nativesEndXf;
57  
58  	/**
59  	 * All male sub-populations to be added for total population (natives +
60  	 * immigrants).
61  	 */
62  	private final List<AbstractAggregationSelector> allMaleAdditions;
63  
64  	/**
65  	 * All male sub-populations to be added for total population (natives +
66  	 * immigrants).
67  	 */
68  	private final List<AbstractAggregationSelector> allFemaleAdditions;
69  
70  	/**
71  	 * All male sub-populations to be subtracted for total population (emigrants).
72  	 */
73  	private final List<AbstractAggregationSelector> allMaleSubtractions;
74  
75  	/**
76  	 * All female sub-populations to be subtracted for total population
77  	 * (emigrants).
78  	 */
79  	private final List<AbstractAggregationSelector> allFemaleSubtractions;
80  
81  	/** All sub-populations to be added for total population. */
82  	private final List<AbstractAggregationSelector> allTotalAdditions;
83  
84  	/** All sub-populations to be subtracted for total population. */
85  	private final List<AbstractAggregationSelector> allTotalSubtractions;
86  
87  	/**
88  	 * Instantiates a new result aggregation helper.
89  	 * 
90  	 * @param numberOfGenerations
91  	 *          the number of generations
92  	 * @param numberOfYears
93  	 *          the number of years
94  	 */
95  	public ResultAggregation(int numberOfGenerations, int numberOfYears) {
96  
97  		// Define general structure
98  		generations = numberOfGenerations;
99  		numOfYears = numberOfYears;
100 		subPopSelectorMap = initSubPopSelectorMap();
101 
102 		// Define often-used selectors
103 		nativesEndXm = new SumOverAgesSelector(END_X_M, NATIVES, -1);
104 		nativesEndXf = new SumOverAgesSelector(END_X_F, NATIVES, -1);
105 
106 		// Extracting those selector lists from the above that are required to
107 		// define further selectors on top
108 		allMaleAdditions = new ArrayList<AbstractAggregationSelector>(
109 		    subPopSelectorMap.get(IMMIGRANTS).get(END_X_M));
110 		allMaleAdditions.add(0, nativesEndXm);
111 		allFemaleAdditions = new ArrayList<AbstractAggregationSelector>(
112 		    subPopSelectorMap.get(IMMIGRANTS).get(END_X_F));
113 		allFemaleAdditions.add(0, nativesEndXf);
114 		allMaleSubtractions = new ArrayList<AbstractAggregationSelector>(
115 		    subPopSelectorMap.get(EMIGRANTS).get(END_X_M));
116 		allFemaleSubtractions = new ArrayList<AbstractAggregationSelector>(
117 		    subPopSelectorMap.get(EMIGRANTS).get(END_X_F));
118 
119 		// Note: total population = natives + immigrants - emigrants
120 		allTotalAdditions = getAllForSubPop(IMMIGRANTS);
121 		allTotalAdditions.add(0, nativesEndXm);
122 		allTotalAdditions.add(0, nativesEndXf);
123 		allTotalSubtractions = getAllForSubPop(EMIGRANTS);
124 	}
125 
126 	/**
127 	 * Initializes the sub-population selector map.
128 	 * 
129 	 * Map format:
130 	 * 
131 	 * [immigrants || emigrants] => ( [END_X_M || END_X_F] => List[Generation_0,
132 	 * ..., Generation_n] )
133 	 * 
134 	 * @return map of sub-population selectors
135 	 */
136 	private Map<ISubPopulationSelector, Map<IOutputVariableSelector, List<AbstractAggregationSelector>>> initSubPopSelectorMap() {
137 		Map<ISubPopulationSelector, Map<IOutputVariableSelector, List<AbstractAggregationSelector>>> resultMap = new HashMap<ISubPopulationSelector, Map<IOutputVariableSelector, List<AbstractAggregationSelector>>>();
138 		for (ISubPopulationSelector trialSelector : GEN_POPULATIONS) {
139 			Map<IOutputVariableSelector, List<AbstractAggregationSelector>> outputMap = new HashMap<IOutputVariableSelector, List<AbstractAggregationSelector>>();
140 			outputMap.put(END_X_M, new ArrayList<AbstractAggregationSelector>());
141 			outputMap.put(END_X_F, new ArrayList<AbstractAggregationSelector>());
142 			resultMap.put(trialSelector, outputMap);
143 			for (int i = 0; i < generations; i++) {
144 				SumOverAgesSelector subPopEndXm = new SumOverAgesSelector(END_X_M,
145 				    trialSelector, i);
146 				SumOverAgesSelector subPopEndXf = new SumOverAgesSelector(END_X_F,
147 				    trialSelector, i);
148 				resultMap.get(trialSelector).get(END_X_M).add(subPopEndXm);
149 				resultMap.get(trialSelector).get(END_X_F).add(subPopEndXf);
150 			}
151 		}
152 		return Collections.unmodifiableMap(resultMap);
153 	}
154 
155 	/** The selector for male year-end population. */
156 	private static final IOutputVariableSelector END_X_M = new IOutputVariableSelector() {
157 		@Override
158 		public String getSuffix() {
159 			return "end_x_m";
160 		}
161 
162 		@Override
163 		public Matrix2D select(BasicResults basicResults) {
164 			return basicResults.getEndXm();
165 		}
166 	};
167 
168 	/** The selector for female year-end population. */
169 	private static final IOutputVariableSelector END_X_F = new IOutputVariableSelector() {
170 		@Override
171 		public String getSuffix() {
172 			return "end_x_f";
173 		}
174 
175 		@Override
176 		public Matrix2D select(BasicResults basicResults) {
177 			return basicResults.getEndXf();
178 		}
179 	};
180 
181 	/** The selector for male mean population. */
182 	private static final IOutputVariableSelector MEAN_X_M = new IOutputVariableSelector() {
183 		@Override
184 		public String getSuffix() {
185 			return "mean_x_m";
186 		}
187 
188 		@Override
189 		public Matrix2D select(BasicResults basicResults) {
190 			return basicResults.getMeanXm();
191 		}
192 	};
193 
194 	/** The selector for female mean population. */
195 	private static final IOutputVariableSelector MEAN_X_F = new IOutputVariableSelector() {
196 		@Override
197 		public String getSuffix() {
198 			return "mean_x_f";
199 		}
200 
201 		@Override
202 		public Matrix2D select(BasicResults basicResults) {
203 			return basicResults.getMeanXf();
204 		}
205 	};
206 
207 	/** The selector for natives. */
208 	private static final ISubPopulationSelector NATIVES = new ISubPopulationSelector() {
209 		@Override
210 		public String getPrefix() {
211 			return "natives";
212 		}
213 
214 		@Override
215 		public BasicResults select(ResultsOfTrial results, int generation) {
216 			return results.getNativesResults();
217 		}
218 	};
219 
220 	/** The selector for immigrants. */
221 	private static final ISubPopulationSelector IMMIGRANTS = new ISubPopulationSelector() {
222 		@Override
223 		public String getPrefix() {
224 			return "immigrants";
225 		}
226 
227 		@Override
228 		public BasicResults select(ResultsOfTrial results, int generation) {
229 			return results.getImmigrantResults().get(generation);
230 		}
231 	};
232 
233 	/** The selector for emigrants. */
234 	private static final ISubPopulationSelector EMIGRANTS = new ISubPopulationSelector() {
235 		@Override
236 		public String getPrefix() {
237 			return "emigrants";
238 		}
239 
240 		@Override
241 		public BasicResults select(ResultsOfTrial results, int generation) {
242 			return results.getEmigrantResults().get(generation);
243 		}
244 	};
245 
246 	/** The array of result-type selectors. */
247 	private static final IOutputVariableSelector[] RESULT_TYPES = { END_X_M,
248 	    END_X_F, MEAN_X_M, MEAN_X_F };
249 
250 	/** The array of sub-population selectors (without natives). */
251 	private static final ISubPopulationSelector[] GEN_POPULATIONS = { IMMIGRANTS,
252 	    EMIGRANTS };
253 
254 	/**
255 	 * Gets the selectors to be used for report generation.
256 	 * 
257 	 * @param generations
258 	 *          the number of generations
259 	 * @param numOfYears
260 	 *          the number of years to be predicted
261 	 * 
262 	 * @return the selectors
263 	 */
264 	public IAggregationSelector[] getSelectorsForReport() {
265 
266 		List<IAggregationSelector> selectors = defineSubPopMergingSelectors();
267 
268 		// Add selectors for natives
269 		for (IOutputVariableSelector resultType : new IOutputVariableSelector[] {
270 		    END_X_M, END_X_F }) {
271 			selectors.add(new ChooseAgesForSingleYearSelector(resultType, NATIVES,
272 			    -1, 0));
273 			selectors.add(new ChooseAgesForSingleYearSelector(resultType, NATIVES,
274 			    -1, numOfYears - 1));
275 		}
276 		for (IOutputVariableSelector resultType : RESULT_TYPES) {
277 			selectors.add(new SumOverAgesSelector(resultType, NATIVES, -1));
278 		}
279 
280 		// Add selectors for all sub-populations and their descendants
281 		for (ISubPopulationSelector trialSelector : GEN_POPULATIONS) {
282 			for (int i = 0; i < generations; i++) {
283 				for (IOutputVariableSelector resultType : new IOutputVariableSelector[] {
284 				    END_X_M, END_X_F }) {
285 					selectors.add(new ChooseAgesForSingleYearSelector(resultType,
286 					    trialSelector, i, 0));
287 					selectors.add(new ChooseAgesForSingleYearSelector(resultType,
288 					    trialSelector, i, numOfYears - 1));
289 				}
290 				for (IOutputVariableSelector resultType : RESULT_TYPES) {
291 					selectors.add(new SumOverAgesSelector(resultType, trialSelector, i));
292 				}
293 			}
294 		}
295 
296 		return selectors.toArray(new IAggregationSelector[0]);
297 	}
298 
299 	/**
300 	 * Gets the selectors for aggregated data export.
301 	 * 
302 	 * @return the selectors for aggregated data export
303 	 */
304 	public IAggregationSelector[] getSelectorsForAggregatedDataExport() {
305 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
306 
307 		selectors.add(new MergeSubPopOldAgeDependencyRatioSelector(
308 		    allTotalAdditions, allTotalSubtractions, "oadr_total_end_mf"));
309 
310 		for (int i = 0; i < numOfYears; i++) {
311 			selectors.add(new YearlyAgeTrialMatrixSelector(allMaleAdditions,
312 			    allMaleSubtractions, "age_trial_matrix_m_for_year_", i));
313 			selectors.add(new YearlyAgeTrialMatrixSelector(allFemaleAdditions,
314 			    allFemaleSubtractions, "age_trial_matrix_f_for_year_", i));
315 		}
316 
317 		return selectors.toArray(new IAggregationSelector[0]);
318 	}
319 
320 	/**
321 	 * Generate selectors that merge certain sub-populations (e.g. all immigrants,
322 	 * all females, all descendant immigrants, both males and females, etc.).
323 	 * 
324 	 * @return the list of defined selectors
325 	 */
326 	private List<IAggregationSelector> defineSubPopMergingSelectors() {
327 
328 		// Total population for natives (m+f)
329 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
330 		selectors.add(new MergeSubPopSumOverAgesSelector(
331 		    new AbstractAggregationSelector[] { nativesEndXm, nativesEndXf },
332 		    "natives_end_x_mf"));
333 
334 		selectors.addAll(defineMFSelectorsForAllMigrantGenerations());
335 
336 		// Specifying the total male/female/male+female population
337 		selectors.addAll(defineTotalMaleFemaleCombinedSelectors());
338 
339 		// Specifying emigrant/immigrant total population
340 		selectors.addAll(defineMigrantSelectors(subPopSelectorMap));
341 
342 		return selectors;
343 	}
344 
345 	/**
346 	 * Specify selectors for total migrant populations.
347 	 * 
348 	 * @param aggrSelectors
349 	 *          the aggregation selectors
350 	 * @param subPopSelectorMap
351 	 *          the sub-population selector map
352 	 */
353 	@SuppressWarnings("unchecked")
354 	private List<IAggregationSelector> defineMigrantSelectors(
355 	    Map<ISubPopulationSelector, Map<IOutputVariableSelector, List<AbstractAggregationSelector>>> subPopSelectorMap) {
356 
357 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
358 
359 		// Add merging selectors for immigrants
360 		selectors.addAll(defineSingleYearSelectors(
361 		    new MergeSubPopSumOverAgesSelector(subPopSelectorMap.get(IMMIGRANTS)
362 		        .get(END_X_M), "immigrants_end_x_m"), numOfYears));
363 		selectors.addAll(defineSingleYearSelectors(
364 		    new MergeSubPopSumOverAgesSelector(subPopSelectorMap.get(IMMIGRANTS)
365 		        .get(END_X_F), "immigrants_end_x_f"), numOfYears));
366 		selectors.add(new MergeSubPopSumOverAgesSelector(
367 		    getAllForSubPop(IMMIGRANTS), "immigrants_end_x_mf"));
368 
369 		// Add merging selectors for emigrants
370 		selectors.addAll(defineSingleYearSelectors(
371 		    new MergeSubPopSumOverAgesSelector(subPopSelectorMap.get(EMIGRANTS)
372 		        .get(END_X_M), null, "emigrants_end_x_m"), numOfYears));
373 		selectors.addAll(defineSingleYearSelectors(
374 		    new MergeSubPopSumOverAgesSelector(subPopSelectorMap.get(EMIGRANTS)
375 		        .get(END_X_F), null, "emigrants_end_x_f"), numOfYears));
376 		selectors.add(new MergeSubPopSumOverAgesSelector(
377 		    getAllForSubPop(EMIGRANTS), null, "emigrants_end_x_mf"));
378 
379 		// Define selectors for descendant immigrant/emigrants
380 		List<AbstractAggregationSelector> allMaleDescImmigrants = new ArrayList<AbstractAggregationSelector>(
381 		    subPopSelectorMap.get(IMMIGRANTS).get(END_X_M));
382 		allMaleDescImmigrants.remove(0);
383 		List<AbstractAggregationSelector> allFemaleDescImmigrants = new ArrayList<AbstractAggregationSelector>(
384 		    subPopSelectorMap.get(IMMIGRANTS).get(END_X_F));
385 		allFemaleDescImmigrants.remove(0);
386 		List<AbstractAggregationSelector> allMaleDescEmigrants = new ArrayList<AbstractAggregationSelector>(
387 		    subPopSelectorMap.get(EMIGRANTS).get(END_X_M));
388 		allMaleDescEmigrants.remove(0);
389 		List<AbstractAggregationSelector> allFemaleDescEmigrants = new ArrayList<AbstractAggregationSelector>(
390 		    subPopSelectorMap.get(EMIGRANTS).get(END_X_F));
391 		allFemaleDescEmigrants.remove(0);
392 
393 		// Add merging selectors for descendant immigrants
394 		selectors.addAll(defineSingleYearSelectors(
395 		    new MergeSubPopSumOverAgesSelector(allMaleDescImmigrants, null,
396 		        "immigrants_desc_end_x_m"), numOfYears));
397 		selectors.addAll(defineSingleYearSelectors(
398 		    new MergeSubPopSumOverAgesSelector(allFemaleDescImmigrants, null,
399 		        "immigrants_desc_end_x_f"), numOfYears));
400 		selectors.add(new MergeSubPopSumOverAgesSelector(Misc
401 		    .<AbstractAggregationSelector> mergeList(allMaleDescImmigrants,
402 		        allFemaleDescImmigrants), null, "immigrants_desc_end_x_mf"));
403 
404 		// Add merging selectors for descendant emigrants
405 		selectors.addAll(defineSingleYearSelectors(
406 		    new MergeSubPopSumOverAgesSelector(allMaleDescEmigrants, null,
407 		        "emigrants_desc_end_x_m"), numOfYears));
408 		selectors.addAll(defineSingleYearSelectors(
409 		    new MergeSubPopSumOverAgesSelector(allFemaleDescEmigrants, null,
410 		        "emigrants_desc_end_x_f"), numOfYears));
411 		selectors.add(new MergeSubPopSumOverAgesSelector(Misc
412 		    .<AbstractAggregationSelector> mergeList(allMaleDescEmigrants,
413 		        allFemaleDescEmigrants), null, "emigrants_desc_end_x_mf"));
414 
415 		return selectors;
416 	}
417 
418 	/**
419 	 * Defines selectors that focus on total male/female population.
420 	 * 
421 	 * @return list of total male/female population selectors
422 	 */
423 	private List<IAggregationSelector> defineTotalMaleFemaleCombinedSelectors() { // FIXME
424 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
425 		selectors.addAll(defineSingleYearSelectors(
426 		    new MergeSubPopSumOverAgesSelector(allMaleAdditions,
427 		        allMaleSubtractions, "total_end_x_m"), numOfYears));
428 		selectors.addAll(defineSingleYearSelectors(
429 		    new MergeSubPopSumOverAgesSelector(allFemaleAdditions,
430 		        allFemaleSubtractions, "total_end_x_f"), numOfYears));
431 		selectors.addAll(defineSingleYearSelectors(
432 		    new MergeSubPopSumOverAgesSelector(allTotalAdditions,
433 		        allTotalSubtractions, "total_end_x_mf"), numOfYears));
434 		return selectors;
435 	}
436 
437 	/**
438 	 * Defines male+female selectors for all single migrant generations.
439 	 * 
440 	 * @return list of all end_x_mf selectors, for all generations and migrant
441 	 *         populations
442 	 */
443 	private List<IAggregationSelector> defineMFSelectorsForAllMigrantGenerations() {
444 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
445 		for (ISubPopulationSelector trialSelector : GEN_POPULATIONS) {
446 			for (int i = 0; i < generations; i++) {
447 				selectors.add(new MergeSubPopSumOverAgesSelector(
448 				    new AbstractAggregationSelector[] {
449 				        subPopSelectorMap.get(trialSelector).get(END_X_M).get(i),
450 				        subPopSelectorMap.get(trialSelector).get(END_X_F).get(i) },
451 				    new AbstractAggregationSelector[0], trialSelector.getPrefix()
452 				        + "_gen_" + i + "_end_x_mf"));
453 			}
454 		}
455 		return selectors;
456 	}
457 
458 	/**
459 	 * Adds the given selector and defines two selectors for first/last year for
460 	 * it.
461 	 * 
462 	 * @param mergeSubPopSumOverAgesSelector
463 	 *          the merge sub pop sum over ages selector
464 	 * @param numOfYears
465 	 *          the number of years
466 	 */
467 	private static List<IAggregationSelector> defineSingleYearSelectors(
468 	    MergeSubPopSumOverAgesSelector mergeSubPopSumOverAgesSelector,
469 	    int numOfYears) {
470 		List<IAggregationSelector> selectors = new ArrayList<IAggregationSelector>();
471 		selectors.add(mergeSubPopSumOverAgesSelector);
472 
473 		// Define selector for first year
474 		selectors.add(new MergeSubPopChooseAgesSingleYearSelector(
475 		    mergeSubPopSumOverAgesSelector, 0));
476 
477 		// Define selector for last year
478 		selectors.add(new MergeSubPopChooseAgesSingleYearSelector(
479 		    mergeSubPopSumOverAgesSelector, numOfYears - 1));
480 
481 		return selectors;
482 	}
483 
484 	/**
485 	 * Gets the all for sub pop.
486 	 * 
487 	 * @param subPopSelector
488 	 *          the sub-population selector
489 	 * 
490 	 * @return all selectors for the specified sub-population
491 	 */
492 	private List<AbstractAggregationSelector> getAllForSubPop(
493 	    ISubPopulationSelector subPopSelector) {
494 		List<AbstractAggregationSelector> result = new ArrayList<AbstractAggregationSelector>();
495 		for (List<AbstractAggregationSelector> selectorList : subPopSelectorMap
496 		    .get(subPopSelector).values()) {
497 			result.addAll(selectorList);
498 		}
499 		return result;
500 	}
501 
502 }