📄 rmd_node__define.pro
字号:
;+
; NAME:
;
; RMD_NODE__DEFINE
;
; PURPOSE:
;
; Class definition for a tree node. It inherits from an
; IDL_CONTAINER class and can contain other nodes. Instance
; data includes parameters, parameter ranges, an ID specified
; externally.
;
; This class definition was written primarily for application
; to minimization. A UI wrapper was written for it called
; TREE_MIN_UI that provides an interface for minimization of
; a function of a single variable. The implementation is
; a global minimization search strategy and provides an
; example use of this class.
;
; AUTHOR:
;
; Robert Dimeo
; NIST Center for Neutron Research
; National Institute of Standards and Technology
; 100 Bureau Drive-Stop 8562
; Gaithersburg, MD 20899
;
; CATEGORY:
;
; OPTIMIZATION
;
; CALLING SEQUENCE:
;
; IDL> o = OBJ_NEW("RMD_NODE", PRANGE = [-5.0,5.0], $
; LEVEL = 1, $
; FUNC = 'MY_MIN_FUNC', $
; DECAY_WIDTH = 3.0, $
; INCREMENT_VALUE = 10, $
; _EXTRA = extra )
;
; The requirements on the function, in this case "MY_MIN_FUNC" are
; that it be written as a FUNCTION, it accepts the parameters with
; which the minimization is performed with respect to, and it accepts
; keyword parameters via EXTRA keyword inheritance. Therefore the
; function might be written as follows:
;
; FUNCTION MY_MIN_FUNC,x,_EXTRA = extra
; y = cos(3.0*x)
; RETURN,y
; END
;
; EXAMPLE USAGE:
;
; A simple example of using this class for minimizing a function
; of a single variable is shown at the end of this code listing
; and it is called TEST_NODE_MIN. A more in-depth example is
; shown in the program named TREE_MIN_UI which is much more
; interactive and illustrates how the tree evolves with each
; successive iteration.
;
; REQUIREMENTS:
;
; IDL 6.0 and higher
;
; REQUIRED PROGRAMS:
;
; NONE
;
; COMMON BLOCKS:
;
; NONE
;
; MODIFICATION HISTORY:
;
; RMD -- Wrote 10/22/04
;
;-
; ************************************ ;
pro rmd_node::cleanup
ptr_free,self.prange_ptr,self.pextra
self->idl_container::cleanup
end
; ************************************ ;
function find_rmd_node_by_id,oref,id_to_match
; This is a recursive function that returns an object
; reference if there is a node object in the object
; hierarchy that matches the id_to_match.
;
; Note that this function is not used anywhere within this
; code but it might be useful in applications
; that use this class.(?)
if n_params() ne 2 then return,0
oref->get_property,id = id
if (id eq id_to_match) then return,oref
nchildren = oref->count()
if nchildren eq 0 then return,0
child = oref->get(/all)
for i = 0,nchildren-1 do begin
result = find_rmd_node_by_id(child[i],id_to_match)
if obj_valid(result) then return,result
endfor
return,0
end
; ************************************ ;
function rmd_node::terminated
return,(self->count()) eq 0
end
; ************************************ ;
pro rmd_node::get_property, parms = parms, $
prange = prange, $
id = id, $
visits = visits, $
nsubdiv = nsubdiv, $
level = level, $
node_value = node_value, $
func = func, $
parent_node = parent_node, $
branch_value = branch_value, $
increment_value = increment_value
increment_value = self.increment_value
if arg_present(parent_node) then parent_node = self.parent_node
if arg_present(parms) then begin
; Get the ranges out
prange = *self.prange_ptr
parms = prange[0,*]+0.5*(prange[1,*]-prange[0,*])
endif
if arg_present(prange) then prange = *self.prange_ptr
func = self.func
visits = self.visits
nsubdiv = self.nsubdiv
id = self.id
level = self.level
node_value = self.node_value
branch_value = self.branch_value
end
; ************************************ ;
function rmd_node::increment_branch_value
self.branch_value = self.branch_value + self.increment_value
return,1
end
; ************************************ ;
function rmd_node::decrement_branch_value
; The "probability decay" implementation
branch_value = self.branch_value - 1
arg = float(self.visits)/self.decay_width
self.branch_value = 1L+long(branch_value*exp(-0.5*arg^2))
return,1
end
; ************************************ ;
function rmd_node::get_new_ranges
; This finds the new ranges based on the current
; parameter ranges.
self->get_property,nsubdiv = nsubdiv,prange = prange
s = size(prange)
if s[0] eq 1 then np = 1 else np = s[2]
new_ranges = fltarr(2,np,nsubdiv)
count = 0L
for i = 0,np-1 do begin
delta = prange[1,i] - prange[0,i] ; This is the spread
; for a particular parameter
; We subdivide this range into NSUBDIV
; ranges and create the new ranges
new_delta = delta/nsubdiv
for j = 0,nsubdiv-1 do begin
pplo = prange[0,i]+j*new_delta
pphi = prange[0,i]+(j+1)*new_delta
new_ranges[*,i,j] = [pplo,pphi]
count++
endfor
endfor
; Now we have to find all possible combinations of
; pairing up ranges of each parameter. Note that
; currently this only works properly when this is a
; binary tree.
count = 0L
ntotal = nsubdiv^np
index_arr = intarr(np,nsubdiv^np)
bit=bytarr(np)
for i=0,2^np-1 do begin
result=i
for k=0,np-1 do begin
valby2=result/2
bit[k]=result-valby2*2
result=valby2
endfor
index_arr[*,i] = fix(bit)
endfor
index_arr = index_arr+1
match_arr = (1+indgen(np)) # (replicate(1,nsubdiv^np))
output_range = fltarr(2,np,nsubdiv^np)
for i = 0,2^np-1 do begin
for j = 0,np-1 do begin
xi = match_arr[j,i]-1
yi = index_arr[j,i]-1
output_range[*,j,i] = new_ranges[*,xi,yi]
endfor
endfor
return,output_range
end
; ************************************ ;
function rmd_node::add_nodes,next_index
if n_params() eq 0 then next_index = 1
index = strtrim(string(next_index),2)
; Add new nodes one level deeper
new_level = self.level + 1L
new_ranges = self->get_new_ranges()
new_best = 0B
n_ranges = (size(new_ranges))[3]
for i = 0,n_ranges - 1 do begin
index = strtrim(string(next_index),2)
id = strtrim(string(new_level),2)+'-'+index
onew = obj_new('rmd_node',id, prange = new_ranges[*,*,i], $
level = new_level, $
parent_node = self, $
func = self.func, $
decay_width = self.decay_width, $
increment_value = self.increment_value, $
_Extra = *self.pextra )
self->add,onew
next_index++
endfor
return,1
end
; ************************************ ;
function rmd_node::add_visit
self.visits = self.visits + 1L
return,1
end
; ************************************ ;
function rmd_node::evaluate_function
self->get_property,parms = parms
self.node_value = call_function(self.func,transpose(parms),_Extra = *self.pextra)
return,1
end
; ************************************ ;
function rmd_node::go_to_the_top, increase = increase,decrease = decrease
self->get_property,parent_node = parent
if keyword_set(increase) then ret = self->increment_branch_value()
if ~obj_valid(parent) then return,0
while obj_valid(parent) do begin
; Increment the parent's branch value
parent->get_property,id = id,branch_value = branch_value
if keyword_set(increase) then ret = parent->increment_branch_value()
if keyword_set(decrease) then ret = parent->decrement_branch_value()
parent->get_property,parent_node = next_parent_up
parent = next_parent_up
endwhile
return,1
end
; ************************************ ;
pro rmd_node::set_property, prange = prange, $
level = level, $
func = func, $
node_value = node_value
if n_elements(node_value) ne 0 then self.node_value = node_value
if n_elements(func) ne 0 then self.func = func
if n_elements(level) ne 0 then self.level = level
if n_elements(prange) ne 0 then *self.prange_ptr = prange
if n_elements(nsubdiv) ne 0 then self.nsubdiv = nsubdiv
end
; ************************************ ;
function rmd_node::init, id, $
prange = prange, $
level = level, $
parent_node = parent_node, $
increment_value = increment_value, $
func = func, $
decay_width = decay_width, $
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -