it.cnr.istc.pst.platinum.ai.framework.parameter.csp.solver.choco.v4.ChocoSolver   F
last analyzed

Complexity

Total Complexity 68

Size/Duplication

Total Lines 597
Duplicated Lines 17.09 %

Importance

Changes 0
Metric Value
eloc 267
dl 102
loc 597
rs 2.96
c 0
b 0
f 0
wmc 68

15 Methods

Rating   Name   Duplication   Size   Complexity  
A doCreateNotEqualCSPConstraint(NotEqualParameterConstraint) 0 16 3
A doCreateCSPVariable(Parameter) 0 37 4
A ChocoSolver() 0 5 1
A build() 0 29 4
A init() 0 4 1
A doCreateEqualCSPConstraint(EqualParameterConstraint) 0 16 3
B update(ParameterNotification) 0 69 8
B doCreateCSPConstraint(ParameterConstraint) 0 48 6
A toString() 0 3 1
A computeSolution() 0 12 3
A isConsistent() 0 36 5
B doCreateBindCSPConstraint(BindParameterConstraint) 51 51 5
B doCreateExcludeCSPConstraint(ExcludeParameterConstraint) 51 51 5
C computeValues(Parameter) 0 77 9
C doFindParameterRelatedConstraints(Parameter) 0 44 10

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like it.cnr.istc.pst.platinum.ai.framework.parameter.csp.solver.choco.v4.ChocoSolver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package it.cnr.istc.pst.platinum.ai.framework.parameter.csp.solver.choco.v4;
2
3
import java.util.ArrayList;
4
import java.util.HashMap;
5
import java.util.HashSet;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Set;
9
10
import org.chocosolver.solver.Model;
11
import org.chocosolver.solver.constraints.Constraint;
12
import org.chocosolver.solver.variables.IntVar;
13
import org.chocosolver.util.iterators.DisposableValueIterator;
14
15
import it.cnr.istc.pst.platinum.ai.framework.microkernel.annotation.lifecycle.PostConstruct;
16
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.event.AddConstraintParameterNotification;
17
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.event.AddParameterNotification;
18
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.event.DelConstraintParameterNotification;
19
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.event.DelParameterNotification;
20
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.event.ParameterNotification;
21
import it.cnr.istc.pst.platinum.ai.framework.parameter.csp.solver.ParameterSolver;
22
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.EnumerationParameter;
23
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.NumericParameter;
24
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.Parameter;
25
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.BinaryParameterConstraint;
26
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.BindParameterConstraint;
27
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.EqualParameterConstraint;
28
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.ExcludeParameterConstraint;
29
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.NotEqualParameterConstraint;
30
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.ParameterConstraint;
31
32
/**
33
 * 
34
 * @author anacleto
35
 *
36
 */
37
public class ChocoSolver extends ParameterSolver 
38
{
39
	private boolean clean;											// clean flag
40
	private Model model;											// CSP model
41
	
42
	private Map<Parameter<?>, IntVar> variables;					// variables of the model
43
	private Map<ParameterConstraint, Constraint> constraints;		// constraints of the model
44
	
45
	/**
46
	 * 
47
	 */
48
	public ChocoSolver() {
49
		super();
50
		// setup data structures
51
		this.variables = new HashMap<>();
52
		this.constraints = new HashMap<>();
53
	}
54
	
55
	/**
56
	 * 
57
	 */
58
	@PostConstruct
59
	private void init() {
60
		// build the model
61
		this.build();
62
	}
63
64
	/**
65
	 * 
66
	 */
67
	@Override
68
	public boolean isConsistent() 
69
	{
70
		// check if clean
71
		if (!this.clean) {
72
			// rebuild the model
73
			this.build();
74
		}
75
		
76
		// consistency flag
77
		boolean consistent = true;
78
		// try to find a solution
79
		this.model.getSolver().solve();
80
		// check feasibility
81
		switch (this.model.getSolver().isFeasible()) 
82
		{
83
			// not feasible
84
			case FALSE : 
85
			case UNDEFINED : {
86
				// no feasible solutions exist
87
				consistent = false;
88
				this.model.getSolver().reset();
89
			}
90
			break;
91
			
92
			// feasible or undefined
93
			case TRUE : {
94
				// a feasible solution exists at least
95
				consistent = true;
96
				this.model.getSolver().reset();
97
			}
98
			break;
99
		}
100
		
101
		// get consistency flag
102
		return consistent;
103
	}
104
	
105
	/**
106
	 * 
107
	 */
108
	@Override
109
	public void computeSolution()
110
	{
111
		// check clean flag
112
		if (!this.clean) {
113
			// build the model
114
			this.build();
115
		}
116
		
117
		// compute values for each parameter
118
		for (Parameter<?> param : this.variables.keySet()) {
119
			this.computeValues(param);
120
		}
121
	}
122
123
	/**
124
	 * 
125
	 */
126
	@Override
127
	public void computeValues(Parameter<?> param) 
128
	{
129
		// get variable
130
		if (!this.variables.containsKey(param)) {
131
			throw new RuntimeException("Parameter not found in the CSP\n- " + param);
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
132
		}
133
		
134
		// check clean flag
135
		if (!this.clean) {
136
			// build the model
137
			this.build();
138
		}
139
	
140
		// check parameter type
141
		switch (param.getType())
142
		{
143
			// enumeration parameter
144
			case ENUMERATION_PARAMETER_TYPE : 
145
			{
146
				// get numeric parameter
147
				EnumerationParameter ep = (EnumerationParameter) param;
148
				// compute allowed values
149
				Set<Integer> vals = new HashSet<>();
150
				// check possible solutions
151
				while (this.model.getSolver().solve())
152
				{
153
					// get variable
154
					IntVar var = this.variables.get(ep);
155
					DisposableValueIterator it = var.getValueIterator(true);
156
					while (it.hasNext()) {
157
						// add value
158
						vals.add(it.next());
159
					}
160
					// dispose iterator
161
					it.dispose();
162
				}
163
				
164
				// set allowed values
165
				int[] values = new int[vals.size()];
166
				int index = 0;
167
				for (int v : vals) {
168
					// get val
169
					values[index] = v;
170
					index++;
171
				}
172
173
				// set values
174
				ep.setValues(values);
175
				
176
				// reset solver
177
				this.model.getSolver().reset();
178
			}
179
			break;
180
			
181
			// numeric parameter
182
			case NUMERIC_PARAMETER_TYPE : 
183
			{
184
				// get numeric parameter
185
				NumericParameter np = (NumericParameter) param;
186
				int lb = Integer.MIN_VALUE;
187
				int ub = Integer.MAX_VALUE;
188
				// check all solutions
189
				while (this.model.getSolver().solve()) {
190
					// check variable bounds
191
					IntVar var = this.variables.get(np);
192
					lb = Math.max(lb, var.getLB());
193
					ub = Math.min(ub, var.getUB());
194
				}
195
				
196
				// set bounds
197
				np.setLowerBound(lb);
198
				np.setUpperBound(ub);
199
				// reset solver
200
				this.model.getSolver().reset();
201
			}
202
			break;
203
		}
204
	}
205
206
	/**
207
	 * 
208
	 */
209
	@Override
210
	public void update(ParameterNotification info) 
211
	{
212
		// check notification type
213
		switch (info.getType())
214
		{
215
			case ADD_PARAM : 
216
			{
217
				// get notification
218
				AddParameterNotification notif = (AddParameterNotification) info;
219
				// create CSP variable
220
				IntVar variable = this.doCreateCSPVariable(notif.getParameter());
221
				// add variable to the model
222
				this.variables.put(notif.getParameter(), variable);
223
			}
224
			break;
225
		
226
			case ADD_CONSTRAINT : 
227
			{
228
				// get notification
229
				AddConstraintParameterNotification notif = (AddConstraintParameterNotification) info;
230
				// create CSP constraint
231
				Constraint cons = this.doCreateCSPConstraint(notif.getParameterConstraint());
232
				// check model status to post constraint
233
				if (this.clean) {
234
					cons.post();
235
				}
236
				// add constraint
237
				this.constraints.put(notif.getParameterConstraint(), cons);
238
			}
239
			break;
240
			
241
			case DEL_CONSTRAINT : 
242
			{
243
				// get notification 
244
				DelConstraintParameterNotification notif = (DelConstraintParameterNotification) info;
245
				// get constraint 
246
				ParameterConstraint cons = notif.getParameterConstraint();
247
				// remove constraint
248
				this.constraints.remove(cons);
249
				// set the clean flag to false
250
				this.clean = false;
251
			}
252
			break;
253
			
254
			case DEL_PARAM : 
255
			{
256
				// get notification 
257
				DelParameterNotification notif = (DelParameterNotification) info;
258
				// get parameter to remove
259
				Parameter<?> param = notif.getParameter();
260
				// remove variable from the model
261
				this.variables.remove(param);
262
				
263
				// remove related constraints
264
				List<ParameterConstraint> toRemove = this.doFindParameterRelatedConstraints(param);				
265
				// remove constraints from the model
266
				for (ParameterConstraint cons : toRemove) {
267
					this.constraints.remove(cons);
268
				}
269
				
270
				// set the clan flag to false
271
				this.clean = false;
272
			}
273
			break;
274
				
275
			default: {
276
				// unknown notification
277
				throw new RuntimeException("Unknown parameter notification type - " + info.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
278
			}		
279
		}
280
	}
281
	
282
	/**
283
	 * 
284
	 */
285
	@Override
286
	public String toString() {
287
		return this.model.toString();
288
	}
289
	
290
	/**
291
	 * 
292
	 */
293
	private void build() 
294
	{
295
		// setup new model
296
		this.model = new Model("Chocho CSP model");
297
		this.model.getSolver().setDFS();
298
		
299
		// update variables associated to parameters
300
		for (Parameter<?> param : this.variables.keySet()) {
301
			// create parameter
302
			IntVar var = this.doCreateCSPVariable(param);
303
			this.variables.put(param, var);
304
		}
305
		
306
		
307
		// update constraints between variables
308
		for (ParameterConstraint constraint : this.constraints.keySet()) {
309
			// create constraint
310
			Constraint cons = this.doCreateCSPConstraint(constraint);
311
			this.constraints.put(constraint, cons);
312
		}
313
		
314
		// post constraints
315
		for (ParameterConstraint constraint : this.constraints.keySet()) {
0 ignored issues
show
Performance introduced by
When you need both the keys and the value of a Map, iterating over entrySet() instead of keySet() is more readable.
Loading history...
316
			// post CSP constraint
317
			this.constraints.get(constraint).post();
318
		}
319
		
320
		// set clean flag
321
		this.clean = true;
322
	}
323
	
324
	/**
325
	 * 
326
	 * @param param
327
	 * @return
328
	 */
329
	private IntVar doCreateCSPVariable(Parameter<?> param)
330
	{
331
		// CSP variable
332
		IntVar var;
333
		// check parameter type
334
		switch (param.getType())
335
		{
336
			// enumeration parameter
337
			case ENUMERATION_PARAMETER_TYPE : 
338
			{
339
				// get enumeration parameter
340
				EnumerationParameter p = (EnumerationParameter) param;
341
				// get value indexes
342
				int[] values = p.getValueIndexes();
343
				// create variable
344
				var = this.model.intVar(p.getLabel(), values);
345
			}
346
			break;
347
			
348
			// numeric parameter
349
			case NUMERIC_PARAMETER_TYPE : 
350
			{
351
				// get numeric parameter
352
				NumericParameter p = (NumericParameter) param;
353
				// create variable
354
				var = this.model.intVar(p.getLabel(), p.getLowerBound(), p.getUpperBound());
355
			}
356
			break;
357
			
358
			// unknown parameter
359
			default : {
360
				throw new RuntimeException("Unknown parameter type - " + param.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
361
			}
362
		}
363
		
364
		// get CSP variable
365
		return var;
366
	}
367
	
368
	/**
369
	 * 
370
	 * @param constraint
371
	 * @return
372
	 */
373
	private Constraint doCreateCSPConstraint(ParameterConstraint constraint)
374
	{
375
		Constraint cons;
376
		// check constraint type
377
		switch (constraint.getType())
378
		{
379
			// bind parameter constraint
380
			case BIND : 
381
			{
382
				// get bind constraint
383
				BindParameterConstraint bind = (BindParameterConstraint) constraint;
384
				cons = this.doCreateBindCSPConstraint(bind);
385
			}
386
			break;
387
			
388
			case EXCLUDE :
389
			{
390
				// get exclude constraint
391
				ExcludeParameterConstraint ex = (ExcludeParameterConstraint) constraint;
392
				cons = this.doCreateExcludeCSPConstraint(ex);
393
			}
394
			break;
395
				
396
			// equal parameter constraint
397
			case EQUAL : 
398
			{
399
				// get equal constraint
400
				EqualParameterConstraint eq = (EqualParameterConstraint) constraint;
401
				cons = this.doCreateEqualCSPConstraint(eq);
402
			}
403
			break;
404
			
405
			// not equal parameter constraint
406
			case NOT_EQUAL : 
407
			{
408
				// get not equal constraint
409
				NotEqualParameterConstraint neq = (NotEqualParameterConstraint) constraint;
410
				cons = this.doCreateNotEqualCSPConstraint(neq);
411
			}
412
			break;
413
			
414
			default : {
415
				throw new RuntimeException("Unknown parameter constraint type - " + constraint.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
416
			}
417
		}
418
		
419
		// get CSP constraint
420
		return cons;
421
	}
422
	
423
	/**
424
	 * 
425
	 * @param bind
426
	 * @return
427
	 */
428 View Code Duplication
	private Constraint doCreateBindCSPConstraint(BindParameterConstraint bind)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
429
	{
430
		// CSP constraint
431
		Constraint cons;
432
		// get reference parameter
433
		Parameter<?> param = bind.getReference();
434
		// check if parameter variable exists
435
		if (!this.variables.containsKey(param)) {
436
			throw new RuntimeException("Unknown parameter variable - " + param);
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
437
		}
438
		
439
		// check parameter type 
440
		switch(param.getType())
441
		{
442
			// binding to enumeration parameter
443
			case ENUMERATION_PARAMETER_TYPE : 
444
			{
445
				// get parameter
446
				EnumerationParameter p = (EnumerationParameter) param;
447
				// get variable
448
				IntVar var = this.variables.get(p);
449
				// get binding value
450
				String value = (String) bind.getValue();
451
				// get related index
452
				int index = p.getDomain().getIndex(value);
453
				// create constraint 
454
				cons = this.model.arithm(var, "=", index);
455
			}	
456
			break;
457
				
458
			// binding numeric variable
459
			case NUMERIC_PARAMETER_TYPE : 
460
			{
461
				// get parameter 
462
				NumericParameter p = (NumericParameter) param;
463
				// get variable 
464
				IntVar var = this.variables.get(p);
465
				// get binding value
466
				int value = Integer.parseInt(bind.getValue().toString());
467
				// create constraint
468
				cons = this.model.arithm(var, "=", value);
469
			}
470
			break;
471
				
472
			default : {
473
				throw new RuntimeException("Unknown parameter type - " + param.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
474
			}
475
		}
476
		
477
		// get create CSP constraint
478
		return cons;
479
	}
480
	
481
	/**
482
	 * 
483
	 * @param bind
484
	 * @return
485
	 */
486 View Code Duplication
	private Constraint doCreateExcludeCSPConstraint(ExcludeParameterConstraint bind)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
487
	{
488
		// CSP constraint
489
		Constraint cons;
490
		// get reference parameter
491
		Parameter<?> param = bind.getReference();
492
		// check if parameter variable exists
493
		if (!this.variables.containsKey(param)) {
494
			throw new RuntimeException("Unknown parameter variable - " + param);
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
495
		}
496
		
497
		// check parameter type 
498
		switch(param.getType())
499
		{
500
			// binding to enumeration parameter
501
			case ENUMERATION_PARAMETER_TYPE : 
502
			{
503
				// get parameter
504
				EnumerationParameter p = (EnumerationParameter) param;
505
				// get variable
506
				IntVar var = this.variables.get(p);
507
				// get binding value
508
				String value = (String) bind.getValue();
509
				// get related index
510
				int index = p.getDomain().getIndex(value);
511
				// create constraint 
512
				cons = this.model.arithm(var, "!=", index);
513
			}	
514
			break;
515
				
516
			// binding numeric variable
517
			case NUMERIC_PARAMETER_TYPE : 
518
			{
519
				// get parameter 
520
				NumericParameter p = (NumericParameter) param;
521
				// get variable 
522
				IntVar var = this.variables.get(p);
523
				// get binding value
524
				int value = (int) bind.getValue();
525
				// create constraint
526
				cons = this.model.arithm(var, "!=", value);
527
			}
528
			break;
529
				
530
			default : {
531
				throw new RuntimeException("Unknown parameter type - " + param.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
532
			}
533
		}
534
		
535
		// get create CSP constraint
536
		return cons;
537
	}
538
	
539
	/**
540
	 * 
541
	 * @param constraint
542
	 * @return
543
	 */
544
	private Constraint doCreateEqualCSPConstraint(EqualParameterConstraint constraint)
545
	{
546
		// check if parameter variables exist
547
		if (!this.variables.containsKey(constraint.getReference()) || 
548
				!this.variables.containsKey(constraint.getTarget())) 
549
		{
550
			throw new RuntimeException("Unknownw parameter variables\n- reference= " + constraint.getReference() + "\n- target= " + constraint.getTarget() + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
551
		}
552
		
553
		// get variables
554
		IntVar ref = this.variables.get(constraint.getReference());
555
		IntVar tar = this.variables.get(constraint.getTarget());
556
		
557
		// create constraint
558
		Constraint cons = this.model.allEqual(ref, tar);
559
		return cons;
560
	}
561
	
562
	/**
563
	 * 
564
	 * @param constraint
565
	 * @return
566
	 */
567
	private Constraint doCreateNotEqualCSPConstraint(NotEqualParameterConstraint constraint)
568
	{
569
		// check if parameter variables exist
570
		if (!this.variables.containsKey(constraint.getReference()) || 
571
				!this.variables.containsKey(constraint.getTarget())) 
572
		{
573
			throw new RuntimeException("Unknownw parameter variables\n- reference= " + constraint.getReference() + "\n- target= " + constraint.getTarget() + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
574
		}
575
		
576
		// get variables
577
		IntVar ref = this.variables.get(constraint.getReference());
578
		IntVar tar = this.variables.get(constraint.getTarget());
579
		
580
		// create constraint
581
		Constraint cons = this.model.allDifferent(ref, tar);
582
		return cons;
583
	}
584
	
585
	/**
586
	 * 
587
	 * @param param
588
	 * @return
589
	 */
590
	private List<ParameterConstraint> doFindParameterRelatedConstraints(Parameter<?> param)
591
	{
592
		// list of parameter related constraints
593
		List<ParameterConstraint> list = new ArrayList<>();
594
		// check constraints
595
		for (ParameterConstraint cons : this.constraints.keySet()) 
596
		{
597
			// check constraint type
598
			switch (cons.getType()) 
599
			{
600
				// bind constraint
601
				case BIND : 
602
				case EXCLUDE : 
603
				{
604
					// check reference
605
					if (cons.getReference().equals(param)) {
606
						// remove constraint
607
						list.add(cons);
608
					}
609
				}
610
				break;
611
			
612
				// binary constraint
613
				case EQUAL : 
614
				case NOT_EQUAL : 
615
				{
616
					// get binary constraint
617
					BinaryParameterConstraint binary = (BinaryParameterConstraint) cons;
618
					if (binary.getReference().equals(param) || binary.getTarget().equals(param)) {
619
						// add constraint
620
						list.add(cons);
621
					}
622
				}
623
				break;
624
				
625
				default : {
626
					// unknown 
627
					throw new RuntimeException("Unknownw parameter constraint type - " + cons.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
628
				}
629
			}
630
		}
631
		
632
		// get list
633
		return list;
634
	}
635
}
636