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
49
50
51
52
53
54
55
56
  return *this;
}

///Destructor
CompositeFunction::~CompositeFunction()
{
}


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

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

118
119
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
/** 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);
  }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/**
309
 * @param i :: A declared parameter index to be removed from active
310
 */
311
void CompositeFunction::fix(size_t i)
312
{
313
  if (isFixed(i)) return;
314
  size_t iFun = functionIndex(i);
315
316
317
318
319
320
321
322
  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]);
323

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

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

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

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

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

356
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
357
358
  m_functions.clear();

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

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

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

404
  IFunction_sptr fun = getFunction(i);
405

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

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

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

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

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

  m_nActive -= dna;
  // Shift the active offsets down by the number of i-th function's active params
459
  for(size_t j=i+1;j<nFunctions();j++)
460
461
462
463
464
465
466
  {
    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
467
  for(size_t j=i+1;j<nFunctions();j++)
468
469
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
/** Replace a function with a new one. The old function is deleted.
477
 *  The new function must have already its workspace set.
478
 * @param f_old :: The pointer to the function to replace. If it's not
479
 *  a member of this composite function nothing happens
480
 * @param f_new :: A pointer to the new function
481
 */
482
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
483
{
484
  std::vector<IFunction_sptr>::const_iterator it = 
485
486
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
487
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
488
  replaceFunction(iFun,f_new);
489
490
}

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

500
  IFunction_sptr fun = getFunction(i);
501
502
  size_t na_old = fun->nActive();
  size_t np_old = fun->nParams();
503

504
505
  size_t na_new = f->nActive();
  size_t np_new = f->nParams();
506
507
508

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

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

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

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

  m_functions[i] = f;
}

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

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

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

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

624
    std::string sindex = varName.substr(1,i - 1);
625
626
627
628
629
630
631
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
632
633
}

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

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

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

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

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

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

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

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

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

736
737
void CompositeFunction::setParametersToSatisfyConstraints()
{
Peterson, Peter's avatar
Peterson, Peter committed
738
  for(size_t i=0;i<nFunctions();i++)
739
740
741
742
743
  {
    getFunction(i)->setParametersToSatisfyConstraints();
  }
}

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

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

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

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

796
/**
797
 * Returns the shrared pointer to the function conataining a parameter
798
 * @param ref :: The reference
799
800
 * @return A function containing parameter pointed to by ref
 */
801
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
802
{
Peterson, Peter's avatar
Peterson, Peter committed
803
  for(size_t iFun=0;iFun<nFunctions();iFun++)
804
  {
805
806
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
807
    {
808
      return fun;
809
810
    }
  }
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  return IFunction_sptr();
}

///**
// * @param fun :: The searched function
// * @return A function containing the argument function fun
// */
//IFunction_sptr CompositeFunction::getContainingFunction(IFunction_sptr fun)
//{
//  if (fun.get() == this)
//  {
//    return fun;
//  }
//  for(size_t iFun=0;iFun<nFunctions();iFun++)
//  {
//    IFunction_sptr f = getFunction(iFun);
//    if (f == fun)
//    {
//      return getFunction(iFun);
//    }
//  }
//  return IFunction_sptr();
//}
834

835
836
} // namespace API
} // namespace Mantid