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
#include "MantidAPI/FunctionFactory.h"
9

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

namespace Mantid
{
namespace API
{

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

23
DECLARE_FUNCTION(CompositeFunction)
24

25
26
/// Copy contructor
CompositeFunction::CompositeFunction(const CompositeFunction& f)
27
:m_nActive(f.m_nParams),m_nParams(f.m_nParams),m_iConstraintFunction(0)
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
  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());
42
  m_iConstraintFunction = f.m_iConstraintFunction;
43
44
45
46
47
48
  return *this;
}

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


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

59
60
61
62
63
64
65
66
67
68
69
/** 
 * 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=(" << ... <<")";
 *   }
70
 * @return the string representation of the composite function
71
 */
72
73
74
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
75
76
77
78
  if (name() != "CompositeFunctionMW")
  {
    ostr << "composite=" <<name() << ";";
  }
Peterson, Peter's avatar
Peterson, Peter committed
79
  for(size_t i=0;i<nFunctions();i++)
80
  {
81
    IFunction* fun = getFunction(i);
82
83
    bool isComp = dynamic_cast<CompositeFunction*>(fun) != 0;
    if (isComp) ostr << '(';
84
    ostr << fun->asString();
85
    if (isComp) ostr << ')';
86
87
88
89
90
91
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
92
  for(size_t i=0;i<nParams();i++)
93
94
95
96
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
97
      IFunction* fun = getFunction(functionIndex(i));
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
      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 << ")";
116
117
118
119
  }
  return ostr.str();
}

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/** Function you want to fit to. 
 *  @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    domain.reset();
    m_functions[ iFun ]->function(domain,tmp);
    values += tmp;
  }
}

/**
 * Derivatives of function with respect to active parameters
 * @param domain :: Function domain to get the arguments from.
 * @param jacobian :: A Jacobian to store the derivatives.
 */
void CompositeFunction::functionDeriv(const FunctionDomain& domain, Jacobian& jacobian)
{
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    domain.reset();
    PartialJacobian J(&jacobian,paramOffset(iFun),activeOffset(iFun));
    getFunction(iFun)->functionDeriv(domain,J);
  }
}

149
/** Sets a new value to the i-th parameter.
150
151
152
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
153
 */
154
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
155
{
156
  size_t iFun = functionIndex(i);
157
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
158
159
}

160
161
162
163
164
165
/** 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)
{
166
  size_t iFun = functionIndex(i);
167
168
169
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

170
/** Get the i-th parameter.
171
 *  @param i :: The parameter index
172
 *  @return value of the requested parameter
173
 */
174
double CompositeFunction::getParameter(size_t i)const
175
{
Peterson, Peter's avatar
Peterson, Peter committed
176
  size_t iFun = functionIndex(i);
177
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
178
179
}

180
181
/**
 * Sets a new value to a parameter by name.
182
183
184
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
185
186
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
187
{
188
  std::string pname;
189
  size_t index;
190
  parseName(name,index,pname);
191
  getFunction(index)->setParameter(pname,value,explicitlySet);
192
193
}

194
195
196
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
197
 * @param description :: The new description
198
199
200
201
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
202
  size_t index;
203
  parseName(name,index,pname);
204
  getFunction(index)->setParameterDescription(pname,description);
205
206
}

207
208
/**
 * Parameters by name.
209
 * @param name :: The name of the parameter.
210
 * @return value of the requested named parameter
211
 */
212
213
double CompositeFunction::getParameter(const std::string& name)const
{
214
  std::string pname;
215
  size_t index;
216
  parseName(name,index,pname);
217
  return getFunction(index)->getParameter(pname);
218
219
220
}

/// Total number of parameters
221
size_t CompositeFunction::nParams()const
222
223
224
225
{
  return m_nParams;
}

226
/**
227
 * 
228
 * @param name :: The name of a parameter
229
 * @return index of the requested named parameter
230
 */
231
size_t CompositeFunction::parameterIndex(const std::string& name)const
232
{
233
  std::string pname;
234
  size_t index;
235
  parseName(name,index,pname);
236
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
237
238
}

Nick Draper's avatar
re #100    
Nick Draper committed
239
/// Returns the name of parameter
240
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
241
/// @return The name of the parameter
242
std::string CompositeFunction::parameterName(size_t i)const
243
{
244
  size_t iFun = functionIndex(i);
245
246
247
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
248
249
}

250
251
252
253
254
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
255
  size_t iFun = functionIndex(i);
256
257
258
259
260
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

261
/// Number of active (in terms of fitting) parameters
262
size_t CompositeFunction::nActive()const
263
264
265
266
267
{
  return m_nActive;
}

/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
268
double CompositeFunction::activeParameter(size_t i)const
269
{
270
  size_t iFun = functionIndexActive(i);
271
272
273
274
  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
275
void CompositeFunction::setActiveParameter(size_t i, double value)
276
{
277
  size_t iFun = functionIndexActive(i);
278
  m_functions[ iFun ]->setActiveParameter(i - m_activeOffsets[iFun],value);
279
280
281
}

/// Returns the name of active parameter i
282
std::string CompositeFunction::nameOfActive(size_t i)const
283
{
284
  size_t iFun = functionIndexActive(i);
285
286
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_activeOffsets[iFun]);
287
288
289
290
291
292
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
293
  size_t iFun = functionIndexActive(i);
294
295
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_activeOffsets[iFun]);
296
  return ostr.str();
297
298
}

299
/**
300
 * query to see in the function is active
301
 * @param i :: The index of a declared parameter
302
 * @return true if parameter i is active
303
 */
304
bool CompositeFunction::isFixed(size_t i)const
305
{
306
  size_t iFun = functionIndex(i);
307
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
308
309
310
}

/**
311
 * @param i :: A declared parameter index to be removed from active
312
 */
313
void CompositeFunction::fix(size_t i)
314
{
315
  if (isFixed(i)) return;
316
  size_t iFun = functionIndex(i);
317
318
319
320
321
322
323
324
  std::vector<size_t>::iterator ia = std::find(m_IFunctionActive.begin(),m_IFunctionActive.end(),iFun);
  if (ia == m_IFunctionActive.end())
  {// isFixed(i) should have returned true
    throw std::runtime_error("Inconsistency in CompositeFunction when fixing parameter "+
      boost::lexical_cast<std::string>(i));
  }
  m_IFunctionActive.erase(ia);
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
325

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

331
/** Makes a parameter active again. It doesn't change the parameter's tie.
332
 * @param i :: A declared parameter index to be restored to active
333
 */
334
void CompositeFunction::unfix(size_t i)
335
{
336
  if (!isFixed(i)) return;
337
  size_t iFun = functionIndex(i);
338

339
340
  m_IFunctionActive.insert(m_IFunctionActive.begin() + m_activeOffsets[iFun],iFun);
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
341
342

  m_nActive++;
Peterson, Peter's avatar
Peterson, Peter committed
343
  for(size_t j=iFun+1;j<nFunctions();j++)
344
345
346
    m_activeOffsets[j] += 1;
}

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

358
  std::vector<IFunction*> functions(m_functions.begin(),m_functions.end());
359
360
  m_functions.clear();

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

370
/** Add a function
371
 * @param f :: A pointer to the added function
372
 * @return The function index
373
 */
374
size_t CompositeFunction::addFunction(IFunction* f)
375
{
376
377
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
  m_IFunctionActive.insert(m_IFunctionActive.end(),f->nActive(),m_functions.size());
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  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();
  }
394
  return m_functions.size() - 1;
395
396
}

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

406
  IFunction* fun = getFunction(i);
407

408
409
  size_t dna = fun->nActive();
  size_t dnp = fun->nParams();
410

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

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

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

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

  m_nActive -= dna;
  // Shift the active offsets down by the number of i-th function's active params
461
  for(size_t j=i+1;j<nFunctions();j++)
462
463
464
465
466
467
468
  {
    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
469
  for(size_t j=i+1;j<nFunctions();j++)
470
471
472
473
474
475
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
476
477
478
479
  if (del)
  {
    delete fun;
  }
480
481
}

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

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

506
  IFunction* fun = getFunction(i);
507
508
  size_t na_old = fun->nActive();
  size_t np_old = fun->nParams();
509

510
511
  size_t na_new = f->nActive();
  size_t np_new = f->nParams();
512
513
514

  // Modify function indeces: The new function may have different number of parameters
  {
515
516
    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
517
    {
518
519
      if (np_old > np_new)
      {
520
        m_IFunction.erase(itFun,itFun + np_old - np_new);
521
522
523
      }
      else if (np_old < np_new) 
      {
524
        m_IFunction.insert(itFun,np_new - np_old,i);
525
      }
526
    }
527
528
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
529
530
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
531
    }
532
533
534
535
  }

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

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

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

  m_functions[i] = f;
  delete fun;
}

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

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

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

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

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

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

    name = varName.substr(i+1);
  }
639
640
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

845
846
} // namespace API
} // namespace Mantid