CompositeFunction.cpp 22.7 KB
Newer Older
1
2
3
4
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
5
6
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
7
#include "MantidAPI/IConstraint.h"
8

9
#include <boost/lexical_cast.hpp>
10
11
12
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
13
#include <algorithm>
14
15
16
17
18
19

namespace Mantid
{
namespace API
{

Peterson, Peter's avatar
Peterson, Peter committed
20
21
using std::size_t;

22
//DECLARE_FUNCTION(CompositeFunction)
23

24
25
/// Copy contructor
CompositeFunction::CompositeFunction(const CompositeFunction& f)
26
:m_nActive(f.m_nParams),m_nParams(f.m_nParams),m_iConstraintFunction(0)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
}

///Assignment operator
CompositeFunction& CompositeFunction::operator=(const CompositeFunction& f)
{
  m_nActive = f.m_nActive;
  m_nParams = f.m_nParams;
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
41
  m_iConstraintFunction = f.m_iConstraintFunction;
42
43
44
45
46
47
  return *this;
}

///Destructor
CompositeFunction::~CompositeFunction()
{
Peterson, Peter's avatar
Peterson, Peter committed
48
  for(size_t i=0;i<nFunctions();i++)
49
50
51
52
53
54
55
56
57
    if (m_functions[i]) delete m_functions[i];
}


/// Function initialization. Declare function parameters in this method.
void CompositeFunction::init()
{
}

58
59
60
61
62
63
64
65
66
67
68
/** 
 * Writes itself into a string. Functions derived from CompositeFunction must
 * override this method with something like this:
 *   std::string NewFunction::asString()const
 *   {
 *      ostr << "composite=" << this->name() << ';';
 *      // write NewFunction's own attributes and parameters
 *      ostr << CompositeFunction::asString();
 *      // write NewFunction's own ties and constraints
 *      // ostr << ";constraints=(" << ... <<")";
 *   }
69
 * @return the string representation of the composite function
70
 */
71
72
73
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
74
75
76
77
  if (name() != "CompositeFunctionMW")
  {
    ostr << "composite=" <<name() << ";";
  }
Peterson, Peter's avatar
Peterson, Peter committed
78
  for(size_t i=0;i<nFunctions();i++)
79
  {
80
    IFunction* fun = getFunction(i);
81
82
    bool isComp = dynamic_cast<CompositeFunction*>(fun) != 0;
    if (isComp) ostr << '(';
83
    ostr << fun->asString();
84
    if (isComp) ostr << ')';
85
86
87
88
89
90
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
91
  for(size_t i=0;i<nParams();i++)
92
93
94
95
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
96
      IFunction* fun = getFunction(functionIndex(i));
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      std::string tmp = tie->asString(fun);
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
115
116
117
118
  }
  return ostr.str();
}

119
/** Sets a new value to the i-th parameter.
120
121
122
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
123
 */
124
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
125
{
126
  size_t iFun = functionIndex(i);
127
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
128
129
}

130
131
132
133
134
135
/** Sets a new description to the i-th parameter.
 *  @param i :: The parameter index
 *  @param description :: The new description
 */
void CompositeFunction::setParameterDescription(size_t i, const std::string& description)
{
136
  size_t iFun = functionIndex(i);
137
138
139
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

140
/** Get the i-th parameter.
141
 *  @param i :: The parameter index
142
 *  @return value of the requested parameter
143
 */
144
double CompositeFunction::getParameter(size_t i)const
145
{
Peterson, Peter's avatar
Peterson, Peter committed
146
  size_t iFun = functionIndex(i);
147
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
148
149
}

150
151
/**
 * Sets a new value to a parameter by name.
152
153
154
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
155
156
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
157
{
158
  std::string pname;
159
  size_t index;
160
  parseName(name,index,pname);
161
  getFunction(index)->setParameter(pname,value,explicitlySet);
162
163
}

164
165
166
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
167
 * @param description :: The new description
168
169
170
171
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
172
  size_t index;
173
  parseName(name,index,pname);
174
  getFunction(index)->setParameterDescription(pname,description);
175
176
}

177
178
/**
 * Parameters by name.
179
 * @param name :: The name of the parameter.
180
 * @return value of the requested named parameter
181
 */
182
183
double CompositeFunction::getParameter(const std::string& name)const
{
184
  std::string pname;
185
  size_t index;
186
  parseName(name,index,pname);
187
  return getFunction(index)->getParameter(pname);
188
189
190
}

/// Total number of parameters
191
size_t CompositeFunction::nParams()const
192
193
194
195
{
  return m_nParams;
}

196
/**
197
 * 
198
 * @param name :: The name of a parameter
199
 * @return index of the requested named parameter
200
 */
201
size_t CompositeFunction::parameterIndex(const std::string& name)const
202
{
203
  std::string pname;
204
  size_t index;
205
  parseName(name,index,pname);
206
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
207
208
}

Nick Draper's avatar
re #100    
Nick Draper committed
209
/// Returns the name of parameter
210
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
211
/// @return The name of the parameter
212
std::string CompositeFunction::parameterName(size_t i)const
213
{
214
  size_t iFun = functionIndex(i);
215
216
217
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
218
219
}

220
221
222
223
224
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
225
  size_t iFun = functionIndex(i);
226
227
228
229
230
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

231
/// Number of active (in terms of fitting) parameters
232
size_t CompositeFunction::nActive()const
233
234
235
236
237
{
  return m_nActive;
}

/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
238
double CompositeFunction::activeParameter(size_t i)const
239
{
240
  size_t iFun = functionIndexActive(i);
241
242
243
244
  return m_functions[ iFun ]->activeParameter(i - m_activeOffsets[iFun]);
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
245
void CompositeFunction::setActiveParameter(size_t i, double value)
246
{
247
  size_t iFun = functionIndexActive(i);
248
  m_functions[ iFun ]->setActiveParameter(i - m_activeOffsets[iFun],value);
249
250
251
252
253
}

/// Update parameters after a fitting iteration
void CompositeFunction::updateActive(const double* in)
{
254
  for(size_t iFun = 0; iFun < m_functions.size(); iFun++)
255
256
257
  {
    m_functions[ iFun ]->updateActive(in + m_activeOffsets[ iFun ]);
  }
258
  applyTies();
259
260
261
}

/// Returns "global" index of active parameter i
262
size_t CompositeFunction::indexOfActive(size_t i)const
263
{
264
  size_t iFun = functionIndexActive(i);
265
266
267
268
  return m_paramOffsets[ iFun ] + m_functions[ iFun ]->indexOfActive(i - m_activeOffsets[iFun]);
}

/// Returns the name of active parameter i
269
std::string CompositeFunction::nameOfActive(size_t i)const
270
{
271
  size_t iFun = functionIndexActive(i);
272
273
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_activeOffsets[iFun]);
274
275
276
277
278
279
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
280
  size_t iFun = functionIndexActive(i);
281
282
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_activeOffsets[iFun]);
283
  return ostr.str();
284
285
}

286
/**
287
 * query to see in the function is active
288
 * @param i :: The index of a declared parameter
289
 * @return true if parameter i is active
290
 */
291
bool CompositeFunction::isActive(size_t i)const
292
{
293
  size_t iFun = functionIndex(i);
294
295
296
297
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

/**
298
 * @param i :: A declared parameter index to be removed from active
299
 */
300
void CompositeFunction::removeActive(size_t i)
301
{
302
  if (!isActive(i)) return;
303
304
  size_t iFun = functionIndex(i);
  size_t ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
305
  m_IFunctionActive.erase(m_IFunctionActive.begin()+ia);
306
307
  m_functions[ iFun ]->removeActive(i - m_paramOffsets[iFun]);

308
  m_nActive--;
Peterson, Peter's avatar
Peterson, Peter committed
309
  for(size_t j=iFun+1;j<nFunctions();j++)
310
311
312
    m_activeOffsets[j] -= 1;
}

313
/** Makes a parameter active again. It doesn't change the parameter's tie.
314
 * @param i :: A declared parameter index to be restored to active
315
 */
316
void CompositeFunction::restoreActive(size_t i)
317
{
318
319
  size_t iFun = functionIndex(i);
  size_t ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
320

321
  std::vector<size_t>::iterator itFun = 
322
    std::find_if(m_IFunctionActive.begin(),m_IFunctionActive.end(),std::bind2nd(std::greater<size_t>(),i));
323

324
  m_IFunctionActive.insert(itFun,1,ia);
325
326
327
  m_functions[ iFun ]->restoreActive(i - m_paramOffsets[iFun]);

  m_nActive++;
Peterson, Peter's avatar
Peterson, Peter committed
328
  for(size_t j=iFun+1;j<nFunctions();j++)
329
330
331
    m_activeOffsets[j] += 1;
}

332
/**
333
 * @param i :: The index of a declared parameter
334
 * @return The index of declared parameter i in the list of active parameters
335
336
 *         if the parameter is tied.
 */
337
size_t CompositeFunction::activeIndex(size_t i)const
338
{
339
340
  size_t iFun = functionIndex(i);
  size_t j = m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
341
  return m_activeOffsets[iFun] + j;
342
343
}

344
345
346
347
348
349
350
351
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_nActive = 0;
  m_paramOffsets.clear();
  m_activeOffsets.clear();
352
353
  m_IFunction.clear();
  m_IFunctionActive.clear();
354

355
  std::vector<IFunction*> functions(m_functions.begin(),m_functions.end());
356
357
  m_functions.clear();

358
  for(std::vector<IFunction*>::size_type i=0;i<functions.size();i++)
359
  {
360
    IFunction* f = functions[i];
361
362
    CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f);
    if (cf) cf->checkFunction();
363
364
365
366
    addFunction(f);
  }
}

367
/** Add a function
368
 * @param f :: A pointer to the added function
369
 * @return The function index
370
 */
371
size_t CompositeFunction::addFunction(IFunction* f)
372
{
373
374
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
  m_IFunctionActive.insert(m_IFunctionActive.end(),f->nActive(),m_functions.size());
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  m_functions.push_back(f);
  //?f->init();
  if (m_paramOffsets.size() == 0)
  {
    m_paramOffsets.push_back(0);
    m_activeOffsets.push_back(0);
    m_nParams = f->nParams();
    m_nActive = f->nActive();
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
    m_activeOffsets.push_back(m_nActive);
    m_nParams += f->nParams();
    m_nActive += f->nActive();
  }
391
  return m_functions.size() - 1;
392
393
}

394
/** Remove a function
395
396
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
397
 */
398
void CompositeFunction::removeFunction(size_t i, bool del)
399
{
400
  if ( i >= nFunctions() )
401
402
    throw std::out_of_range("Function index out of range.");

403
  IFunction* fun = getFunction(i);
404

405
406
  size_t dna = fun->nActive();
  size_t dnp = fun->nParams();
407

408
  for(size_t j=0;j<nParams();)
409
410
  {
    ParameterTie* tie = getTie(j);
411
    if (tie && tie->findParametersOf(fun))
412
413
414
415
416
417
418
419
420
421
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

  // Shift down the function indeces for parameters
422
  for(std::vector<size_t>::iterator it=m_IFunction.begin();it!=m_IFunction.end();)
423
  {
424

425
426
    if (*it == i)
    {
427
      it = m_IFunction.erase(it);
428
    }
429
    else
430
    {
431
432
433
434
      if (*it > i)
      {
        *it -= 1;
      }
435
      ++it;
436
437
438
439
    }
  }

  // Shift down the function indeces for active parameters
440
  for(std::vector<size_t>::iterator it=m_IFunctionActive.begin();it!=m_IFunctionActive.end();)
441
442
443
  {
    if (*it == i)
    {
444
      it = m_IFunctionActive.erase(it);
445
    }
446
    else
447
    {
448
449
450
451
      if (*it > i)
      {
        *it -= 1;
      }
452
      ++it;
453
454
455
456
457
    }
  }

  m_nActive -= dna;
  // Shift the active offsets down by the number of i-th function's active params
458
  for(size_t j=i+1;j<nFunctions();j++)
459
460
461
462
463
464
465
  {
    m_activeOffsets[j] -= dna;
  }
  m_activeOffsets.erase(m_activeOffsets.begin()+i);

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
466
  for(size_t j=i+1;j<nFunctions();j++)
467
468
469
470
471
472
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
473
474
475
476
  if (del)
  {
    delete fun;
  }
477
478
}

479
/** Replace a function with a new one. The old function is deleted.
480
 *  The new function must have already its workspace set.
481
 * @param f_old :: The pointer to the function to replace. If it's not
482
 *  a member of this composite function nothing happens
483
 * @param f_new :: A pointer to the new function
484
 */
485
void CompositeFunction::replaceFunctionPtr(const IFunction* f_old,IFunction* f_new)
486
{
487
  std::vector<IFunction*>::const_iterator it = 
488
489
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
490
  std::vector<IFunction*>::difference_type iFun = it - m_functions.begin();
491
  replaceFunction(iFun,f_new);
492
493
}

494
/** Replace a function with a new one. The old function is deleted.
495
496
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
497
 */
498
void CompositeFunction::replaceFunction(size_t i,IFunction* f)
499
{
500
  if ( i >= nFunctions() )
501
502
    throw std::out_of_range("Function index out of range.");

503
  IFunction* fun = getFunction(i);
504
505
  size_t na_old = fun->nActive();
  size_t np_old = fun->nParams();
506

507
508
  size_t na_new = f->nActive();
  size_t np_new = f->nParams();
509
510
511

  // Modify function indeces: The new function may have different number of parameters
  {
512
513
    std::vector<size_t>::iterator itFun = std::find(m_IFunction.begin(),m_IFunction.end(),i);
    if(itFun != m_IFunction.end()) // functions must have at least 1 parameter
514
    {
515
516
      if (np_old > np_new)
      {
517
        m_IFunction.erase(itFun,itFun + np_old - np_new);
518
519
520
      }
      else if (np_old < np_new) 
      {
521
        m_IFunction.insert(itFun,np_new - np_old,i);
522
      }
523
    }
524
525
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
526
527
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
528
    }
529
530
531
532
  }

  // Modify function indeces: The new function may have different number of active parameters
  {
533
534
    std::vector<size_t>::iterator itFun = std::find(m_IFunctionActive.begin(),m_IFunctionActive.end(),i);
    if (itFun != m_IFunctionActive.end())
535
536
537
    {
      if (na_old > na_new)
      {
538
        m_IFunctionActive.erase(itFun,itFun + na_old - na_new);
539
540
541
      }
      else if (na_old < na_new) 
      {
542
        m_IFunctionActive.insert(itFun,na_new - na_old,i);
543
544
545
546
      }
    }
    else if (na_new > 0)
    {
547
548
      itFun = std::find_if(m_IFunctionActive.begin(),m_IFunctionActive.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunctionActive.insert(itFun,na_new,i);
549
550
551
    }
  }

552
  size_t dna = na_new - na_old;
553
554
  m_nActive += dna;
  // Recalc the active offsets 
555
  for(size_t j=i+1;j<nFunctions();j++)
556
557
558
559
  {
    m_activeOffsets[j] += dna;
  }

560
  size_t dnp = np_new - np_old;
561
562
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
563
  for(size_t j=i+1;j<nFunctions();j++)
564
565
566
567
568
569
570
571
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
  delete fun;
}

572
/**
573
 * @param i :: The index of the function
574
 * @return function at the requested index
575
 */
576
IFunction* CompositeFunction::getFunction(std::size_t i)const
577
{
Peterson, Peter's avatar
Peterson, Peter committed
578
  if ( i >= nFunctions() )
579
  {
580
    throw std::out_of_range("Function index out of range.");
581
  }
582
583
584
  return m_functions[i];
}

585
586
/**
 * Get the index of the function to which parameter i belongs
587
 * @param i :: The parameter index
588
 * @return function index of the requested parameter
589
 */
590
size_t CompositeFunction::functionIndex(std::size_t i)const
591
{
592
  if( i >= nParams() )
593
  {
594
    throw std::out_of_range("Function parameter index out of range.");
595
  }
596
  return m_IFunction[i];
597
598
599
600
}

/**
 * Get the index of the function to which parameter i belongs
601
 * @param i :: The active parameter index
602
 * @return active function index of the requested parameter
603
 */
604
size_t CompositeFunction::functionIndexActive(std::size_t i)const
605
{
606
  if( i >= nParams() )
607
    throw std::out_of_range("Function parameter index out of range.");
608
  return m_IFunctionActive[i];
609
610
611
}

/**
612
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
613
* @param index :: Receives function index or throws std::invalid_argument
614
* @param name :: Receives the parameter name
615
*/
616
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
617
{
618
619
620
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
621
    throw std::invalid_argument("Parameter " + varName + " not found.");
622
623
624
625
626
627
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

628
    std::string sindex = varName.substr(1,i - 1);
629
630
631
632
633
634
635
    index = boost::lexical_cast<int>(sindex);

    if (i == varName.size() - 1)
      throw std::invalid_argument("Name cannot be empty");

    name = varName.substr(i+1);
  }
636
637
}

638
/** Returns the index of parameter i as it declared in its function
639
 * @param i :: The parameter index
640
641
 * @return The local index of the parameter
 */
642
size_t CompositeFunction::parameterLocalIndex(size_t i)const
643
{
644
  size_t iFun = functionIndex(i);
645
646
647
  return i - m_paramOffsets[iFun];
}

648
/** Returns the name of parameter i as it declared in its function
649
 * @param i :: The parameter index
650
651
 * @return The pure parameter name (without the function identifier f#.)
 */
652
std::string CompositeFunction::parameterLocalName(size_t i)const
653
{
654
  size_t iFun = functionIndex(i);
655
656
657
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

658
/**
659
 * Apply the ties.
660
661
662
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
663
  for(size_t i=0;i<nFunctions();i++)
664
665
666
667
668
669
670
671
672
673
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
674
  for(size_t i=0;i<nFunctions();i++)
675
676
677
678
679
680
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
681
 * @param i :: The index of the tied parameter.
682
683
 * @return True if successfull
 */
684
bool CompositeFunction::removeTie(size_t i)
685
{
686
  size_t iFun = functionIndex(i);
687
688
689
690
691
692
693
694
695
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  if (res)
  {
    m_nActive++;
  }
  return res;
}

/** Get the tie of i-th parameter
696
 * @param i :: The parameter index
697
 * @return A pointer to the tie.
698
 */
699
ParameterTie* CompositeFunction::getTie(size_t i)const
700
{
701
  size_t iFun = functionIndex(i);
702
703
704
705
706
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
707
 * @param tie :: A pointer to a new tie
708
709
710
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
711
712
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
713
714
715
716
717
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
718
719
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
720
 * @param description :: Parameter documentation
721
 */
722
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
723
{
724
725
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
726
  (void) description; //Avoid compiler warning
727
728
729
730
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
731
 *  @param ic :: Pointer to a constraint.
732
733
734
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
735
736
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
737
  getFunction(iFun)->addConstraint(ic);
738
739
}

740
741
void CompositeFunction::setParametersToSatisfyConstraints()
{
Peterson, Peter's avatar
Peterson, Peter committed
742
  for(size_t i=0;i<nFunctions();i++)
743
744
745
746
747
  {
    getFunction(i)->setParametersToSatisfyConstraints();
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
748
/// Get constraint
749
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
750
/// @return A pointer to the constraint
751
IConstraint* CompositeFunction::getConstraint(size_t i)const
752
{
753
  size_t iFun = functionIndex(i);
754
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
755
756
}

757
/** Remove a constraint
758
 * @param parName :: The name of a parameter which constarint to remove.
759
760
761
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
762
763
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
764
765
766
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

767
/** Checks if a constraint has been explicitly set
768
 *  @param i :: The parameter index
769
 *  @return true if the function is explicitly set
770
 */
771
bool CompositeFunction::isExplicitlySet(size_t i)const
772
{
773
  size_t iFun = functionIndex(i);
774
775
776
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

777
/**
778
 * Returns the index of parameter if the ref points to one of the member function
779
 * @param ref :: A reference to a parameter
780
 * @return Parameter index or number of nParams() if parameter not found
781
 */
782
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
783
{
784
  if (ref.getFunction() == this && ref.getIndex() < nParams())
785
  {
786
    return ref.getIndex();
787
  }
Peterson, Peter's avatar
Peterson, Peter committed
788
  for(size_t iFun=0;iFun<nFunctions();iFun++)
789
  {
790
    IFunction* fun = getFunction(iFun);
791
792
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
793
794
795
796
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
797
  return nParams();
798
799
}

800
/**
801
 * @param ref :: The reference
802
803
 * @return A function containing parameter pointed to by ref
 */
804
IFunction* CompositeFunction::getContainingFunction(const ParameterReference& ref)const
805
{
806
  if (ref.getFunction() == this && ref.getIndex() < nParams())
807
808
809
  {
    return ref.getFunction();
  }
Peterson, Peter's avatar
Peterson, Peter committed
810
  for(size_t iFun=0;iFun<nFunctions();iFun++)
811
  {
812
    IFunction* fun = getFunction(iFun)->getContainingFunction(ref);
813
814
815
816
817
818
819
    if (fun)
    {
      return getFunction(iFun);
    }
  }
  return NULL;
}
820

821
/**
822
 * @param fun :: The searched function
823
824
 * @return A function containing the argument function fun
 */
825
IFunction* CompositeFunction::getContainingFunction(const IFunction* fun)
826
827
828
829
830
{
  if (fun == this)
  {
    return this;
  }
Peterson, Peter's avatar
Peterson, Peter committed
831
  for(size_t iFun=0;iFun<nFunctions();iFun++)
832
  {
833
    IFunction* f = getFunction(iFun)->getContainingFunction(fun);
834
835
836
837
838
839
840
841
    if (f)
    {
      return getFunction(iFun);
    }
  }