CONOPT
Loading...
Searching...
No Matches
mp_qpbandb.f90
Go to the documentation of this file.
1!> @file mp_qpbandb.f90
2!! @ingroup FORTOPENMP_EXAMPLES
3!!
4!!
5!! QPBandB: Multi Threaded implementation of QP4 MINLP model
6!! The implementation shows how to implement a parallel Branch & Bound
7!! procedure that still is deterministic independent of the order in
8!! which the sub-models are solved (within the framework defined here
9!! with Work-pools).
10!!
11!! When testing that the sequential and parallel algorithms uses the same
12!! number of nodes we have a test that the solves are identical even
13!! when run with different threads. This is some kind of test that
14!! CONOPT Solves are reproducable and that there are no un-initialized
15!! values used in the algorithm.
16!!
17!!
18!! For more information about the individual callbacks, please have a look at the source code.
19
20#if defined(_WIN32) && !defined(_WIN64)
21#define dec_directives_win32
22#endif
23
24Module qp_data
25 Implicit None
26 Integer, Parameter :: NN = 32 ! Dimension of Q
27 Integer, Parameter :: Nvar = 2*nn ! Number of variables in model
28 Integer, Parameter :: nbin = nn ! Number of binary variables in model
30 Integer, Parameter :: nobs = 60 ! Observations used to estimate Q
31 Real(8), dimension(NN,NN) :: q
32 Real(8), dimension(nn) :: mean
33 Real(8) :: target
34 Integer, Parameter :: maxbin = 15
35 Integer, Dimension(Nbin) :: binmap ! Mapping from binary to index in all variables
36End Module qp_data
38Module bb_data
39!
40! Data used to manage the Branch and Bound Process
41!
42 Use qp_data
43 Use omp_lib
44 Implicit None
45!
46! Branch and bound node data
47!
48 Type bbnode
49 Integer :: Number ! Sequense number of the node.
50 real(8), dimension(NVar) :: Values ! Solution value or initial values
51 Integer, dimension(Nbin) :: fixed ! Binary: 0=fixed zero, 1=fixed 1, -1 not fixed.
52 Type (bbnode), Pointer :: prvnode, nxtnode ! Pointer forward and backward in
53 ! double-linked list of active nodes
54 real(8) :: object ! Objective value (if solved) or lower bound if
55 ! not yet solved
56 Integer :: node_stat ! Node Status:
57 ! 0 - created but not solved
58 ! 1 - solved
59 Integer :: solstat ! Solution status. Initialized to -1 and
60 ! redefined when the model has been solved
61 Integer :: modstat ! Model status. Initialized to -1 and
62 ! redefined when the model has been solved
63 Integer :: depth ! Depth of the node in the B&B tree
64 Logical :: isinteger ! Is true iff the solution is integer
65 Integer :: sthread ! The thread being used when solving
66 End type bbnode
68 Type bbnodeptr
69 Type (bbnode), Pointer :: bnode
70 End Type bbnodeptr
72 Real(8), Parameter :: bintol = 1.d-7
73 Integer :: totnodes ! Total number of nodes in use
74 Integer :: freenodes ! Number of active nodes
75 Integer :: actnodes ! Number of free nodes in a free list
76 Integer :: numsolve ! Counter for finished Solves.
78! Data for best solution
79!
80 Logical :: intfound ! Global flag indicating whether we already have an integer
81 ! feasible solution.
82 Integer :: numintfound ! Number of integer solutions found
83 Real(8) :: bestint ! Objective value for the best integer solution found so far.
84 Real(8), dimension(NVar) :: solution ! The solution corresponding to BestInt
86! Data for managing the Branch and Bound Tree
87!
88 Type (bbnode), Pointer :: actnode ! Pointer to first node in a list of active untested noded
89 Type (bbnode), Pointer :: freenode ! Pointer to first node in a freelist
91! Data for managing a WorkPool with the nodes selected for the next
92! set of parallel Solves
93!
94 Integer, Parameter :: maxmaxpool = 64 ! Allocation size for WorkPool
95 Integer :: maxpool ! Largest size of WorkPool selected by user
96 Logical :: maxdyn ! If .true. then MaxPool above is dynamic
97 Integer :: workpool ! Size of the actual workpool
98 Type (bbnodeptr) :: work_node(maxmaxpool) ! Pointers to the selected nodes in the WorkPool
100 integer :: maxthread ! Maximum number of threads
101 Logical :: parallel ! If true then run the COI_Solve loop over the nodes
102 ! in the WorkPool in parallel
104 Integer, Dimension(:), Pointer :: cntvect
105 End Type controlv
106 Type (controlv), Dimension(:), Pointer :: cntvect1 ! CONOPT Control vectors, one for each thread
107 Real(8) :: stime ! Accumulated time in Solve Loop
109 Contains
110!
111! Routines used to manage the Branch and Bound Tree
112!
113Subroutine remove_activenode(Node)
114!
115! Remove a node from the list of active nodes.
116!
117 Implicit None
118 Type (BBNode), Pointer :: Node
119
120 if ( associated(node%prvnode) ) then
121 node%prvnode%nxtnode => node%nxtnode
122 else
123 actnode => node%nxtnode
124 endif
125 if ( associated(node%nxtnode) ) then
126 node%nxtnode%prvnode => node%prvnode
127 endif
128 actnodes = actnodes - 1
129
130End Subroutine remove_activenode
131
132Subroutine return_freenode(Node)
133!
134! Link the node into the free list. The free list does not use prvnode
135!
136 Implicit None
137 Type (BBNode), Pointer :: Node
138
139 node%nxtnode => freenode
140 freenode => node
141 freenodes = freenodes + 1
142
143End Subroutine return_freenode
144
145Subroutine get_freenode(Node)
146!
147! Get a free node to be used in the list of active nodes and initialize
148! the status.
149!
150 Implicit None
151 Type (BBNode), Pointer :: Node
152
153 if ( associated(freenode) ) then
154 node => freenode
155 freenode => freenode%Nxtnode
156 freenodes = freenodes - 1
157 else
158 Allocate(node)
159 Nullify(node%NxtNode);
160 Nullify(node%PrvNode);
161 totnodes = totnodes + 1
162 node%Number = totnodes
163 endif
164 node%Node_Stat = 0
165 node%Solstat =-1
166 node%Modstat =-1
167 node%Sthread =-1
168
169End Subroutine get_freenode
170
171Subroutine deallocate_nodes
172!
173! Deallocates the nodes in the free list between solves so the next
174! solve starts without any nodes.
175!
176 Implicit None
177 Type (BBNode), Pointer :: Node, Next
178
179 node => freenode
180 do while ( Associated(node) )
181 next => node%Nxtnode
182 Deallocate(node);
183 node => next
184 enddo
185 Nullify(freenode)
186
187End Subroutine deallocate_nodes
188
189Subroutine add_activenode(Node)
190!
191! Add a node to the front of the list of Active nodes
192!
193 Implicit None
194 Type (BBNode), pointer :: Node
195
196 actnodes = actnodes + 1
197 if ( associated(actnode) ) then
198 node%NxtNode => actnode
199 actnode%PrvNode => node;
200 else
201 Nullify(node%NxtNode);
202 endif
203 Nullify(node%PrvNode);
204 actnode => node
205
206End Subroutine add_activenode
207
208Subroutine add2workpool( Node )
209!
210! Add a node to the Workpool list
211!
212 Implicit None
213 Type (BBNode), pointer :: Node
214
215 workpool = workpool + 1
216! write(*,*) 'Work_node(',Workpool,') has number',node%number
217 work_node(workpool)%Bnode => node
218
219end Subroutine add2workpool
220
221Subroutine list_node(node)
222
223 Implicit None
224 Type (BBNode), pointer :: Node
225
226 If ( Associated(node) ) Then
227 write(*,*) 'List_Node: Number=',node%Number,' Node_Stat=',node%node_stat
228 Else
229 write(*,*) 'List_Node: Node not associated.'
230 Endif
231End Subroutine list_node
232
233Subroutine list_nodes
234
235 Implicit None
236 Type (BBNode), Pointer :: Node
237 Integer :: N
238
239 n = 0
240 node => actnode
241 do while ( Associated(node) )
242 write(*,"('List_nodes: Node number=',i4,' Node_Stat=',I2,' Object=',1pe15.8)") node%number, node%node_stat, node%object
243 node => node%nxtnode
244 n = n + 1
245 enddo
246 write(*,*) 'List_nodes: Total=',n
247
248End Subroutine list_nodes
249
250Subroutine select_var(Node, IB)
251!
252! Select variable to branch on, counted in the space of binary variables.
253! Currently there is only one rule, namely to select based on max
254! infeasibility. Other Variable selection rules could be implemented
255! in this routine.
256!
257 Implicit None
258 Type (BBNode), Pointer :: Node
259 integer :: IB, i, j
260 Real(8) :: Dist, Maxdist
261
262 maxdist = 0.d0
263 ib = 0
264 do i = 1, nn
265 j = binmap(i)
266 dist = min( node%values(j), 1.d0-node%values(j) )
267 if ( dist > maxdist ) then
268 maxdist = dist
269 ib = i
270 endif
271 enddo
272
273End Subroutine select_var
274
275subroutine create_workpool
276!
277! Create a workpool of up to MaxPool nodes to be processed in
278! parallel.
279! The nodes are removed from the active list.
280!
281 Implicit None
282 Type (BBNode), Pointer :: Node, Curr, Next
283 Real(8) :: Cutoff
284 integer :: IB ! Branching variable
285
286 Nullify(node)
287 workpool = 0
288 write(*,*) 'Create_WorkPool'
289!
290! If the max size of the workpool is dynamic then use the formula
291! MaxThread*min(8,1+ActNodes/(MaxThread*5)). With few nodes
292! (<MaxThread*5) we will select MaxThread nodes. With more nodes we
293! will select gradually more up to a maximum of MaxThread*8.
294!
295 if ( maxdyn ) maxpool = maxthread*min(8,1+actnodes/(maxthread*5))
296 do while ( workpool < maxpool )
297 cutoff = 1.d30
298 curr => actnode
299!
300! Run through the linked list of active nodes and find the best.
301! We use the objective but other criteria could be used
302!
303 Nullify(node)
304 do while (associated(curr))
305 next => curr%NxtNode
306 if ( curr%Object < cutoff ) then
307 node => curr
308 cutoff = curr%Object
309 endif
310 curr => next
311 enddo
312 if ( .not. associated(node) ) then
313 exit
314 endif
315 if ( node%Node_Stat == 0 ) then
316!
317! The node has been created but not solved.
318! Take it immediately: remove it from the active list and add it
319! to the work_node vector
320!
321 write(*,"('Unsolved node',i5,' selected. Obj=',e24.17)") node%Number,node%Object
322 Call remove_activenode(node)
323 call add2workpool(node)
324 else
325!
326! The node has been solved. Split it in two and take one or both
327! depending on the space left in the workpool. The total number
328! of nodes will grow by one so a dynamic MaxPool must be adjusted
329! before the space test below
330!
331 if ( maxdyn ) maxpool = maxthread*min(8,1+(actnodes+1)/(maxthread*5))
332!
333! Get a new node and, select a branching variable, and copy the
334! old node into the new node.
335!
336 call get_freenode(next)
337 call select_var( node, ib )
338 next%Values = node%Values
339 next%Fixed = node%Fixed
340 next%Object = node%Object
341!
342! Make the two node unsolved and fix the branching variable down and up
343! respectively.
344!
345 node%Node_Stat = 0
346 node%Solstat = -1
347 node%Modstat = -1
348 node%Depth = node%Depth + 1
349 node%Fixed(ib) = 0 ! Branch down
350
351 next%Node_Stat = 0
352 next%Solstat = -1
353 next%Modstat = -1
354 next%Depth = node%Depth
355 next%Fixed(ib) = 1 ! Branch up
356!
357! Add the first node to the workpool
358!
359 Call remove_activenode(node)
360 call add2workpool(node)
361 write(*,"('New-Down node',i5,' selected. Obj=',e24.17)") node%Number,node%Object
362!
363! Add the second node to the workpool or to the pool of active
364! nodes, depending on space in the workpool
365!
366 if ( workpool < maxpool ) then
367 call add2workpool(next)
368 write(*,"('New-Up Next',i5,' selected. Obj=',e24.17)") next%Number,next%Object
369 else
370 call add_activenode(next)
371 endif
372 endif
373 enddo
374
375end subroutine create_workpool
376
377subroutine solve_workpool
378!
379! Solve the models in the WorkPool and integrate the solutions into
380! the active list of nodes. Update the best solution if one is found.
381!
382 Use proginfop
383 Use conopt
384 implicit none
385
386 integer nw ! index for active node in the WorkPool
387 integer Thread
388 Integer, Dimension(:), pointer :: CntVect ! CONOPT Control vector for current node
389 integer COI_Error
390 Type (BBNode), Pointer :: Node, Curr, Next
391 Logical :: NewInt
392 Real(8) Time0
393
394! write(*,*) 'Calling Solve_WorkPool with',WorkPool,' nodes.'
395 time0 = omp_get_wtime()
396 if ( workpool .le. 1 .OR. .NOT. parallel ) Then
397! This is a serial version
398 thread = 1
399 do nw = 1, workpool
400 node => work_node(nw)%Bnode
401 if ( debug ) then
402 write(16,*) 'Starting to solve node',node%number,' using thread',thread
403 endif
404 cntvect => cntvect1(thread)%CntVect
405 coi_error = coidef_usrmem( cntvect, node ) ! Pass the current node through Usrmem
406 If ( coi_error .ne. 0 ) THEN
407 write(*,*)
408 write(*,*) '**** Fatal Error while loading CONOPT Callback routines.'
409 write(*,*)
410 stop
411 ENDIF
412 node%Sthread = thread
413 coi_error = coi_solve( cntvect )
414 If ( coi_error .ne. 0 ) THEN
415 write(*,*)
416 write(*,*) '**** Fatal Error while solving.'
417 write(*,*)
418 stop
419 ENDIF
420 enddo
421 Else
422! And this is the corresponding Parallel version of the SOLVE loop.
423!$OMP PARALLEL DEFAULT(SHARED) Private(COI_Error,Thread, Node)
424!$OMP DO PRIVATE(Thread, COI_Error, Node, CntVect) SCHEDULE(Guided)
425 do nw = 1, workpool
426 node => work_node(nw)%Bnode
427 thread = 1+omp_get_thread_num()
428 if ( debug ) then
429 write(16,*) 'Starting to solve node',node%number,' using thread',thread
430 endif
431 cntvect => cntvect1(thread)%CntVect
432 coi_error = coidef_usrmem( cntvect, node ) ! Pass the current node through Usrmem
433 If ( coi_error .ne. 0 ) THEN
434 write(*,*)
435 write(*,*) '**** Fatal Error while loading CONOPT Callback routines.'
436 write(*,*)
437 call flog( "Errors encountered during setup for Solve.", 1 )
438 ENDIF
439 node%Sthread = thread
440 coi_error = coi_solve( cntvect )
441 If ( coi_error .ne. 0 ) THEN
442 write(*,*)
443 write(*,*) '**** Fatal Error while solving.'
444 write(*,*)
445 call flog( "Errors encountered during Solve.", 1 )
446 ENDIF
447 enddo
448!$OMP END PARALLEL
449 Endif
450 stime = stime + omp_get_wtime() - time0
451 numsolve = numsolve + workpool
452!
453! Process the solutions. The loop is not parallelized so the order here
454! is fixed, independent of the order in which the nodes finished
455! solving.
456!
457 newint = .false. ! No new integer solution in this pass
458 do nw = 1, workpool
459 node => work_node(nw)%Bnode
460 write(*,'("Node=",I5," Solstat=",I3," Modstat=",I3," Object=",F24.17)') &
461 node%number, node%Solstat, node%modstat, node%Object
462 if ( node%Solstat .ne. 1 .or. node%Modstat .gt. 2 ) then
463!
464! Node was not solved properly
465!
466 call flog( "Solve did not return an normal solver status.", 1 )
467 Else if ( node%Modstat .gt. 2 ) then
468!
469! Node was not solved to local optimality. Fathom.
470!
471 write(*,*) 'Not optimal -- fathom'
472 call return_freenode(node)
473 else if ( intfound ) then
474 if ( node%object >= bestint ) then
475!
476! A better solution has been found. Fathom.
477!
478 write(*,*) 'Worse than optimal -- fathom'
479 call return_freenode(node)
480 else
481 if ( node%IsInteger ) then
482 write(*,*) 'Integer Solution Stored'
483 numintfound = numintfound + 1
484 newint = .true.
485 bestint = node%object
486 solution = node%Values
487 call return_freenode(node)
488 Else
489! write(*,*) 'Non-Integer. Kept'
490 call add_activenode(node)
491 Endif
492 endif
493 else
494!
495! An Integer solution has not yet been found. We cannot fathom it.
496!
497 if ( node%IsInteger ) then
498 write(*,*) 'Integer Solution Stored'
499 numintfound = numintfound + 1
500 intfound = .true.
501 newint = .true.
502 bestint = node%object
503 solution = node%Values
504 call return_freenode(node)
505 Else
506! write(*,*) 'Non-Integer. Kept'
507 call add_activenode(node)
508 Endif
509 endif
510 enddo
511!
512! If we did find a new integer solution then scan the list of active
513! nodes to check if some of them should be fathomed.
514!
515 if ( newint ) then
516 curr => actnode
517 do while (associated(curr))
518 next => curr%NxtNode
519 if ( curr%Object > bestint ) then
520 write(*,"('Node',I5,' with Object=',F18.12,' fathomed by new objective')") curr%Number, curr%Object
521 call remove_activenode(curr)
522 call return_freenode(curr)
523 endif
524 curr => next
525 enddo
526 endif
527
528end subroutine solve_workpool
529
530End Module bb_data
531
532REAL FUNCTION rndx( )
533!
534! Defines a pseudo random number between 0 and 1
535!
536 IMPLICIT NONE
537
538 Integer, save :: seed = 12359
539
540 seed = mod(seed*1027+25,1048576)
541 rndx = float(seed)/float(1048576)
542
543END FUNCTION rndx
544
545subroutine defdata
546!
547! Define values for A, B, and Obs
548!
549 Use qp_data
550 IMPLICIT NONE
551
552 Integer :: i, j, k
553 Real, External :: Rndx
554 Real(8) :: Sum
555 Real(8), dimension(NN,Nobs) :: Xobs
556
557 Target = 10.0d0
558 do i = 1, nn
559 mean(i) = Target + (rndx()*4.d0-2.d0)
560 enddo
561!
562! Create a positive definite matrix computed as the sum of some
563! outer products
564!
565 do i = 1, nn
566 do j = 1, nn
567 q(i,j) = 0.d0
568 enddo
569 enddo
570 do i = 1, nn
571 sum = 0.d0
572 do k = 1, nobs
573 xobs(i,k) = 100.d0*rndx()
574 sum = sum + xobs(i,k)
575 enddo
576 sum = sum / nobs
577 do k = 1, nobs
578 xobs(i,k) = xobs(i,k) - sum
579 enddo
580 enddo
581 do i = 1, nn
582 do j = 1, i
583 sum = 0.d0
584 do k = 1, nobs
585 sum = sum + xobs(i,k) * xobs(j,k)
586 enddo
587 q(i,j) = sum / (nobs-1)
588 q(j,i) = q(i,j)
589 enddo
590 enddo
591!
592! Create BinMap
593!
594 do i = 1, nn
595 binmap(i) = nn+i
596 enddo
597
598end subroutine defdata
599!
600! Main program. A simple setup and call of CONOPT for a QP model
601!
602!> Main program. A simple setup and call of CONOPT
603!!
604Program qp_threads
605
607 Use conopt
608 use bb_data
609 use qp_data
610 Use omp_lib
611 Implicit None
612!
613! Data needed for Branch and bound
614!
615 Integer :: thread
616!
617! Declare the user callback routines as Integer, External:
618!
619 Integer, External :: qp_readmatrix ! Mandatory Matrix definition routine defined below
620 Integer, External :: qp_fdeval ! Function and Derivative evaluation routine
621 ! needed a nonlinear model.
622 Integer, External :: qp_2dlagrstr ! 2nd derivative routine for structure
623 Integer, External :: qp_2dlagrval ! 2nd derivative routine for values
624 Integer, External :: qp_2ddir ! Directional 2nd derivative routine
625 Integer, External :: bb_status ! callback for displaying solution status
626 Integer, External :: bb_solution ! callback for displaying solution values
627 Integer, External :: bb_message ! callback for managing messages
628 Integer, External :: bb_errmsg ! callback for managing error messages
629 Integer, External :: bb_option ! Define options using a callback. Files cannot be used
630 ! for multithreading since they can be shared and not
631 ! read in the proper order.
632#ifdef dec_directives_win32
633!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_ReadMatrix
634!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_FDEval
635!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DLagrStr
636!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DLagrVal
637!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DDir
638!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Status
639!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Solution
640!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Message
641!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_ErrMsg
642!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Option
643#endif
644!
645! Control vector
646!
647 INTEGER :: coi_error
648 Integer, Dimension(:), Pointer :: cntvect ! CONOPT Control vector for current node
649
650 Real(8) time0, time1, stime1
651 Real(8) time8s, time16s, time32s, timeds
652 Real(8) time8p, time16p, time32p, timedp
653 Real(8) stime8s, stime16s, stime32s, stimeds
654 Real(8) stime8p, stime16p, stime32p, stimedp
655 Integer numsolve1
656 Integer numsolve8s, numsolve16s, numsolve32s, numsolveds
657 Integer numsolve8p, numsolve16p, numsolve32p, numsolvedp
658
659 call startup
660 maxthread = omp_get_max_threads()
661 write(11,*) 'Initial MaxThread=',maxthread
662 write(*,*) 'Initial MaxThread=',maxthread
663 If ( maxthread .lt. 2 ) then
664 maxthread = 2
665 call omp_set_num_threads(maxthread)
666 write(11,*) 'Revised MaxThread=',maxthread
667 write(*,*) 'Revised MaxThread=',maxthread
668 Endif
669! Debug = .true. ! Turn on if debugging output is needed
670 If ( debug ) Then
671 Open(12,file='threadA1.txt',status='unknown')
672 Open(16,file='nodesA.txt',status='unknown')
673 Endif
674!
675 call defdata
676!
677! Create a vector of Control Vectors in CntVect1 and allocate and
678! initialize the individual vectors for each thread.
679!
680 Allocate( cntvect1( maxthread ) )
681 coi_error = 0
682 do thread = 1, maxthread
683 coi_error = coi_create( cntvect )
684 cntvect1(thread)%CntVect => cntvect
685!
686! Tell CONOPT about the size of the model by populating the Control Vector:
687! We will create a QP model with one constraint, sum(i, x(i) ) = 1
688! and NN variables. NN and the Q matrix are defined in Module QP_Data.
689!
690 coi_error = max( coi_error, coidef_numvar( cntvect, 2*nn ) ) ! NN variables
691 coi_error = max( coi_error, coidef_numcon( cntvect, 4+nn ) ) ! 3+NN constraint + 1 objective
692 coi_error = max( coi_error, coidef_numnz( cntvect, 6*nn ) ) ! 6*NN nonzeros in the Jacobian
693 coi_error = max( coi_error, coidef_numnlnz( cntvect, nn ) ) ! NN of which are nonlinear
694 coi_error = max( coi_error, coidef_numhess( cntvect, nn*(nn+1)/2 ) ) ! Hessian is dense in the NN nonlinear variables
695 coi_error = max( coi_error, coidef_optdir( cntvect, -1 ) ) ! Minimize
696 coi_error = max( coi_error, coidef_objcon( cntvect, 1 ) ) ! Objective is constraint 1
697!
698! Tell CONOPT about the callback routines:
699!
700 coi_error = max( coi_error, coidef_readmatrix( cntvect, qp_readmatrix ) )
701 coi_error = max( coi_error, coidef_fdeval( cntvect, qp_fdeval ) )
702 coi_error = max( coi_error, coidef_2dlagrstr( cntvect, qp_2dlagrstr ) )
703 coi_error = max( coi_error, coidef_2dlagrval( cntvect, qp_2dlagrval ) )
704 coi_error = max( coi_error, coidef_2ddir( cntvect, qp_2ddir ) )
705 coi_error = max( coi_error, coidef_status( cntvect, bb_status ) )
706 coi_error = max( coi_error, coidef_solution( cntvect, bb_solution ) )
707 coi_error = max( coi_error, coidef_message( cntvect, bb_message ) )
708 coi_error = max( coi_error, coidef_errmsg( cntvect, bb_errmsg ) )
709 If ( debug ) &
710 coi_error = max( coi_error, coidef_option( cntvect, bb_option ) )
711
712#if defined(CONOPT_LICENSE_INT_1) && defined(CONOPT_LICENSE_INT_2) && defined(CONOPT_LICENSE_INT_3) && defined(CONOPT_LICENSE_TEXT)
713 coi_error = max( coi_error, coidef_license( cntvect, conopt_license_int_1, conopt_license_int_2, conopt_license_int_3, conopt_license_text) )
714#endif
715 enddo
716 If ( coi_error .ne. 0 ) THEN
717 write(*,*)
718 write(*,*) '**** Fatal Error while loading CONOPT Callback routines.'
719 write(*,*)
720 call flog( "Skipping First Solve due to setup errors", 1 )
721 ENDIF
722 write(11,*) 'Finished Setup of model'
723 write(*,*) 'Finished Setup of model'
724!
725! Solve the B and B process with MaxPool = 1
726!
727 parallel = .false.
728 maxdyn = .false.
729 maxpool = 1
730 time0 = omp_get_wtime()
731 Call bandb_solve
732 time1 = omp_get_wtime() - time0
733 stime1 = stime
734 numsolve1 = numsolve
735 write(11,*) 'Finished sequential with Maxpool=',maxpool
736 write(*,*) 'Finished sequential with Maxpool=',maxpool
737 If ( debug ) Then
738 close(12); close(16)
739 Open(12,file='threadB1.txt',status='unknown')
740 Open(16,file='nodesB.txt',status='unknown')
741 Endif
742!
743! Redo the B and B process with MaxPool = 8
744!
745 maxpool = 8
746 time0 = omp_get_wtime()
747 Call bandb_solve
748 time8s = omp_get_wtime() - time0
749 stime8s = stime
750 numsolve8s = numsolve
751 write(11,*) 'Finished sequential with Maxpool=',maxpool
752 write(*,*) 'Finished sequential with Maxpool=',maxpool
753!
754! Redo the B and B process with MaxPool = 16
755!
756 maxpool = 16
757 time0 = omp_get_wtime()
758 Call bandb_solve
759 time16s = omp_get_wtime() - time0
760 stime16s = stime
761 numsolve16s = numsolve
762 write(11,*) 'Finished sequential with Maxpool=',maxpool
763 write(*,*) 'Finished sequential with Maxpool=',maxpool
764!
765! Redo the B and B process with MaxPool = 32
766!
767 maxpool = 32
768 time0 = omp_get_wtime()
769 Call bandb_solve
770 time32s = omp_get_wtime() - time0
771 stime32s = stime
772 numsolve32s = numsolve
773 write(11,*) 'Finished sequential with Maxpool=',maxpool
774 write(*,*) 'Finished sequential with Maxpool=',maxpool
775!
776! Redo the B and B process with Dynamic MaxPool
777!
778 maxdyn = .true.
779 time0 = omp_get_wtime()
780 Call bandb_solve
781 timeds = omp_get_wtime() - time0
782 stimeds = stime
783 numsolveds = numsolve
784 write(11,*) 'Finished sequential with Maxpool=',maxpool
785 write(*,*) 'Finished sequential with Maxpool=',maxpool
786 If ( debug ) Then
787 close(12); close(16)
788 Open(12,file='threadC1.txt',status='unknown')
789 Open(13,file='threadC2.txt',status='unknown')
790 Open(14,file='threadC3.txt',status='unknown')
791 Open(15,file='threadC4.txt',status='unknown')
792 Open(16,file='nodesC.txt',status='unknown')
793 Endif
794!
795! Redo again with same three MaxPool sizes but with a parallel solve loop.
796!
797 parallel = .true.
798 maxdyn = .false.
799 maxpool = 8
800 time0 = omp_get_wtime()
801 Call bandb_solve
802 time8p = omp_get_wtime() - time0
803 stime8p = stime
804 numsolve8p = numsolve
805 write(11,*) 'Finished parallel with Maxpool=',maxpool
806 write(*,*) 'Finished parallel with Maxpool=',maxpool
807 maxpool = 16
808 time0 = omp_get_wtime()
809 Call bandb_solve
810 time16p = omp_get_wtime() - time0
811 stime16p = stime
812 numsolve16p = numsolve
813 write(11,*) 'Finished parallel with Maxpool=',maxpool
814 write(*,*) 'Finished parallel with Maxpool=',maxpool
815 maxpool = 32
816 time0 = omp_get_wtime()
817 Call bandb_solve
818 time32p = omp_get_wtime() - time0
819 stime32p = stime
820 numsolve32p = numsolve
821 maxdyn = .true.
822 time0 = omp_get_wtime()
823 Call bandb_solve
824 timedp = omp_get_wtime() - time0
825 stimedp = stime
826 numsolvedp = numsolve
827 write(11,*) 'Finished parallel with Maxpool=',maxpool
828 write(*,*) 'Finished parallel with Maxpool=',maxpool
829!
830! Clean up
831!
832 DO thread = 1, maxthread
833 coi_error = max( coi_error, coi_free( cntvect1(thread)%CntVect ) )
834 Enddo
835 Deallocate( cntvect1 )
836
837 write(*,*) 'Number of Binary variables in model=',nn
838 write(*,*) 'Number of threads in parallel experiments=',maxthread
839 write(*,*)
840 write(*,"('Loop type MaxPool Total time % Solve Time % Number of Solves Parallel Speedup')")
841 write(*,*)
842 write(*,1000) 'Sequential',' 1',time1, 100.d0, stime1, 100.d0, numsolve1
843 write(*,1000) 'Sequential',' 8',time8s ,time8s /time1*100.d0, stime8s ,stime8s /stime1*100.d0, numsolve8s
844 write(*,1000) 'Sequential','16',time16s,time16s/time1*100.d0, stime16s,stime16s/stime1*100.d0, numsolve16s
845 write(*,1000) 'Sequential','32',time32s,time32s/time1*100.d0, stime32s,stime32s/stime1*100.d0, numsolve32s
846 write(*,1000) 'Sequential',' D',timeds ,timeds /time1*100.d0, stimeds ,stimeds /stime1*100.d0, numsolveds
847 write(*,1000) 'Parallel ',' 8',time8p ,time8p /time1*100.d0, stime8p ,stime8p /stime1*100.d0, numsolve8p , time8s/time8p
848 write(*,1000) 'Parallel ','16',time16p,time16p/time1*100.d0, stime16p,stime16p/stime1*100.d0, numsolve16p, time16s/time16p
849 write(*,1000) 'Parallel ','32',time32p,time32p/time1*100.d0, stime32p,stime32p/stime1*100.d0, numsolve32p, time32s/time32p
850 write(*,1000) 'Parallel ',' D',timedp ,timedp /time1*100.d0, stimedp ,stimedp /stime1*100.d0, numsolvedp , timeds/timedp
851
8521000 Format(a,5x,a2,f12.3,f9.1,f12.3,f9.1,i12,f19.2)
853
854 write(*,*)
855 write(*,*) 'End of QP Branch & Bound example.'
856
857#if defined (nocomp)
858 call flog( "Successful Solve", 0 )
859#else
860 if ( numsolve8s .ne. numsolve8p ) then
861 call flog( "Difference between number of nodes in sequential and parallel solve for MaxPool=8", 1 )
862 else if ( numsolve16s .ne. numsolve16p ) then
863 call flog( "Difference between number of nodes in sequential and parallel solve for MaxPool=16", 1 )
864 else if ( numsolve32s .ne. numsolve32p ) then
865 call flog( "Difference between number of nodes in sequential and parallel solve for MaxPool=32", 1 )
866 else if ( numsolveds .ne. numsolvedp ) then
867 call flog( "Difference between number of nodes in sequential and parallel solve for Dynamic MaxPool", 1 )
868 else
869 call flog( "Successful Solve", 0 )
870 endif
871#endif
872
873End Program qp_threads
874
875
876!> Sets runtime options
877!!
878!! @include{doc} option_params.dox
879Integer Function bb_option( ncall, rval, ival, lval, usrmem, name )
880#ifdef dec_directives_win32
881!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Option
882#endif
883 integer ncall, ival, lval
884 character(Len=*) :: name
885 real*8 rval
886 real*8 usrmem(*) ! optional user memory
887
888 Select Case (ncall)
889 case (1)
890 name = 'locon3'
891 ival = 0
892 case (2)
893 name = 'lotria'
894 ival = 0
895 case default
896 name = ' '
897 end Select
898 bb_option = 0
899
900end Function bb_option
901
902Subroutine bandb_solve
903
904 Use bb_data
905 Use qp_data
906 implicit none
907 Integer i
908 Type (BBNode), Pointer :: Node
909!
910! Initialize the first node for B&B tree
911!
912 numsolve = 0
913 numintfound = 0
914 Nullify(freenode)
915 Nullify(actnode)
916 intfound = .false.
917 totnodes = 0 ! Total number of nodes in use
918 actnodes = 0 ! Number of active nodes
919 freenodes = 0 ! Number of free nodes in a free list
920 stime = 0 ! Reset Solve loop timer
921!
922 Call get_freenode(node) ! Create a root node with no binaries fixed
923 node%Depth = 0;
924 do i = 1, nvar
925 node%Values(i) = 0.d0
926 enddo
927 do i = 1, nbin
928 node%Fixed(i) = -1
929 enddo
930 node%Object = 1.e29 ! We need a value for the first selection before
931 ! the node has been solved
932 Call add_activenode(node)
933 do while ( actnodes > 0 )
934 write(*,*) 'Creating WorkPool. Active nodes=',actnodes
935 Call create_workpool
936 write(*,*) 'WorkPool with ',workpool,' nodes selected. Remaining Active nodes=',actnodes
937 if ( workpool > 0 ) then
938 Call solve_workpool
939 endif
940 Enddo
941 Call deallocate_nodes ! Clean up again in the node list
942
943 if ( intfound ) then
944 write(*,*)
945 write(*,*) 'An integer solution with objective',bestint,' has been found.'
946 write(*,*)
947 write(*,*) 'Solution values:'
948 do i = 1, 2*nn
949 write(*,"(I5,1pe20.12)") i, solution(i)
950 enddo
951 else
952 write(*,*) 'No integer solution has been found'
953 endif
954 write(*,*) 'Number of Solves: ', numsolve
955 write(*,*) 'Number of Integer Solutions:', numintfound
956 write(*,*)
957
958End Subroutine bandb_solve
959!
960! ============================================================================
961! Define information about the model:
962!
963
964!> Define information about the model
965!!
966!! @include{doc} readMatrix_params.dox
967Integer Function qp_readmatrix( lower, curr, upper, vsta, type, rhs, esta, &
968 colsta, rowno, value, nlflag, n, m, nz, &
969 usrmem )
970#ifdef dec_directives_win32
971!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_ReadMatrix
972#endif
973 Use bb_data
974 Use qp_data
975 implicit none
976 integer, intent (in) :: n ! number of variables
977 integer, intent (in) :: m ! number of constraints
978 integer, intent (in) :: nz ! number of nonzeros
979 real*8, intent (in out), dimension(n) :: lower ! vector of lower bounds
980 real*8, intent (in out), dimension(n) :: curr ! vector of initial values
981 real*8, intent (in out), dimension(n) :: upper ! vector of upper bounds
982 integer, intent (in out), dimension(n) :: vsta ! vector of initial variable status
983 ! (not defined here)
984 integer, intent (out), dimension(m) :: type ! vector of equation types
985 integer, intent (in out), dimension(m) :: esta ! vector of initial equation status
986 ! (not defined here)
987 real*8, intent (in out), dimension(m) :: rhs ! vector of right hand sides
988 integer, intent (in out), dimension(n+1) :: colsta ! vector with start of column indices
989 integer, intent (out), dimension(nz) :: rowno ! vector of row numbers
990 integer, intent (in out), dimension(nz) :: nlflag ! vector of nonlinearity flags
991 real*8, intent (in out), dimension(nz) :: value ! vector of matrix values
992 Type (bbnode) :: usrmem
993 integer :: i, j
994!
995! Information about Variables:
996! Default: Lower = -Inf, Curr = 0, and Upper = +inf.
997! Default: the status information in Vsta is not used.
998!
999! Nondefault: Lower bound = 0 for all variables
1000!
1001 do i = 1, nvar
1002 lower(i) = 0.0d0
1003 enddo
1004 do i = 1, nn
1005 upper(nn+i) = 1.d0
1006 enddo
1007 do i = 1, nvar
1008 curr(i) = usrmem%Values(i)
1009 enddo
1010!
1011! Fix the binary variables if indicated by Fixed
1012!
1013 do i = 1, nbin
1014 if ( usrmem%fixed(i) == 0 ) then
1015 j = binmap(i)
1016 lower(j) = 0.d0
1017 upper(j) = 0.d0
1018 elseif ( usrmem%fixed(i) == 1 ) then
1019 j = binmap(i)
1020 lower(j) = 1.d0
1021 upper(j) = 1.d0
1022 endif
1023 enddo
1024!
1025! Information about Constraints:
1026! Default: Rhs = 0
1027! Default: the status information in Esta and the function
1028! value in FV are not used.
1029! Default: Type: There is no default.
1030! 0 = Equality,
1031! 1 = Greater than or equal,
1032! 2 = Less than or equal,
1033! 3 = Non binding.
1034!
1035! Constraint 1 (Objective)
1036! Rhs = 0.0 (default) and type Non binding
1037!
1038 type(1) = 3
1039!
1040! Constraint 2 (Sum of all X-vars = 1)
1041! Rhs = 1 and type Equality
1042!
1043 rhs(2) = 1.d0
1044 type(2) = 0
1045!
1046! Constraint 3 (average of all mean = target)
1047! Rhs = Target and type Eguality
1048!
1049 rhs(3) = target
1050 type(3) = 0
1051!
1052! Constraint 4 (sum of all Bin-vars =L= Maxbin)
1053! Rhs = Maxbin and type L
1054!
1055 rhs(4) = maxbin
1056 type(4) = 2
1057!
1058! Next N constraints ( x(i) - bin(i) =L= 0 )
1059! Rhs = 0 (default) and type L
1060!
1061 do i = 1,nn
1062 type(4+i) = 2
1063 enddo
1064!
1065! Information about the Jacobian.
1066!
1067! Colsta = Start of column indices (No Defaults):
1068! Rowno = Row indices
1069! Value = Value of derivative (by default only linear
1070! derivatives are used)
1071! Nlflag = 0 for linear and 1 for nonlinear derivative
1072! (not needed for completely linear models)
1073!
1074 j = 1 ! counter for current nonzero
1075 do i = 1, nn
1076 colsta(i) = j
1077 rowno(j) = 1 ! Objective - nonlinear
1078 nlflag(j) = 1
1079 j = j + 1
1080 rowno(j) = 2 ! sum(x) = 1
1081 value(j) = 1.d0
1082 nlflag(j) = 0
1083 j = j + 1
1084 rowno(j) = 3 ! sum(mean*x) = target
1085 value(j) = mean(i)
1086 nlflag(j) = 0
1087 j = j + 1
1088 rowno(j) = 4+i ! x(i) - bin(i) =l= 0
1089 value(j) = 1.d0
1090 nlflag(j) = 0
1091 j = j + 1
1092 enddo
1093 do i = 1, nn
1094 colsta(nn+i) = j
1095 rowno(j) = 4 ! sum(bin) =l= Maxbin
1096 value(j) = 1.d0
1097 nlflag(j) = 0
1098 j = j + 1
1099 rowno(j) = 4+i ! x(i) - bin(i) =l= 0
1100 value(j) = -1.d0
1101 nlflag(j) = 0
1102 j = j + 1
1103 enddo
1104 colsta(2*nn+1) = j
1105
1106 qp_readmatrix = 0 ! Return value means OK
1107
1108end Function qp_readmatrix
1109!
1110!==========================================================================
1111! Compute nonlinear terms and non-constant Jacobian elements
1112!
1113
1114!> Compute nonlinear terms and non-constant Jacobian elements
1115!!
1116!! @include{doc} fdeval_params.dox
1117Integer Function qp_fdeval( x, g, jac, rowno, jcnm, mode, ignerr, errcnt, &
1118 n, nz, thread, usrmem )
1119#ifdef dec_directives_win32
1120!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_FDEval
1121#endif
1122 Use bb_data
1123 Use qp_data
1124 implicit none
1125 integer, intent (in) :: n ! number of variables
1126 integer, intent (in) :: rowno ! number of the row to be evaluated
1127 integer, intent (in) :: nz ! number of nonzeros in this row
1128 real*8, intent (in), dimension(n) :: x ! vector of current solution values
1129 real*8, intent (in out) :: g ! constraint value
1130 real*8, intent (in out), dimension(n) :: jac ! vector of derivatives for current constraint
1131 integer, intent (in), dimension(nz) :: jcnm ! list of variables that appear nonlinearly
1132 ! in this row. Ffor information only.
1133 integer, intent (in) :: mode ! evaluation mode: 1 = function value
1134 ! 2 = derivatives, 3 = both
1135 integer, intent (in) :: ignerr ! if 1 then errors can be ignored as long
1136 ! as errcnt is incremented
1137 integer, intent (in out) :: errcnt ! error counter to be incremented in case
1138 ! of function evaluation errors.
1139 integer, intent (in) :: thread !
1140 Type (bbnode) :: usrmem
1141 Integer :: i, j
1142 real*8 :: sum
1143!
1144! Row 1: The objective function is nonlinear
1145!
1146 if ( rowno .eq. 1 ) then
1147!
1148! Mode = 1 or 3. Function value: G = x * Q * x / 2
1149!
1150 if ( mode .eq. 1 .or. mode .eq. 3 ) then
1151 sum = 0.d0
1152 do i = 1, nn
1153 do j = 1, nn
1154 sum = sum + x(i)*q(i,j)*x(j)
1155 enddo
1156 enddo
1157 g = sum / 2.d0
1158 endif
1159!
1160! Mode = 2 or 3: Derivative values: Q*x
1161!
1162 if ( mode .eq. 2 .or. mode .eq. 3 ) then
1163 do i = 1, nn
1164 sum = 0
1165 do j = 1, nn
1166 sum = sum + q(i,j) * x(j)
1167 enddo
1168 jac(i) = sum
1169 enddo
1170 endif
1171 qp_fdeval = 0
1172 Else
1173!
1174! Other rows are linear and will not be called.
1175!
1176 qp_fdeval = 1
1177 endif
1178 qp_fdeval = 0
1179
1180end Function qp_fdeval
1181
1182
1183!> Computes the second derivative of a constraint in a direction
1184!!
1185!! @include{doc} 2DDir_params.dox
1186Integer Function qp_2ddir( X, DX, D2G, ROWNO, JCNM, NODRV, N, NJ, THREAD, USRMEM )
1187#ifdef dec_directives_win32
1188!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DDir
1189#endif
1190 Use qp_data
1191 Use bb_data
1192 implicit none
1193 INTEGER, Intent(IN) :: rowno, n, nj, thread
1194 INTEGER, Intent(IN OUT) :: nodrv
1195 INTEGER, Dimension(NJ), Intent(IN) :: jcnm
1196 real*8, Dimension(N), Intent(IN) :: x
1197 real*8, Dimension(N), Intent(IN) :: dx
1198 real*8, Dimension(N), Intent(OUT) :: d2g
1199 Type (bbnode) :: usrmem
1200 integer :: i,j
1201 real(8) :: sum
1202!
1203! Is only called for Irow = 1, the nonlinear objective
1204! Return H*Dx = Q*Dx in D2G
1205!
1206 if ( rowno .eq. 1 ) then
1207 do i = 1, nn
1208 sum = 0.d0
1209 do j = 1, nn
1210 sum = sum + q(i,j) * dx(j)
1211 enddo
1212 d2g(i) = sum
1213 enddo
1214 qp_2ddir = 0
1215 else
1216 qp_2ddir = 1
1217 endif
1218
1219End Function qp_2ddir
1220
1221
1222!> Specify the structure of the Lagrangian of the Hessian
1223!!
1224!! @include{doc} 2DLagrStr_params.dox
1225Integer Function qp_2dlagrstr( ROWNO, COLNO, NODRV, N, M, NHESS, USRMEM )
1226#ifdef dec_directives_win32
1227!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DLagrStr
1228#endif
1229 Use qp_data
1230 Use bb_data
1231 implicit none
1232 INTEGER n, m, nhess, nodrv
1233 INTEGER rowno(nhess), colno(nhess)
1234 Type (bbnode) :: usrmem
1235
1236 Integer :: i,j,k
1237
1238 k = 1
1239 Do i = 1, nn
1240 do j = i,nn
1241 rowno(k) = j
1242 colno(k) = i
1243 k = k + 1
1244 Enddo
1245 Enddo
1246 qp_2dlagrstr = 0
1247
1248End function qp_2dlagrstr
1250
1251!> Compute the Lagrangian of the Hessian
1252!!
1253!! @include{doc} 2DLagrVal_params.dox
1254Integer Function qp_2dlagrval( X, U, ROWNO, COLNO, VALUE, NODRV, N, M, NHESS, USRMEM )
1255#ifdef dec_directives_win32
1256!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: QP_2DLagrVal
1257#endif
1258 Use qp_data
1259 Use bb_data
1260 implicit none
1261 INTEGER n, m, nhess, nodrv
1262 real*8 x(n), u(m), value(nhess)
1263 INTEGER rowno(nhess), colno(nhess)
1264 Type (bbnode) :: usrmem
1265
1266 Integer :: i,j,k
1267
1268 k = 1
1269 Do i = 1, nn
1270 do j = i,nn
1271 value(k) = q(i,j)*u(1)
1272 k = k + 1
1273 Enddo
1274 Enddo
1275 qp_2dlagrval = 0
1276
1277End function qp_2dlagrval
1278!
1279! Toutines for Message, Status, Solution, and ErrMsg called
1280! BB_Message, BB_Status, BB_Solution, and BB_ErrMsg.
1281! They are very simple and we avoid written output since overlapping
1282! threads can give unreadable output.
1283!
1284Integer Function bb_status( MODSTA, SOLSTA, ITER, OBJVAL, USRMEM )
1285#ifdef dec_directives_win32
1286!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Status
1287#endif
1288!
1289! Simple implementation in which we just store the status and
1290! objective value in the current node.
1291!
1292 Use bb_data
1293 IMPLICIT NONE
1294 INTEGER, Intent(IN) :: modsta, solsta, iter
1295 real*8, Intent(IN) :: objval
1296 Type (bbnode) :: usrmem
1297
1298 usrmem%Solstat = solsta
1299 usrmem%Modstat = modsta
1300 usrmem%Object = objval
1301 usrmem%Node_Stat = 1
1302
1304 return
1305
1306END Function bb_status
1307
1308Integer Function bb_solution( XVAL, XMAR, XBAS, XSTA, YVAL, YMAR, YBAS, YSTA, N, M, USRMEM )
1309#ifdef dec_directives_win32
1310!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Solution
1311#endif
1312!
1313! Store the solution in the Values field of the solved node.
1314! Also check for integrality. If done here it is inside the
1315! parallel loop.
1316!
1317 Use bb_data
1318 IMPLICIT NONE
1319 INTEGER, Intent(IN) :: n, m
1320 INTEGER, Intent(IN), Dimension(N) :: xbas, xsta
1321 INTEGER, Intent(IN), Dimension(M) :: ybas, ysta
1322 real*8, Intent(IN), Dimension(N) :: xval, xmar
1323 real*8, Intent(IN), Dimension(M) :: yval, ymar
1324 Type (bbnode) :: usrmem
1325
1326 Integer :: numintvar, i, j
1327 Real(8) :: dist
1328
1329 DO i = 1, n
1330 usrmem%Values(i) = xval(i)
1331 ENDDO
1332 bb_solution = 0
1333
1334 numintvar = 0
1335 do i = 1, nn
1336 j = binmap(i)
1337 dist = min( usrmem%values(j), 1.d0-usrmem%values(j) )
1338 if ( dist <= bintol ) numintvar = numintvar + 1
1339 enddo
1340 usrmem%IsInteger = (numintvar == nn)
1341
1342END Function bb_solution
1343
1344Integer Function bb_message( SMSG, DMSG, NMSG, LLEN, USRMEM, MSGV )
1345#ifdef dec_directives_win32
1346!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_Message
1347#endif
1348!
1349! Simple implementation in which does nothing. Messages from different
1350! threads can give a confusing output.
1351!
1352 Use bb_data
1353 Use proginfop
1354 IMPLICIT NONE
1355
1356 INTEGER, Intent(IN) :: smsg, dmsg, nmsg
1357 INTEGER, Intent(IN) , Dimension(*) :: llen
1358 CHARACTER(Len=133), Intent(IN), Dimension(*) :: msgv
1359 Type (bbnode) :: usrmem
1360
1361 Integer :: i, thread, num
1362
1363 if ( debug ) then
1364!
1365! write to document file
1366!
1367 thread = usrmem%Sthread
1368 num = usrmem%Number
1369 do i = 1, dmsg
1370 write(11+thread,"(i4,': ',(A))") num,msgv(i)(1:llen(i))
1371 enddo
1372 endif
1373 bb_message = 0
1374 return
1375
1376END Function bb_message
1377
1378Integer Function bb_errmsg( ROWNO, COLNO, POSNO, MSGLEN, USRMEM, MSG )
1379#ifdef dec_directives_win32
1380!DEC$ ATTRIBUTES STDCALL, REFERENCE, NOMIXED_STR_LEN_ARG :: BB_ErrMsg
1381#endif
1382!
1383! Simple implementation in which does nothing. Messages from different
1384! threads can give a confusing output.
1385!
1386 Use bb_data
1387 IMPLICIT NONE
1388
1389 INTEGER, Intent(IN) :: rowno, colno, posno, msglen
1390 CHARACTER(Len=*), Intent(IN) :: msg
1391 Type (bbnode) :: usrmem
1392 bb_errmsg = 0
1393 return
1394
1395END Function bb_errmsg
integer(c_int) function coidef_message(cntvect, coi_message)
define callback routine for handling messages returned during the solution process.
Definition conopt.f90:1265
integer(c_int) function coidef_solution(cntvect, coi_solution)
define callback routine for returning the final solution values.
Definition conopt.f90:1238
integer(c_int) function coidef_status(cntvect, coi_status)
define callback routine for returning the completion status.
Definition conopt.f90:1212
integer(c_int) function coidef_readmatrix(cntvect, coi_readmatrix)
define callback routine for providing the matrix data to CONOPT.
Definition conopt.f90:1111
integer(c_int) function coidef_errmsg(cntvect, coi_errmsg)
define callback routine for returning error messages for row, column or Jacobian elements.
Definition conopt.f90:1291
integer(c_int) function coidef_fdeval(cntvect, coi_fdeval)
define callback routine for performing function and derivative evaluations.
Definition conopt.f90:1135
integer(c_int) function coidef_2dlagrstr(cntvect, coi_2dlagrstr)
define callback routine for providing the structure of the second derivatives of the Lagrangian.
Definition conopt.f90:1547
integer(c_int) function coidef_option(cntvect, coi_option)
define callback routine for defining runtime options.
Definition conopt.f90:1346
integer(c_int) function coidef_2ddir(cntvect, coi_2ddir)
define callback routine for computing the second derivative for a constraint in a direction.
Definition conopt.f90:1421
integer(c_int) function coidef_usrmem(cntvect, usrmem)
provides a pointer to user memory that is available in all callback functions. NOTE: this is not a ca...
Definition conopt.f90:1601
integer(c_int) function coidef_2dlagrval(cntvect, coi_2dlagrval)
define callback routine for computing the values of the second derivatives of the Lagrangian.
Definition conopt.f90:1573
integer(c_int) function coidef_license(cntvect, licint1, licint2, licint3, licstring)
define the License Information.
Definition conopt.f90:293
integer(c_int) function coidef_numvar(cntvect, numvar)
defines the number of variables in the model.
Definition conopt.f90:97
integer(c_int) function coidef_numcon(cntvect, numcon)
defines the number of constraints in the model.
Definition conopt.f90:121
integer(c_int) function coidef_numnlnz(cntvect, numnlnz)
defines the Number of Nonlinear Nonzeros.
Definition conopt.f90:167
integer(c_int) function coidef_optdir(cntvect, optdir)
defines the Optimization Direction.
Definition conopt.f90:213
integer(c_int) function coidef_numnz(cntvect, numnz)
defines the number of nonzero elements in the Jacobian.
Definition conopt.f90:144
integer(c_int) function coidef_numhess(cntvect, numhess)
defines the Number of Hessian Nonzeros.
Definition conopt.f90:188
integer(c_int) function coidef_objcon(cntvect, objcon)
defines the Objective Constraint.
Definition conopt.f90:239
integer(c_int) function coi_create(cntvect)
initializes CONOPT and creates the control vector.
Definition conopt.f90:1726
integer(c_int) function coi_free(cntvect)
frees the control vector.
Definition conopt.f90:1749
integer(c_int) function coi_solve(cntvect)
method for starting the solving process of CONOPT.
Definition conopt.f90:1625
#define nobs
Definition leastsq.c:15
void defdata()
Defines the data for the problem.
Definition leastsq.c:35
float rndx()
Defines a pseudo random number between 0 and 1.
Definition leastsq.c:22
int select_var(struct BBNode *node)
Definition mp_qpbandb.c:240
void add_activenode(struct BBNode *node)
Definition mp_qpbandb.c:219
void return_freenode(struct BBNode *node)
Definition mp_qpbandb.c:181
void solve_workpool()
Definition mp_qpbandb.c:360
void bandb_solve()
Definition mp_qpbandb.c:502
void add2workpool(struct BBNode *node)
Definition mp_qpbandb.c:232
void create_workpool()
Definition mp_qpbandb.c:266
#define maxmaxpool
Definition mp_qpbandb.c:131
struct BBNode * get_freenode()
Definition mp_qpbandb.c:191
void remove_activenode(struct BBNode *node)
Definition mp_qpbandb.c:168
void list_nodes()
Definition mp_qpbandb.c:153
void list_node(struct BBNode *node)
Definition mp_qpbandb.c:144
integer function bb_message(smsg, dmsg, nmsg, llen, usrmem, msgv)
integer function bb_solution(xval, xmar, xbas, xsta, yval, ymar, ybas, ysta, n, m, usrmem)
program qp_threads
Main program. A simple setup and call of CONOPT.
integer function bb_status(modsta, solsta, iter, objval, usrmem)
integer function bb_option(ncall, rval, ival, lval, usrmem, name)
Sets runtime options.
integer function bb_errmsg(rowno, colno, posno, msglen, usrmem, msg)
#define nj
Definition mp_trans.c:46
type(controlv), dimension(:), pointer cntvect1
logical maxdyn
integer maxthread
subroutine deallocate_nodes
subroutine flog(msg, code)
Definition comdeclp.f90:48
logical debug
Definition comdeclp.f90:23
subroutine startup
Definition comdeclp.f90:31
integer, parameter maxbin
real(8) target
integer, parameter nn
real(8), dimension(nn) mean
integer, parameter nbin
integer, parameter nvar
real(8), dimension(nn, nn) q
integer function qp_readmatrix(lower, curr, upper, vsta, type, rhs, esta, colsta, rowno, value, nlflag, n, m, nz, usrmem)
Define information about the model.
Definition qp1.f90:200
integer function qp_fdeval(x, g, jac, rowno, jcnm, mode, ignerr, errcnt, n, nz, thread, usrmem)
Compute nonlinear terms and non-constant Jacobian elements.
Definition qp1.f90:284
integer function qp_2ddir(x, dx, d2g, rowno, jcnm, nodrv, n, nj, thread, usrmem)
Computes the second derivative of a constraint in a direction.
Definition qp2.f90:285
integer function qp_2dlagrval(x, u, rowno, colno, value, nodrv, n, m, nhess, usrmem)
Compute the Lagrangian of the Hessian.
Definition qp3.f90:298
integer function qp_2dlagrstr(rowno, colno, nodrv, n, m, nhess, usrmem)
Specify the structure of the Lagrangian of the Hessian.
Definition qp3.f90:278