Accessing Laws through Classes


The base class law has seven subclasses that divide laws by how many sublaws they evolve and how they are parsed. Some laws use ACIS classes such as curves, wires, surfaces, or transformations as part of their definition. These laws are derived from either unary_data_law or from multiple_data_law. Other ACIS classes are wrapped by a class derived from the class law_data so that they have a more uniform interface.

The classes derived from base law include:

constant_law
Defines a data member that has a constant value.
identity_law
Defines the input variables to the other law classes. Variables in C++ are numbered starting at zero (0). Variables using law symbols are numbered starting at one (1). Any letter of the alphabet may be followed by a number when using law symbols. When followed by a number in law symbol format, the numbers begin at 1. The law symbols (A-Z)1, X, U, or T are equivalent to the zero identity. The variables X, Y, and Z are equivalent to the indices 0, 1, and 2 in C++. U and V are equivalent to 0 and 1 in C++. T is equivalent to 0 in C++.
unary_law
Defines mathematical functions that have one sublaw argument.
binary_law
Defines mathematical functions that have two sublaw arguments. Some binary laws are associative, meaning in the case of plus, (A+B)+C=A+(B+C), and some are commutative, meaning in the case of times, A*B=B*A.
multiple_law
Defines mathematical functions that have multiple sublaw arguments and may be commutative, meaning f(A,B,C)=f(B,C,A).
law_data
Defines a base class used to handle ACIS classes that behave like functions. The derived classes from law_data are wrapper classes for specific ACIS classes, such as curves, wires, surfaces, and transforms. The purpose of the wrapper law_data class is to permit some ACIS classes to be handled in the same way as normal law classes. The wrapper functions know how to evaluate the data from the ACIS classes, how to save and restore them, and how to parse and unparse them.
unary_data_law
Similar to unary_law but can accept as input an array of elements derived from the law_data class. Therefore, it can handle laws, curves, wires, transforms, or surfaces.
multiple_data_law
Similar to multiple_law but can accept as input an array of elements derived from the law_data class. Therefore, it can handle laws, curves, wires, transforms, or surfaces.
These seven classes specify how the input arguments are to be parsed. For the most part, these classes are not accessed directly unless you are deriving a new law that does not already exist. All other law classes, which cover simple arithmetic, advanced mathematics, trigonometry, hyperbolic functions, derivatives, etc., are derived from one of these seven law classes.

For example, plus_law is derived from binary_law. binary_law parses the two input arguments that plus_law then operates on. Likewise, cos_law is derived from unary_law. unary_law parses the single input argument on which cos_law then operates.

Defining New Law Classes

An application can create a new law class that is not already a part of ACIS. In fact, an application is more likely to derive its own law class than to derive its own entity class (from ENTITY). This section describes how an application would derive a law.

Note: When an application derives its own law or entity classes for use in a save file, it breaks the ACIS geometry bus, because only that ACIS application understands how to save and restore the new information. However, laws that are derived strictly for the purposes of analysis do not break the ACIS geometry bus.

For a new law class to be handled properly, it must meet the following requirements.

Evaluators

All derived law classes are required to have the evaluate and derivative methods. Laws derived from constant laws inherit these two methods.

When calling the evaluation methods, use the most specific evaluation method possible. The more specific evaluation methods perform checking on the laws. For example, evaluate verifies that the law returns three values, else an error is issued.

public: virtual void law::evaluate (
    double const* x, // pointer to values used in evaluation
    double* answer   // multi-dimension answer range for evaluation
) const;

This method takes two pointers to memory that the caller is responsible for creating and freeing. The x argument tells where to evaluate the law. This can be more than one dimension. The answer argument returns the evaluation. This can be more than one dimension. x should be the size returned by the take_dim method, and answer should be the size returned by the return_dim method. All derived law classes must have this method or inherit it. This does no checking of the dimension of input and output arguments. It is preferable to call a more specific evaluator if possible.

void cos_law::evaluate(double *x,double *answer)
{
    answer[0]=cos(sub_law->evaluateS(x));
}
public: virtual int law::return_dim () const;

The return_dim tells how many values are returned in the answer argument of the evaluate method. The default is 1. All derived law classes must have this method or inherit it.

int law::return_dim()
{
    return 1;
}
public: virtual int law::take_dim () const;

The take_dim tells how many values are read from the x argument array of the evaluate method. The default is 1. All derived law classes must have this method or inherit it.

int law::take_dim()
{
    return 1;
}

Inherited Evaluators

The remaining evaluators are usually inherited.

public: double law::eval (
    double x   // domain value to perform evaluation
    ) const;

Works on laws that take and return single values. This method evaluates the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method to make sure that no more than one argument is taken or returned by calling take_dim and return_dim.

public: virtual void law::evaluate (
    double const* x,  // pointer to values used in  evaluation
    double* answer    // multi-dimension answer range for evaluation
    ) const;

This method takes two pointers to memory that the caller is responsible for creating and freeing. The x argument tells where to evaluate the law. This can be more than one dimension. The answer argument returns the evaluation. This can be more than one dimension. x should be the size returned by the take_dim method, and answer should be the size returned by the return_dim method. All derived law classes must have this method or inherit it.

public: double law::evaluateC_R (
    complex_number c  // second number
    ) const;

Works on laws that have two-dimensional domains and one-dimensional ranges. This method evaluates the given law at the value c. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: void law::evaluateDM (
    double const* x,  // pointer to values used in evaluation
    double* answer,   // multi-dimension answer range for evaluation
    int n             // number of derivatives
    ) const;

Works on laws that accept multiple domains and return multiple range values. This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: double law::evaluateDM_R (
    double const* x,  // pointer to values used in evaluation
    int n             // number of derivatives
    ) const;

Works on laws that accept multiple domains and return a single range value. This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: double law::evaluateDR_R (
    double x,  // input value
    int n      // number of derivatives
    ) const;

Works on laws that accept a real (single domain) and return a single range value. This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAvector law::evaluateDR_V (
    double x,  // domain value to perform evaluation
    int n      // number of derivatives
    );

Works on laws that accept a real (single domain) and return a vector (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAposition law::evaluateM_P (
    double const *x   // pointer to values used in evaluation
    ) const;

Works on laws that accept a multiple domain and return a position (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPApar_pos law::evaluateM_PP (
    double const *x   // pointer to values used in evaluation
    ) const;

Works on laws that accept a multiple domain and return a parameter position (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: double law::evaluateM_R (
    double const* x   // pointer to values used in evaluation
    ) const;

Works on laws that accept a multiple domain and return a real (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAvector law::evaluateM_V (
    double const *x   // domain value to perform evaluation
    ) const;

Works on laws that accept a multiple domain and return a vector (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAposition law::evaluateNV_P (
    SPAnvector const& nv  // pointer to n-dimension vector
    ) const;

Works on laws that accept an n-dimensional vector as a single argument (domain) and return a position (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: double law::evaluateNV_R (
    SPAnvector const& nv  // pointer to numerical vector
    ) const;

Works on laws that accept an n-dimensional vector as a single argument (domain) and return a real (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAvector law::evaluatePP_V (
    SPApar_pos const& pp  // pointer to par_pos
    ) const;

Works on laws that accept a parameter position (domain) and return a vector (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAposition law::evaluateP_P (
    SPAposition p  // pointer to input position
    ) const;

Works on laws that accept a position (domain) and return a vector (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

public: SPAvector law::evaluateR_V (
    double x   // pointer to values used in evaluation
    ) const;

Works on laws that accept a real (domain) and return a vector (range value). This method evaluates the nth derivative of the given law at the value x. All law classes inherit this method for convenience. It calls the main evaluate method and does some checking of take_dim and return_dim.

deriv and derivative

The protected deriv method of the new law specifies how to take the derivative of the law. This is unique for each law. There are three ways in which ACIS laws take derivatives: symbolic, by calling ACIS class evaluators, or numeric.

For example, COS(X^2) has the symbolic derivative -SIN(X^2)*2*X. The symbolic derivatives are exact, fast, and the preferred method for taking derivatives.

A curve or surface law takes its derivative by calling ACIS class evaluators. These have procedural accuracy but cannot be further simplified.

In the case where more derivatives are required than a curve or surface provides, or, in the case where a law is so complicated that a symbolic derivative is unavailable, numeric approximations may be used. Numeric approximations are fourth order. Left- and Right- handed derivatives are also provided.

Call the derivative method to access the derivative, which checks to see if a cached version of the derivative exists. If not, it calls the deriv method. The derivative method is inherited from the base law class.

C++ Example

law *cos_law::deriv(int w)
{
    // The expected derivative is:
    // cos(f) = -sin(f)*f
    // The real work of taking the derivative is
    // performed on the following lines.
    // Remember that the derivative of the sublaw
    // also needs to be taken with respect to the
    // derivative variable w.
    // The expected derivative is:
    // cos(f) = -sin(f)*f
    law *sub1 = new sin_law(sub_law);
    law *sub2 = new uminus_law(sub1);
    sub1->remove();
    law *fprime=sub_law->derivative(w);
    law *answer = new times_law(sub2,fprime);
    sub2->remove();
    fprime->remove();
    return answer;
}
protected law **dlaw;

The dlaw is used to hold cache derivatives with respect to each of its variables.

protected int dlaw_size;

The dlaw_size is used to tell how many cache derivatives are held by dlaw.

protected: virtual law* law::deriv (
    int which = 0  // variable to take derivative with respect to default value (X or A1)
    ) const;

The deriv method returns a law pointer to the derivative of the given law with respect to the which variable. Variables in C++ are numbered starting at zero (0). Variables using law symbols are numbered starting at one (1). Any letter of the alphabet may be followed by a number when using law symbols. When followed by a number in law symbol format, the numbers begin at 1. The law symbols (A-Z)1, X, U, or T are equivalent to the zero identity. The variables X, Y, and Z are equivalent to the indices 0, 1, and 2 in C++. U and V are equivalent to 0 and 1 in C++. T is equivalent to 0 in C++. All derived law classes must have this method or inherit it.

law *plus_law::deriv(int w)
{
    // Create the law left derivative plus
    // right derivative
    law *sub1=left_law->derivative(w);
    law *sub2=right_law->derivative(w);
    law *answer = new plus_law(sub1,sub2);
    // Clean up memory
    sub1->remove();
    sub2->remove();
    return answer;
}

Parsing

Laws do not work by manipulating strings. However, given a string, one can create a law from it by calling the law parser, api_str_to_law. The strings passed in are documented in the online help as law symbols.

Applications deriving their own laws are required to have the representative static instance of the law, the law_list static instance, and the make_one method to register a new law with ACIS.

For the parser to work, each law class must overload these methods:

The new laws arguments in the static, representative instance of itself can be NULL. The representative instance is then passed as an argument into a static instance of the law_list. When the law_list instance is created, it attaches its law argument to a linked list of other laws.

All of the law symbols that the law parser recognizes are contained within the linked list of laws (law_list). Because an instance of each law is present in the law_list, the list can be traversed. The individual law_list and law_list methods can be called to find out what the parser should check for.

When a quoted character string (for example, the law mathematical function) is passed to the api_str_to_law function, it first parses the string. The parser attempts to match the longest substrings within the law to what the symbol methods have registered. When a substring is matched, its parent class type informs the parser how to handle parenthesis groupings of elements preceding it and following it.

Once all of the relationships between the substrings in the law mathematical function have been determined, law class instances are created starting at the innermost sublaw, which is usually an identity_law type. The instances are created using the make_one method of the respective law type.

public: virtual char* law::string (
    law_symbol_type type = DEFAULT // type of law standard ACIS type
    );

The string and symbol methods of the new law are simple routines required for parsing. The string method returns the laws name, which is used when parsing and when saving or restoring the law to or from a file. It is provided as a user-friendly interface to find out the definition of the current law. The string methods for an application deriving its own law will look similar to the following source code.

There are two symbol types associated with laws: the ACIS DEFAULT type and the MAPLE type, which is used by the popular symbolic-math software package. The string method returns the DEFAULT symbol unless the programmer tells it otherwise.

arcsin_law my_law;
char* str_default = my_law.string();              // str_default = ARCSIN
char* str_also_default = my_law.string(DEFAULT);  // str_also_default = ARCSIN
char* str_maple = my_law.string(MAPLE);           // str_maple = arcsin

C++ Example

char *cos_law::string(law_symbol_type type)
{
    // Derived classes must use the appropriate functions
    // ustring (unary), bstring (binary), cstring (multiple),
    // or number_string (constant).
    chr *answer;
    If (type == DEFAULT){
       answer = ustring(COS);
    } else if (type == ...) {
       answer = ustring(...);
       // answer is some other type
    }
    return answer;
}

The quoted return string for both string and symbol methods must agree. In this example, the return string is COS if the law_symbol_type is DEFAULT. This is the string that the parser is looking for and that an application can use as input to the api_str_to_law function.

The string method calls an additional function, depending on its parents type. For example, if its parent is a unary_law (or unary_data_law), then the ustring function is used. If its parent is a binary_law, then the bstring function is used. If its parent is a multiple_law (or multiple_data_law), then the cstring function is used. If its parent is a constant_law, then the number_string function is used with a double value instead of a string.

These additional string functions allow the sublaws of a given law to be viewed, and take care of leading and trailing parenthesis and commas during parsing for the law type.

public: virtual char const* law::symbol (
    law_symbol_type type = DEFAULT  // type of law symbol standard ACIS type
    );

The string and symbol methods of the new law are simple routines required for parsing. The symbol method for an application deriving its own law will look similar to the following source code.

C++ Example

char *cos_law::symbol(law_symbol_type type)
{
    If (type == DEFAULT){
       returnCOS;
    } else if (type == ...) {
       return ...;  // answer is some other type
    }
}

The quoted return string for both string and symbol methods must agree. In this example, the return string is COS if the law_symbol_type is DEFAULT. This is the string that the parser is looking for and that an application can use as input to the api_str_to_law function.

public: virtual int law::precedence ();

Precedence specifies the order in which laws should be evaluated. For example, multiplication is evaluated before addition. The following is a list of values that may be returned by your function. The higher order numbers for precedence are evaluated first. In the event of a tie, operators are evaluated from left to right. For example, 1-2-3 evaluates to -4 and is equivalent to (1-2)-3.

			#define PRECEDENCE_OR        1
			#define PRECEDENCE_AND       2
			#define PRECEDENCE_NOT       3
			#define PRECEDENCE_EQUAL     4
			#define PRECEDENCE_PLUS      5
			#define PRECEDENCE_TIMES     6
			#define PRECEDENCE_POWER     7
			#define PRECEDENCE_FUNCTION  8
			#define PRECEDENCE_CONSTANT  9
			char make_one;
			

The make_one method of the new law is required to get the law to parse.

The following example shows the make_one method for the cos_law. It has a pointer to a sublaw (for example, another law) as its input argument. The sublaw, however complex, is created first. Then the cos_law is created around the sublaw with a pointer to that sublaw.

C++ Example

unary_law *cos_law::make_one(law *sub)
{
    return new cos_law(sub);
}

Applications deriving their own laws are required to have the representative static instance of the law, the law_list static instance, and the make_one method.

Simplify

The law simplifier is accessed through the method simplify. When given a law, the simplify function returns a law that is equivalent to the given law but with fewer or simpler terms.

The goal of the simplifier is to improve performance; it is not to simplify a law as far as possible. Laws that require extensive analysis in order to simplify would defeat the purpose of improved performance. These are not simplified, and a copy of the original is returned.

protected law *slaw;

This data member of the law class holds a cache value of the most simplified version of the law.

protected int slevel;

This data member of the law class tells what level of simplification was used to create the law held by slaw. See simplify for a discussion of the levels.

public: law* law::simplify (
    int level = 0,  // level of simplification
    int show_work = 0  // for debugging, shows simplification
    );

This method calls the law simplifier, returns a simplified law, and caches its value in the slaw data member. Its two arguments are both optional. They are primarily set for experimentation and debugging. At present, only level 0 and 1 simplification are available. Level 0 is recommended for most uses.

When show_work argument is set to a positive integer, debugging information is provided. Because laws cache their simplified version, simplifying a law twice does not result in any debugging information on the second call. To trick the simplifier into not using its cache value, the level argument should be set to 666.

public: virtual law* law::sub_simplify ();

This is a method that may be overloaded by classes to provide assistance to the simplifier. Most laws simply inherit a function that returns null.

For example, a curve law applied to a line or ellipse can return an equation in the form of a law. The sub_simplify method can then access private members of the curve law that the simplifier does not have access to.

C++ Example

			law *norm_law::sub_simplify()
			{
			    // this_law was set to v*(dot(v,v))^(-0.5)
			    // by the constructor
			    this_law->add();
			    return this_law;
			}
			

Memory Management

Laws are use-counted. Therefore, their destructor is protected and should not be called directly. When an application destructs a law, the remove method should be called. For more efficient memory usage behind the scenes, the law classes use the add and remove methods which increment or decrement a use count, an indication of how many copies of the law are in existence.

For example, if f is a law for X^2, it is an exponent_law with the arguments identity_law for x and the constant_law for 2.

When a new df law is created using the derivative method of f, the result 2*X is a times_law with the arguments constant_law for 2 and the identity_law for x.

In the construction process of the df law, instead of creating new instances of the constant_law for 2 and the identity_law for x, the constructor calls the add methods, which increment their respective use counts. In this manner, memory is not taken up with duplicates of the constant_law for 2 or the identity_law for x.

If the remove method of either f or df is called, the remove methods of their sublaws are also called. The sublaws decrement the use count and only actually call the law::~law destructor if the use count goes to zero.

The following data members and methods are used for law memory management.

int use_count;

This data member keeps track of how many references to the law are in existence. When it reaches zero (0) through subsequent calls to remove, then the protected destructor is called.

protected: virtual law::~law ();

This is the protected destructor. It is not called directly. In addition to the law constructor and the destructors of the main law class, a derived law may also have a destructor. All of destructors are called by remove when the use count reaches zero.

The destructor of derived classes should be a public method.

public static int how_many_laws;

This is a static data member of the law class that keeps track of how many law are in existence at any given time. It is used to check for memory leaks.

public: void law::add ();

This is not usually called by an application directly. An application calls this method to preserve a copy of this law. It is also called by the law constructors for the law being constructed, as well as for all of its sublaws. It increments the use_count.

public: void law::remove ();

Applications should call remove instead of the tilde (~) destructor to get rid of a law. Decrements the use_count. This is called by the law destructors for the law being destructed, as well as for all of its sublaws. remove calls the destructor if use_count falls to zero. Used for memory management.

public: char* law::string_and_data (
    law_data** *ld,       // array of law data
    int* size,            // size of arrayv     law_symbol_type type = DEFAULT  // type of law symbol standard ACIS type
    );

This method is inherited by all classes. Given a law, this returns an array of law_data pointers, the size of the array, and its string in the type specified. This function is used by save to create the string and the array of law_data pointers that defines the law.

void save();

This method saves the law symbol string for the given law in the DEFAULT law_symbol_type format to the save file (SAT or SAB). This saves not only the identifier string, but also all associated law_data information.

law *restore();

This function returns a law created from the law symbols in the DEFAULT law_symbol_type format that were saved to a save file. This restores not only the identifier string, but also all associated law_data information. The result is returned as a pointer to a law.

Type Identification

There are two ways of determining the type of a law. The first way identifies the class at the top of the expression tree. The second way tells what type of algebraic structure the law has.

For example, a law may be constant without being derived from the constant law class. For this reason, it is almost always best to identify a law by calling zero, integer, constant, linear, or polynomial methods. These methods set the type_flag and not_type_flag so that subsequent calls have faster performance.

Class identification is best done with the isa method. The following code fragment checks to see if my_law is a constant_law or a law derived from constant_law, such as the pi_law. The law mathematical function 5*4 is an example of a times_law that is constant. It would not pass the if statement in the following code fragment.

C++ Example

Law *my_law;
...
if (my_law->isa(constant_law::id())
{,br>     ...
}

Because isa only checks for class type, it is used only in cases where laws are being symbolically manipulated as in the simplifier. It should not be used to check for an algebraic property.

The id, isa, and type methods of the new law are required for all derived law classes, but include nearly identical code for all law classes.

public: virtual int law::type () const;

This data member of the law class caches the results of previous inquiries as to the algebraic type of a law. The following is a list of allowed values:

#define LAW_TYPE_UNKNOWN     0
#define LAW_TYPE_ZERO        1
#define LAW_TYPE_INTEGER     2
#define LAW_TYPE_CONSTANT    3
#define LAW_TYPE_LINEAR      4
#define LAW_TYPE_POLYNOMIAL  5
#define LAW_TYPE_G_INFINITY  6
#define LAW_TYPE_G_5         7
#define LAW_TYPE_G_4         8
#define LAW_TYPE_G_3         9
#define LAW_TYPE_G_2         10
#define LAW_TYPE_G_1         11
#define LAW_TYPE_CONTINUOUS  12
#define LAW_TYPE_BOUNDED     13
#define LAW_TYPE_RATIONAL    14

For example, COS(X+7)^2 + SIN(X+7)^2 is the constant 1. A call to the method constant returns true and sets the type_flag to LAW_TYPE_CONSTANT. Subsequent calls to the constant method would only need to reference this type_flag.

public: static int law::id ();

The id methods purpose is to return a unique integer identification for the class. It gets this by calling new_law_id the first time id is called. These identifiers are used to pass values to the isa function when it is called to perform class identification. Every law class must have this method.

public: virtual int law::type () const;

The type methods purpose is only to return its identification. The type method is only used internally to overload the == operator for laws. Every law class must have this method.

int cos_law::type()
{
    return id();
}
public: virtual logical law::isa (
    int t  // id method return
    ) const;

The isa method returns true or false depending upon whether or not this law or any of its ancestors have this same identification as the one passed in. For example, a plus_law returns true if the identification (id) for a plus_law, binary_law, or law is passed to it.

The source code from the cos_law for these methods could be used as shown, with the exception of the class name and the parent class unary_law::isa method used in the isa method. The derived classs isa method should use the isa method from its parent class. The following code fragment is nearly identical for all law classes, except that the parent needs to be changed.

logical cos_law::isa(int t)
{
    // Derived classes should use the proper parent class
    // is a method, such as binary_law::isa(t), etc.
    return (t==id() || unary_law::isa(t));
}
public: logical law::zero (
    double tol = SPAresabs      // tolerance to use in determination, use SPAresabs by default
    );

The zero method returns true if the law is equivalent to zero. The law mathematical function vec(0, 0, 0) is considered zero by this method.

public: logical law::integer ();

The integer method returns true if the law is equivalent to a constant_law which returns an integer.

public: logical law::constant ();

The constant method returns true if its evaluate method returns the same value for all inputs. The law mathematical function vec(0, 0, 0) is considered constant by this method.

public: logical law::linear ();

The linear method returns true if the derivative method returns the same value for all inputs.

public: virtual law_polynomial* law::polynomial (
    law* in// input law
    ) const;

The polynomial method returns a law polynomial class which contains the coefficients of a polynomial and a law that it is a polynomial with respect to. The argument in may be null. If the in argument is not null, then the law polynomial class that is returned contains the coefficients of a polynomial with respect to the in law.

Operators and Properties

The == and != methods are used to identify whether a law is identical to another law. These methods use the same method. All three need to be defined or inherited by all derived classes.

public: int law::operator== (
    law& inlaw    // law to compare this to
    );

The == method determines whether this law class is equivalent to the given inlaw class. This is inherited by all laws and calls the same method which the major law subclasses override. This is used for simplification.

public: int law::operator!= (
    law& inlaw    // law to compare this to
    );

The != method determines whether this law class is not equivalent to the given inlaw class. This is inherited by all laws and calls the same method which the major law subclasses override. This is used for simplification.

public: virtual int law::same (
     law*,  // 1st law to test
    law*   // 2nd law to test
    );

The same method should not be called directly by the application. This is used for simplification. For a law to be saved and restored, it must have or inherit this method. This method is called by the == method, to see if two laws are the same.

public: virtual law_domain* law::domain ();

The domain method returns a law_domain class that contains information that defines the domain of the law. See the law_domain class in the online documentation for a further description.

public: virtual int law::singularities (
        double** where,   // where discontinuity exist
        int** type        // type of discontinuity
        );

The singularities method returns true if any singularities exist for the law. It also returns an array of doubles which specify where singularities are, and an array of integers which specify the type of singularity. This is only implemented at this time for one dimensional laws.

The type is 0 if there is a discontinuity, 1 if the discontinuity is in the 1st derivative, and any integer n if the discontinuity is in the nth derivative. -1 means that it is not defined.

[Top]