Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Ampersand is meant to develop information systems.
This tutorial will get you going with Ampersand. Consult your tutor with questions.
You have a tool to experiment with, supplemented by this video (in Dutch) to make your start even easier.
This tutorial is meant for Business- or IT professionals who want to learn about information systems development. Knowledge about Ampersand is not presumed. The text offers pointers for you to find out many things on your own. This tutorial is intended for individual study, but you can always ask your tutor if things are unclear. The required theory is also available in Learning Unit 3 of the coursebook of the course IM0403, Rule-Based Design, taught at the Open University of the Netherlands.
You will start by looking at an information system called "Enrollment" and learn the basics of its specification. By looking at a small information system you can discuss the purpose of the course with your tutor and peers.
Then you will be introduced to the web-based version of Ampersand, RAP4, in which you can specify an information system and create a working web-based prototype. With this tool, you can make information systems of your own, enabling you to complete the course.
Next, we will have a look at the conceptual model behind the Enrollment system. You will learn to interpret a rule based on the given concepts and relations. You will see some basics of relational algebra.
You will learn how to analyse a "spreadsheet information system" and turn it into a well defined information system. This technique allows you to help organizations with organizing and structuring data.
You will learn how to add rules to your data. This will allow you to add meaning to your information system, because you can assure your user community that these rules will remain satisfied.
Ampersand is meant to develop information systems.
This tutorial will get you going with Ampersand. Consult your tutor with questions.
You have a tool to experiment with.
Ampersand adheres to the reactive programming paradigm. This chapter tells the story...
The easiest way to think about Ampersand is to envisage an information system as a set of structured data that changes over time (just like a database), together with a set of constraints (the rules) on that data that must remain satisfied throughout their lifetime.
Abstract? Here is a simple example:
Think of your example system as an empty set of data with just one rule: "Every parcel must have an owner."
Suppose that there is an event that inserts into the data set: "Parcel with property identifier 074.0-0000-0084.0 is 0.54 acres large."
The system will now signal that property 074.0-0000-0084.0 doesn't have an owner.
Either you (as a user) or a computer (as automaton) can satisfy the rule by inserting into the data that the owner of property 074.0-0000-0084.0 is Grafton Town of Highway Department, 30 Providence Rd, Grafton, MA 01519-1186. Hence the rule is satisfied.
bla bla
Do you want to avoid unnecessary reading? Take a moment to decide which statement describes your curiosity best:
"I'm just interested to know who might use Ampersand and for which purposes." Click here to learn why you might want Ampersand.
"I am a student wanting to use Ampersand in class." This tutorial was made just for you. Students who like something different will love it.
"I am a computer professional in need of a good method for designing an information system." Computer professionals who like fast results will be thrilled, provided they make the effort of learning.
"I am a scientific researcher and I want to learn more about the research behind Ampersand." Scientists who like formal methods will appreciate this particular use of relation algebra.
"I am a software engineer and I want to change Ampersand to suit my needs." You'll be delighted to see that your back-end software is as adaptable as your front-end software, and everything is generated towards proven technology for the sake of maintainable results.
"I work in an industry, an enterprise, or a government institute and I hope Ampersand is the silver bullet that kills all vampires and solves my problems." Alas, there's no such thing as a free lunch. Ampersand is not interesting for you. (Ampersand promises correct data and fast development to those who don't believe in fairy tales and do want to make the effort.)
Rarely does one need to learn everything there is to know about Ampersand. Take one bite at a time, no more than you can chew, and use it in practice immediately. Learn as you go...
Ampersand is a project with no funds. The people who are supporting Ampersand are volunteers with little spare time. This explains why there are omissions in this text. So please condone any shortcomings. We are looking for skilled volunteers to help this project forward, by the way.
Unless otherwise specified, everything in this repository is covered by the following licence:
Ampersand Documentation by the the Ampersand team is licensed under a Creative Commons Attribution 4.0 International Licence.
Based on a work at https://github.com/AmpersandTarski/documentation
In the code you can find the MEANING of each relation in natural language. In the model, each relation represents a set of pairs. The relation takes
is filled with (Student, Course)
-pairs that each specify a specific course that that specific student is taking. The same student can appear in more pairs and the same course can appear in more pairs. But each combination is unique, a specific pair (x,y) can only appear in the set once.
You have seen the web application Enrollment in action. You have seen the code that defines the system in such a way that Ampersand can generate the web application. Now we will have a look at the conceptual model that is defined in that code. In this tutorial we will only describe the example to make you more familiar with the terminology. Just try to recognize what is described in the code and in the working system.
We have three ingredients:
CONCEPT
RELATION
RULE
Before we discuss these three main ingredients, we will discuss the other keywords you see in the code.
INTERFACE is not crucial for the conceptual model, but still crucial for the web application. It uses the conceptual model to define the tabs and fields displayed. We will come back to this later.
The text after MEANING and PURPOSE is printed in the documentation that RAP4 can generate.
MESSAGE and VIOLATION are used to display messages on screen to the user about rule violations.
POPULATION provides the web application with actual data to test the rules with. Adding data to the system can also be done with an excel sheet. The data specifies elements that populate the concepts and whether or not these elements are connected to each other in a specific relation.
The goal of the model is to define rules that will govern the behavior of the system. Rules are about relations and relations link elements of one concept with elements of another concept. So we need all three ingredients (concept, relation and rule) to define the model. Deciding about these ingredients, their name and their attributes is exactly the modeling that you will learn in this course.
A conceptual model of Enrollment can be represented with a diagram:
In the code you can find the MEANING of each relation in natural English. In the model, each relation represents a set of pairs. The relation takes
is filled with (Student, Course)
-pairs that each specify a specific course that that specific student is taking. The same student can appear in more pairs and the same course can appear in more pairs. But each combination is unique, a specific pair (x,y) can only appear in the set once.
In the code you see the keyword [TOT]
in the definition of the relation takes
. It is called a multiplicity. The multiplicity 'total' means that each student must take at least one course.
Question 1: given the initial dataset in the source-code of Enrollment, what pairs are in the relation isPartOf
?
Question 2: given the initial dataset in the source-code of Enrollment, which students are enrolled for which modules?
Check your answer in the web application Enrollment.
So let’s finally go to the one rule that governs this information system: isEnrolledFor |- takes ; isPartOf~
The rule consists of two parts with |-
as separator. On each side of the separator you find a relation. On the left-hand side we have the relation isEnrolledFor
and on the right-hand side you see a relation that is not explicitly defined in the model. This relation is constructed with two relations that are in the model: takes
and isPartOf~
(pronounced as “isPartOf-flip”, indicating the relation in opposite direction). This constructed relation consists of (Student
, Module
)-pairs with a specific student that is taking a course that contains (among others) this specific module.
Try to trace this last description in the model and note that although the result is a pair of two elements, there are actually three concepts involved.
Let’s call this new relation canEnrollFor
.
Now we can pronounce the rule in more or less natural language: "isEnrolledFor implies canEnrollFor". If the first is true than the second must also be true.
Everytime the user of the system tries to enroll a student for a module, the rule checks whether this student can be enrolled for this module based on the course the student is taking. If this enrollement is not allowed, the rule produces a violation message. In fact, with each ‘save’ in the database, all information in the database is checked against this rule.
Try to reason about the answers to the following questions based on the conceptual model and the rule. After that, try it out in the system.
Question 1: Suppose the user adds to the database that student Peter is enrolled for the module IT-Governance. Will this cause a violation message?
Question 2: Next, what will happen when the module IT-Governance is no longer a part of the course Business IT. Why?
Question 3: Think of an entry you can do in the system to generate a violation message and try it out in the system.
Question 4: John is a hard working student and he wants to take a second course, Management. Will the system allow this? Why?
Question 5: The multiplicity [TOT] seem to work as a rule. What is the difference between a multiplicity, like TOT
, and a rule, like isEnrolledFor |- takes ; isPartOf~
?
an information system may be seen as a system of relations and rules that governs data, supplemented by user interfaces that give access to that data.
a rule engine executes the rules on all data regularly
Ampersand lets you use business rules as intended in the (by the Business Rules Group, 2003). This chapter quotes each article from the manifesto verbatim. Besides, it describes how Ampersand implements it,
Watch to learn how we use the words atom, concept, and relation.
This concludes your first steps to get acquainted with Ampersand script en RAP4. The Open University Coursebook contains all theoretical background you need to start understanding and creating your own model. This Gitbook offers more practical and up to date information about the language Ampersand script. For the syntax and meaning of Ampersand constructs, consult chapter . For more in depth information about modeling in Ampersand . For the rest...have a look around and feel free to ask questions.
Primary Requirements, Not Secondary |
1.1. | Rules are a first-class citizen of the requirements world. |
Ampersand says: | Agreed! First-class means that every requirement is a rule and every rule is a requirement. An Ampersand-engineer makes a requirement concrete by specifying a constraint. At design time, these constraints must be consistent and Ampersand's type system helps out by signalling those inconsistencies. At runtime violations of constraints are signalled the moment they occur. |
1.2. | Rules are essential for, and a discrete part of, business models and technology models. |
Ampersand says: | Agreed! Business models and technical models in Ampersand consist of rules. |
Separate From Processes, Not Contained In Them |
2.1. | Rules are explicit constraints on behavior and/or provide support to behavior. |
Ampersand says: | Agreed! Each rule in Ampersand is a constraint, the violations of which are computed (in real time) and signalled to the appropriate stakeholder. The signal triggers behavior of the individual who is assignd to make that violation go away. Support is provided by different types of enforcement. |
2.2. | Rules are not process and not procedure. They should not be contained in either of these. |
Ampersand says: | Agreed! An Ampersand-engineer defines rules, not processes and not procedures. |
2.3. | Rules apply across processes and procedures. There should be one cohesive body of rules, enforced consistently across all relevant areas of business activity. |
Ampersand says: | Agreed! A rule applies throughout its context. If several processes and procedures are valid in a particular context, all rules of that context apply to all of them. |
Deliberate Knowledge, Not A By-Product |
3.1. | Rules build on facts, and facts build on concepts as expressed by terms. |
Ampersand says: | Agreed! Facts are true statements. Assuming that the data entered in an information system represent facts, Ampersand preserves their truth with mathematical rigor. If false data (i.e. non-facts) are entered into an information system built by Ampersand, the software will detect every inconsistency caused by that falsehood. Facts in Ampersand constitute the population of relations. Relations exist between concepts. Rules are expressed by terms in which operators link relations into meaningful terms. |
3.2. | Terms express business concepts; facts make assertions about these concepts; rules constrain and support these facts. |
Ampersand says: | Agreed! If the Ampersand-engineer works on a business problem, she uses the concepts of the business as concepts in Ampersand. |
3.3. | Rules must be explicit. No rule is ever assumed about any concept or fact. |
Ampersand says: | Agreed! Every rule in Ampersand is explicit and has a well defined meaning that a computer can calculate. An Ampersand-engineer can formulate that rule explicitly in natural language too. |
3.4. | Rules are basic to what the business knows about itself — that is, to basic business knowledge. |
Ampersand says: | Agreed! Rules are the mortar that unite individuals to form an organisation or to realise a business process. Together with the definitions of concepts and relations, rules form the ontology of the business. |
3.5. | Rules need to be nurtured, protected, and managed. |
Ampersand says: | Agreed! Rules need to be managed in a rule repository such as RAP. |
Declarative, Not Procedural |
4.1. | Rules should be expressed declaratively in natural-language sentences for the business audience. |
Ampersand says: | Agreed! Ampersand rules are constraints, and therefore declarative. A rule has no procedural interpretation. |
4.2. | If something cannot be expressed, then it is not a rule. |
Ampersand says: | Only formal rules are expressed in Ampersand, which is necessary for generating software. Informal rules cannot be expressed in Ampersand. However formal rules are accompanied by their formulation in natural language. |
4.3. | A set of statements is declarative only if the set has no implicit sequencing. |
Ampersand says: | Agreed! Statements in Ampersand are order independent. There is no implicit sequencing. Changing places does not change meaning, just like rules in natural language do. |
4.4. | Any statements of rules that require constructs other than terms and facts imply assumptions about a system implementation. |
Ampersand says: | Agreed! Ampersand defines rules exclusively by terms and facts and makes no assumptions about a system implementation. |
4.5. | A rule is distinct from any enforcement defined for it. A rule and its enforcement are separate concerns. |
Ampersand says: | Agreed! Rules and enforcements of rules are separated in Ampersand. Ampersand supports 4 ways of enforcing rules: invariance (a rule must remain satisfied at all times), process (a rule must be satisfied eventually by a designated role who reacts on violations), automated (a rule wil remain satified because a computer reacts on violations), and none (the rule will remain satisfied without any enforcement. Axioms are such rules.) |
4.6. | Rules should be defined independently of responsibility for the who, where, when, or how of their enforcement. |
Ampersand says: | Agreed! responsibility is specified separate from rules in Ampersand. |
4.7. | Exceptions to rules are expressed by other rules. |
Ampersand says: | Agreed! Ampersand contains no exception mechanism for precisely this reason. Every exception is expressed as a proper rule. |
Well-Formed Expression, Not Ad Hoc |
5.1. | Business rules should be expressed in such a way that they can be validated for correctness by business people. |
Ampersand says: | Agreed! Business rules are formulated (by an Ampersand-engineer) both in natural language and in formal language. The natural language representation is used in discussions with business people. The formal language is used by computers. The correspondence between the two can be verified by peer-reviewing. |
5.2. | Business rules should be expressed in such a way that they can be verified against each other for consistency. |
Ampersand says: | Agreed! Consistency of rules is first checked in a type checker. Rules that fail this test have no semantics and are rejected as a consequence. The remaining rules have an interpretation, which is used by a computer to signal data that violates the rule. In case of an inconsistency, violations won't go away. The only way to resolve that situation is to change one or more rules to form a consistent set. |
5.3. | Formal logics, such as predicate logic, are fundamental to well-formed term of rules in business terms, as well as to the technologies that implement business rules. |
Ampersand says: | Agreed! Ampersand use mathematical logic on terms in relation algebra. |
Rule-Based Architecture, Not Indirect Implementation |
6.1. | A business rules application is intentionally built to accommodate continuous change in business rules. The platform on which the application runs should support such continuous change. |
Ampersand says: | Agreed! The business rules application generated by Ampersand accommodates change in business rules by instant building of the application and by mutual independence of rules. Taking out or adding a rule does not affect other rules. The Ampersand compiler will generate the application also if the rules are not yet complete, which allows for incremental development of the rules. |
6.2. | Executing rules directly — for example in a rules engine — is a better implementation strategy than transcribing the rules into some procedural form. |
Ampersand says: | Agreed! Rules in Ampersand are executed directly. All transformations needed are perfomed "under the hood" outside the view of engineers and users. |
6.3. | A business rule system must always be able to explain the reasoning by which it arrives at conclusions or takes action. |
Ampersand says: | Agreed! The system gives highly informative error messages that use the text of each rule to explain violations. |
6.4. | Rules are based on truth values. How a rule's truth value is determined or maintained is hidden from users. |
Ampersand says: | Agreed! The computation is hidden from users. All the user sees is a (database-like) application that signals violations when necessary. |
6.5. | The relationship between events and rules is generally many-to-many. |
Ampersand says: | Agreed! The Ampersand-system bears resemblance to reactive programming in this respect. |
Rule-Guided Processes, Not Exception-Based Programming |
7.1. | Rules define the boundary between acceptable and unacceptable business activity. |
Ampersand says: | Agreed! A business that can clearly express what is acceptable/desirable and what is not (given its goals and culture) is supported by Ampersand's formal rules. When executed, violations will signal transgressions of the boundary. Ampersand will also tell which rule has been violated. Of course, a computer can never enforce ethical conduct. Neither can Ampersand. |
7.2. | Rules often require special or selective handling of detected violations. Such rule violation activity is activity like any other activity. |
Ampersand says: | Agreed! There are enforcement mechanisms to trigger corrective actions, either human action (process enforcement) or computer action (automated enforcement) or no action (invariance; the computer blocks and must roll back) |
7.3. | To ensure maximum consistency and reusability, the handling of unacceptable business activity should be separable from the handling of acceptable business activity. |
Ampersand says: | Agreed! Even though Ampersand has no specific construct for this, this principle is clearly applicable. |
For the Sake of the Business, Not Technology |
8.1. | Rules are about business practice and guidance; therefore, rules are motivated by business goals and objectives and are shaped by various influences. |
Ampersand says: | Agreed! Ampersand stimulates to write a purpose with each rule. That is where motivations, business goals and objectives are linked to rules. In the Ampersand way of working, Ampersand-engineers are stimulated to identify stakeholders and discuss with them deeply. |
8.2. | Rules always cost the business something. |
Ampersand says: | Agreed! If the rule is not automated, people have to be educated to enforce them. That costs. Even if the rule is automated, there is a learning curve for people to comply with the rule correctly. That costs. If both cases it has to be documented and validated. That costs. The point is there are no free lunches. So you don't want more rules, you want fewer (good) rules. (… which is Principle 8.4.) (thanks to Ron Ross for this paragraph) |
8.3. | The cost of rule enforcement must be balanced against business risks, and against business opportunities that might otherwise be lost. |
Ampersand says: | Agreed! This goes without saying |
8.4. | ‘More rules’ is not better. Usually fewer ‘good rules’ is better. |
Ampersand says: | Agreed! More rules restrict more, less rules restrict less. An Ampersand-engineer will happily remove a rule if it doesn't add value |
8.5. | An effective system can be based on a small number of rules. Additional, more discriminating rules can be subsequently added, so that over time the system becomes smarter. |
Ampersand says: | Agreed! Many Ampersand examples of less than 10 rules exist. A typical large system contains several hundreds of rules. Adding rules over time is easy, because rules have the property of compositionality. |
Of, By, and For Business People, Not IT People |
9.1. | Rules should arise from knowledgeable business people. |
Ampersand says: | Agreed! The making of rules is a task for the wise, just as in the legislative process in civilized countries. |
9.2. | Business people should have tools available to help them formulate, validate, and manage rules. |
Ampersand says: | Agreed! Ampersand provides a method, a course, and tools for this purpose. |
9.3. | Business people should have tools available to help them verify business rules against each other for consistency. |
Ampersand says: | Agreed! Ampersand and RAP are such tools. Ampersand verifies rules for consistency and RAP is a repository in which those rules can be managed. |
Managing Business Logic, Not Hardware/Software Platforms |
10.1. | Business rules are a vital business asset. |
Ampersand says: | Agreed! In principle, a business is a group of individuals who share purpose and are committed by a set of rules they try to follow. Without those rules, there is no business. So the business rules are a vital asset to the business. |
10.2. | In the long run, rules are more important to the business than hardware/software platforms. |
Ampersand says: | Agreed! A business without rules is merely a group of individuals, devoid of purpose. A business without hard/software platforms has been the norm for the many centuries before the information revolution starte. For this reason, Ampersand engineers focus on the business and let Ampersand do the technical work for them. |
10.3. | Business rules should be organized and stored in such a way that they can be readily redeployed to new hardware/software platforms. |
Ampersand says: | Agreed! The Ampersand compiler generates code that is typically deployed on a Docker platform. This means that deployment is instant, independent of hardware/software platforms, and headache free. |
10.4. | Rules, and the ability to change them effectively, are fundamental to improving business adaptability. |
Ampersand says: | Agreed! Adapting one rule has very often no consequence for other rules, because rules are mutually independent. That adaptation can be implemented in the software almost instantaneously. |
In this section, you will learn the basic structure of information systems according to Ampersand. By studying a simple system, you will learn how Ampersand represents such systems.
We will study an information system called "Enrollment". The purpose of that system is to enroll students for modules. Students can enroll (or be enrolled) for any module that is part of the course they take.
Try it out on an Ampersand implementation. Copy this example code, make a new script on an Ampersand system, compile it, and generate a prototype implementation from it. Run the prototype and then click on the icon "Overview" in the top-left of the screen. The application will start. Browse through the data and change things. Find out which courses, students, and modules there are and try to see what happens if you add or remove information from the system. You can use this assignment as a guide:
Who are the three students and what are the courses they take?
Is there a module HRM
?
Add, in the tab Course, the module HRM to the Management course. The system sees that the subject is unknown, and provides a green plus-sign to add it.
Each change will be saved automatically.
Note that this change is also visible in the tab Modules.
Now enroll student John
for the module Business Rules
. You can do this either in the tab Students or the tab Modules. We will later see why this is the case.
Now enroll student Peter
for the module Business Rules
.
This will trigger a message because this student does not take the course Business IT.
Click on the message to see details.
Look-up in the code below where this message is defined. It is the line that starts with RULE
. You don't have to understand the syntax at this point.
Click cancel.
Use the trash can icon to remove the course Business IT
fromSusan
in the tab Students.
This also will trigger an error message because each student can only enroll for a module in courses he has registered in. Get rid of the message by going to the "List all interfaces" in the menu bar and navigate back to the overview.
Look up in the code the definition of the RELATION takes
. The keyword [TOT]
is responsible for this message.
Note the four icons on the top-right of the screen and click on the second icon (nine dots).
Click on 'Reinstall database'
The Installer screen comes up. Click on the big red button and wait for it to turn green.
Click on 'overview' and the initial data is back.
Have a look at the code below, to find where the initial data is defined.
Have a look at the code-part at the end called INTERFACE and compare it with the screen. Note which parts you recognize. The syntax of the code is discussed in the documentation.
This information system was built by the following code:
After finishing your assignment, you have learned:
to recognize details in the source code of your information system and relate them to the information system "Enrollment" that you have been playing with;
that a rule of the business, such as "A student can only enroll for a module that is in the course the student takes" can be formalized in Ampersand.
that such a business rule can be used to constrain data in a database.
Sometimes, in describing the syntax, EBNF-like notation is used, with the following meaning:
To keep this chapter as readable as possible, we have chosen to omit some details that are irrelevant for practically all Ampersand modelers. In the very rare case that these technicalities are of interest, the reader could have a look in the sourcecode of the parser, where all EBNF statements are fully detailed in comments.
A concept statement defines a concept in natural language. A concept is a name for similar things. For example: Peter
, John
, and Barack
are things you might want to call Person
, whereas 45-NP-88
and KD-686-D
could be instances of the concept LicensePlate
.
This statement means that there exists a concept called <upper case identifier>
in the current context.
<upper case identifier>
specifies the name of the concept. It starts with an upper case character and may subsequently have any combination of upper case (ABCDEFGHIJKLMNOPQRSTUVWXYZ), lower case (abcdefghijklmnopqrstuvwxyz), digits (0123456789) and underscore (_).
<String>
defines the concept. Please describe in natural language the conditions that make an atom belong to this concept. Your definition is used by the documentation generator, which expects it to be a grammatically correct and complete sentence.
The name of a concept starts with an uppercase character.
A concept should be used for immutable concepts. E.g. use a concept Person
to express that a person will always be a person and will not change in, let us say, a table. However, don't use Employee
, because termination of an employee's contract causes a person to be an employee no longer. So employees are not immutable. To be an employee is a dynamic property, so model it as a relation.
The description will be printed in the functional specification, so please check that your definition is a complete sentence.
Concepts need not be defined. If you use a concept without a definition, Ampersand makes it for you.
For the purpose of documentation, you may state the language in which the meaning is written. You may also state in which markup you have written your meaning. Examples:
If you specify the language, Ampersand can restrict the documentation for the language you choose. Currently, you can only choose DUTCH
or ENGLISH
. The default language is English
By specifying a markup language, Ampersand interprets the text as specified. If you do not specify the markup language, your text is interpreted as restructured text. The available markup languages are LATEX
, MARKDOWN
, HTML
, and REST
. The default markup language is REStructured Text (REST).
The purpose of Ampersand is to help business engineers deliver . Correct means that the system complies demonstrably to the rules of the business. How cool is that!
Medications, a demonstrator built by TNO in Ampersand to showcase attestation on the internet. This example is undocumented.
, a site to disclose standards for electronic messaging in the sector of flexible labour. This example is undocumented.
, a tool for students to learn how to work with Ampersand. This project is documented in .
Make a conceptual analysis of your business problems to create a shared understanding. Then use the resulting data model to kick-start your application(s).
Use Ampersand as a platform for reactive programming, to deliver you from workflows and workflow models.
Be baffled by the precision with which you can formalize legal rules, and enjoy the benefits of compliance-by-design.
Experiment with rules to and cut back on red tape.
Make enterprise software adaptable by using Ampersand's software generator and reducing your programming effort to a minimum. Even complex changes, such as changes in your conceptual model (viz. data model) are brought into production quickly.
Support your own business, rather than someone else's view on your business. Designing with lets your business associates convince themselves that the system supports exactly the right rules.
Decrease maintenance cost and increase understanding, by describing goals instead of steps. Ampersand is a language, which yields simplicity without sacrificing precision.
Develop more efficiently by preventing errors instead of correcting them. Enjoy the benefits of strong and static typing. Several scientific studies show significant effects of strong and static typing on the total cost of ownership of your design. Besides, it enables Ampersand to generate efficient code.
Gain mathematical certainty of compliance. Ampersand uses relation algebra to align the IT system to the business, by exploiting its natural language interpretation alongside its technical interpretation as working software. Your claim that business stakeholders understand (solely in natural language) what the computer does (in software) can't be made more convincingly.
True low-code platforms, such as Ampersand, give you full functionality with little code. Do the and experience a full non-trivial example of an information system specified in 61 lines of code only.
Reduce risk by developing in small increments. Add constraints, user interfaces, relations, and other design elements one at a time. Generate a prototype at any intermediate stage, to try out your system long before it is finished.
Reduce risk by dividing the work into small subsystems. To isolate subsystems is easy, due to . Ampersand lets you combine subsystems into larger systems, automating the burden of combining them. Reuse design patterns to assemble systems, rather than re-invent from scratch.
Deploy quickly by building, configuring, and taking it to production automatically.
To design and build a good information system is a difficult task. Ampersand makes this easier by automating tedious coding tasks and preventing scores of errors you might make. Use it to create a wonderful festival organisation platform, your very own web shop for pedigree poodles, or the trip organiser for hiking expeditions in the Andes. It's all up to you.
Not many people can design and build good information systems. It is a difficult task. Ampersand makes your life easier by automating tedious coding tasks and preventing scores of errors you might make. Use it to create this wonderful festival organization platform, your very own webshop for pedigree poodles, or the trip organizer for hiking expeditions in the Andes. It's all up to you.
A characteristic of Ampersand is its focus on business rules. Business rules embody the agreements of people who pursue a common goal. Naturally, such rules are to be respected by every information system that supports their business. The value of Ampersand is this: once you have a precise set of rules, you have your information system. The coding of software is automated by Ampersand. So if a rule changes, you have altered it in your code in a breeze. That is why Ampersand focuses on rules.
Ampersand is a way of designing information systems for enterprises, supported by a method, a tool, and a course. These are the things you do (click on the hyperlinks to watch video clips):
Define a domain language (in Ampersand) to consolidate agreement of terms among stakeholders, using it solely for technical purposes.
Use the documented ontology that Ampersand generates to validate the agreed rules.
When you click on the blue plus-sign on the top-right side in the menu bar in your screen, you can make a new script. Clicking this opens an editor screen in which you can type your very first Ampersand script.
Next, click on the blue Compile button. When RAP4 is finished compiling your script, the compiler message should read "The script of Enrollment contains no type errors" and two blue buttons should be visible below that. Please make it a habit to read the Compiler message carefully each time you compile a script
Generate a Prototype: Click the blu button "Prototype" and when RAP3 has finished loading you will see a new link "Launch Prototype". Click the link.
Now you see the information system you have just compiled from the code. You are already familiar with the look and feel. Click the Overview button in the top-left of the screen and have a look around.
Try to generate documentation: Click on the button Diagnosis. When RAP4 is done, a link will be added below the button. Click on the button Func. spec + pictures and again a link will be added. These two functions create pdf-files with information about the code that has been compiled. During the course you can have a better look there.
During the remainder of this course you will compile and run your own scripts in this way, so it pays to familiarize yourself with it.
You are now going to change some code and view the results in RAP4. Navigate back to your script editor (wherever you are, you can always go back to it via "MyScripts" in the menu bar).
If you want to save the original script, go to MyScripts, create a new script and copy the same code in there.
Let's add the possibility to register teachers in this system:
Define a new concept with the keyword CONCEPT: CONCEPT Teacher
with a short description. Note that concept names start with an Uppercase and that all quotes need to be double quotes.
Define the relation between Module and Teacher with the keyword RELATION: RELATION providedBy[Module*Teacher]
MEANING "A module is provided by a teacher"
Note that relation names start with lowercase.
You can define an initial set of teachers and relate them to a module following the examples already available in the script. But you can also add the data later using the prototype. (Adding initial data in the script is a lot of work. There is another method, using spreadsheets. This is another topic in this tutorial.)
Add a service for the teachers in the third tab, the one for Modules. Below the codelines for "Modules" and above the line for "Course": , "Teacher" : providedBy CRUD
Save, compile, create protype, launch prototype, reinstall database and see the result in the third tab called "Modules". Note that you need to reinstall the database because the old database is still there, but the database structure has changed in the application.
Note that we have not defined any rules about teachers, so anything you fill in, is OK for this system.
Try to understand what you see in the script by making other changes, compile and inspect the changes; learn by doing. Try for instance to create a new course with modules and teachers. Demonstrate your changes to your peers and discuss the results.
After finishing your assignment, you have learned:
how to use RAP4 to write, save and compile code.
the first basic keywords of Ampersand script and their effect on the prototype.
A relation statement says that a relation exists. It introduces (defines, declares) the relation in the context that uses the relation statement.
A population statement specifies which pairs (of atoms) are in a relation.
A relation is a set that contains pairs of atoms. Over time, pairs can be inserted into or deleted from a relation, for example by a user typing data into an Ampersand application. So the content of a relation is changing over time.
When discussing relations, an arbitrary relation is referred to as , , or . To say that a pair belongs to a relation , we write or alternatively .
In this example:
contract
is the name of the relation,
Order
is the source concept of the relation,
ContractID
is the target concept of this relation, and
UNI
and TOT
are constraints of this relation.
Each relation used in Ampersand has to be declared. This means that the developer tells the system that this particular relation exists. A relation declaration can have one of the following formats:
In the declaration RELATION owner[Person*Building]
, owner
is the name and [Person*Building]
is the type of the relation. Relation names start with a lower case character, to avoid confusion with concept names. The signature of this relation is owner[Person*Building]
. The signature identifies the relation within its context. The left hand concept, Person
, is called the source of the relation and the right concept, Building
, is called the target.
All three formats define a relation by its name, its source concept and its target concept. By convention, the name of a relation is a single word that starts with a lower case letter. The source and target concepts start with an upper case letter. This convention avoids confusion between concepts and relations.
A relation statement means that there exists a relation in the current context with the specified name, source concept and target concept.
A relation statement may occur anywhere inside a context, both inside and outside a pattern.
The name, source concept and target concept together identify a relation uniquely within its context. As a consequence, the name of a relation does not have to be unique. E.g. name[Book*Name]
can be specified in the same context as name[Person*Name]
. Because they have different source concepts, these are different relations.
The <properties>
-part is meant for writing multiplicity constraints in a comma separated list between square brackets '[' and ']'. E.g. [UNI,TOT]
. The following properties can be specified on any relation r[A*B]
There are additional relations that can be specified on endo relations. An endo relation is a relation where the source and target concepts are equal. r[A*A]
.
Let's assume that we want to express that any person can live in one city only. So under this constraint "Joe Smith lives in New York" and "Joe Smith lives in Denver" cannot both be true at the same time.
In relation algebra, we say that the relation is univalent, which means that every atom in the source concept can only be paired with a single atom in the target concept. This is modeled as
A pragma is optional and is characterized by the reserved word PRAGMA
. The PRAGMA
is followed by two or three strings. It is used to construct sentences in natural language, using pairs from the actual population of a relation. A pragma specifies how we speak (in natural language) about any pair in the relation. Ampersand also uses pragmas to generate examples in the functional specification. Example of a pragma with three strings:
To use this pragma on the pair (John,Amsterdam)
results in the sentence "Student John flies the flag of Amsterdam in top."
. The two atoms are fitted in between the three strings. A pragma with two strings is identical to a pragma in which the third string is empty.
(The PRAGMA
keyword will become obsolete in a future version of Ampersand. It will be replaced by the VIEW
-statement which offers more flexibility in composing sentences.)
Example:
The PRAGMA
tells us that it makes sense to utter the phrase "Provider Mario's Pizza's has accepted order 12345."
How can I create my own information system in RAP4? Go to .
What is the conceptual model behind an Ampersand model? Go to
How can I upload from spreadsheets into my application?
Communicate with the business solely , which is a natural language.
into rules that are relevant for the information system using Ampersand-script.
Generate a of your information system for verification purposes.
to walk through user stories, test user acceptance, elicit requirements, or otherwise gain more assurance that your design is what your audience wants.
Ampersand is grounded in Relation Algebra. Scientific foundations of Ampersand have been published in the International Conference on Relation Algebraic Methods in Computer Science () from 2011 onwards.
Ampersand is a tool for rule-based design. It adheres closely to the concept of business rule as defined by the Business Rules Group. The explains the correspondence between the Business Rules Manifesto and Ampersand.
The Open University of the Netherlands has a , in which students use Ampersand for this purpose.
Ampersand is freely available as an .
Copy the code for the system enrollment from or take it from the OU course-site. The code starts with CONTEXT
and ends with ENDCONTEXT
. Paste the script in the RAP4 editor (On rap.cs.ou.nl only: you now have to click on the big blue button "beware to save your work before leaving the editer field!"). The script is now saved in RAP4.
How to describe functionality in a ?
How can I upload from spreadsheets into my application?
The optional <properties>
and <pragma>
-parts are discussed in the sequel. The <meaning>
-part is discussed .
For a full discussion of meaning, we refer to .
Operator
meaning
<foo>?
Zero or one occurrence of <foo>
<foo>+
One or more occurrences of <foo>
<foo>*
Zero or more occurrences of <foo>
& | property | semantics |
UNI | univalent | For any |
INJ | injective | For any |
SUR | surjective | For any |
TOT | total | For any |
& | property | semantics |
SYM | symmetric | For each ( |
ASY | antisymmetric | If ( |
TRN | transitive | If ( |
RFX | reflexive | For each |
IRF | irreflexive | For each |
PROP | - | shortcut for the combination of symmetric and antisymmetric. |
An information system should represent the truth. So, as a designer you must know a thing or two about truth.
Let us introduce some language to talk about truth. Consider a fact "Joe Smith lives in New York." from an Ampersand perspective. In Ampersand, we can analyse this as follows:
Let Person
and City
be concepts****
Let "Joe Smith"
be an atom of the concept Person
and "New York"
an atom of the concept City
.
Let us use the relation livesIn[Person*City]
to contain our fact.
livesIn
is the relation name and [Person*City]
is the signature of this relation.
Person
is the source of this relation and City
is the target.
If the pair ("Joe Smith","New York")
is an element of this relation, Ampersand considers the statement "Joe Smith" livesIn "New York"
to be true. So all pairs in a relation represent facts, i.e. true statements.
Ampersand takes a pragmatic stance on truth: You model only things that make sense to the business. This video clip illustrates the distinction between sensible and senseless statements. A sensible statement (we say: "It makes sense.") is a statement that can be true or false. Sentences that are not sensible (we can say: it is non-sense) are to be avoided. The Ampersand type system helps you to make sensible statements only.
Truth always has context. If we say "Jack was married to Jackie", this statement is true in a context where "Jack" refers to the 35th president of the United States, John F. Kennedy. However, this statement is not true in a context where there is no Jack. And in a context where marriage doesn't exist, this statement makes no sense.
MEANING can be used with CONCEPT-statements, RELATION-statements, and RULE-statements, to define the meaning of your concepts, relations, and rules.
A meaning is optional and is characterized by the reserved word MEANING
. It specifies the meaning of a concept, a relation, or a rule in natural language. The meaning is used to generate documentation and is printed in the functional specification. A <meaning>
can be any text, starting with {+
and ending with +}
e.g.
The optional <language>
is specified as
IN ENGLISH
or
IN DUTCH
.
Example :
This is a way to override the default language (which is English).
Sometimes you need formatting in the meaning, such as dotted lists, italics, or mathematical symbols. For this purpose you have a choice in which syntax you specify the meaning. The optional <markup>
is one of :
REST
(Restructured text. This is the default)
HTML
LATEX
MARKDOWN
Example :
Ampersand uses Pandoc to offer a choice for your markup. See pandoc.org for details.
The purpose of a rule is to constrain data. Refer to the chapter about rules in the tutorial for examples and a practice-oriented explanation.
A rule statement defines something that should be true. It does not define the enforcement.
A <rule>
has the following syntax:
Terms and operators are discussed in a separate section:
A <label>
is optional. It can be a single word or a string (enclosed by double brackets) followed by a colon (:
).
The meaning of a rule can be written in natural language in the Meaning part of the RULE statement. It is a good habit to specify the meaning! The meaning will be printed in the functional specification. The meaning is optional.
The <text>
part is where the the meaning is written down. It is enclosed by {+
and +}
and may be spread across multiple lines. If you need specific markup, turn to this page for a full explanation.
Messages may be defined to give feedback whenever the rule is violated. The message is a string. When you run your prototype this is printed in a red box when the rule is violated. You will see the violations by clicking on that message.
A violation message can be constructed so that it gives specific information about the violating atoms:
Every segment must be of one of the following forms:
TXT
String
SRC
Expression
TGT
Expression
A rule is violated by a pair of atoms (source, target). The source atom is the root of the violation message. In the message, the target atoms are printed. With the Identity relation, the root atom itself can be printed. You can use an expression to print other atoms. Below two examples reporting a violation of the rule that each project must have a project leader. The first prints the project's ID, the second the project's name using the relation projectName:
VIOLATION ( TXT "Project ", SRC I, TXT " does not have a projectleader")
VIOLATION ( TXT "Project ", SRC projectName, TXT " does not have a projectleader")
By default, rules are invariant rules. By preceding the rule statement with a role specification for this rule, the rule becomes a process rule.
tbd
Most things in your model are in it for a reason. To document these, you should use the PURPOSE statement.
PURPOSE
<type of thing>
<name>
<language>?
<markup>?
{+
<anything>
+}
Where <type of thing>
and <name>
are the type and name of the thing that is refered to. This could be one of: CONCEPT
, RELATION
, RULE
, IDENT
, VIEW
, PATTERN
, INTERFACE
, CONTEXT
The optional and can be used to override the settings for language and markup. If omitted, these are inherited from the pattern of context where the PURPOSE statement is specified in.
Examples:
When defining the purpose of a relation, make sure that Ampersand can identify the relation unambiguously. If you have multiple relations accountOwner
, add the signature to disambiguate it. For instance:
For the purpose of documentation, you may state the language in which you write a purpose. You may also state in which markup language you use. Examples:
If you specify the language, Ampersand can restrict the documentation for the language you choose. Currently, you can only choose DUTCH
or ENGLISH
. The default language is English.
By specifying a markup language, Ampersand interprets the text as specified. If you do not specify the markup language, your text is interpreted as REStructured Text (REST
). The available markup languages are LATEX
, MARKDOWN
, HTML
, and REST
.
A classify statement is also called a specialization. It specifies that atoms of one concept are atoms of another concept as well. You can use it to buils classifications like Linnaeus did.
In a specialization, e.g. CLASSIFY Sedan ISA Car
, we call the first concept (Sedan
) the specific concept and the second (Car
) the generic concept. The meaning of a specialization is that every atom from the specific concept is an atom from the generic concept as well. So every (atom that is a) Sedan is a Car as well.
So in general: CLASSIFY
ISA
means: .
To save some writing, you may specify
This means exactly the same as
A specialization is a static relationship. If you want to say that a student is a person, please consider whether you want this to be static. If a person can enroll to become a student, or graduate or drop out to become non-student again, the dynamics of that cannot be captured in a specialization. Use a relationship instead to model the state of being a student.
E.g. RELATION student[Person*Enrollment]
By adding and removing pairs to that relation, it continuously reflects which persons are a student.
To represent a real-world thing in an information system context, you use atoms.
An atom refers to an individual object in the real world, such as the student called "Caroline". But what if there are three different Carolines? What does it mean to say: "Caroline has passed the exam for Spanish Medieval Literature."? This sentence might be true for one Caroline, but false for the others. Clearly, to avoid ambiguous sentences, an atom must identify exactly one real-world object, no more, no less. Or rather, it suffices that the atom identifies one object within the context in which we are working: if the context is a group with only one Caroline, there will be no ambiguity. Similarly, ABBA is unique among all pop groups in the world; there ought to be only one building permit with number 5678; etcetera.
"Caroline"
, 5
, 1917-11-07
48
, 10.34
, 2.
, .001
, -125
, +5.33333
, 2.5E2
, 5E-3
The syntax of atoms is largely taken from ISO8601 and corresponds to the syntax of SQL and Excel. (Acknowledgement: the following text was adapted from Wikipedia)
Date and time values are ordered from the largest to smallest unit of time: year, month (or week), day, hour, minute, second, and fraction of second. The lexicographical order of the representation thus corresponds to chronological order, except for date representations involving negative years. This allows dates to be naturally sorting|sorted by, for example, file systems.
Each date and time value has a fixed number of digits that must be padded with leading zeros.
Representations can be done in one of two formats - a basic format with a minimal number of separators or an extended format with separators added to enhance human readability. The separator used between date values (year, month, week, and day) is the hyphen, while the colon is used as the separator between time values (hours, minutes, and seconds).
For reduced accuracy, any number of values may be dropped from any of the date and time representations, but in the order from the least to the most significant. For example, "2004-05" is a valid ISO 8601 date, which indicates May (the fifth month) 2004. This format will never represent the 5th day of an unspecified month in 2004, nor will it represent a time-span extending from 2004 into 2005.
If necessary for a particular application, the standard supports the addition of a decimal fraction to the smallest time value in the representation.
Atoms are represented in an SQL database. For this purpose, every atom has a type (sometimes called the technical type). The representation in SQL is given in the following table.
The last column, eq, tells whether Ampersand implements equality on these types. If equality is not defined, the operators \/
, /\
, -
, \
, /
, ;
, and <>
cannot be used.
The distinction between closed and open types is relevant in the following situations:
The complement of a relation, -r[A*B]
, is defined only if both A
and B
are closed.
The full relation, V[A*B]
is defined only if both A
and B
are closed.
A service INTERFACE X : e
requires that the target of e
is closed.
Violations are currently signaled at runtime, but future versions of Ampersand will signal these violations at compile time.
Every atom whose atomic type is marked "yes" in the column "eq" can be compared for equality. For all other atoms, equality is not defined.
The following Ampersand statement declares the atomic type of a concept:
e.g.
If Person
and Company
are both LegalEntity
, then both of them will be implicitly declared as ALPHANUMERIC
too.
This page describes the notion of term. Its subpages provide several interpretations of terms, all of which are valid so you can use each interpretation at your own discretion.
The purpose of a term is to compute pairs that constitute a relation. We use operators to assemble terms from smaller terms, to express in formal language precisely what is meant in the natural language of the business. The smallest term is a single relation.
We noticed that our readers have different backgrounds. They have different preferences about the way we explain the operators in Ampersand. Some prefer an explanation in logic, others in algebra, and still others in set theory. So we decided to explain the operators in many different ways simultaneously, hoping that one of them suits your preference.
A term is a combination of operators and relations. Its meaning is a set of pairs, which is in fact a newly created relation. The word "expression" may be used as a synonym for "term" in the context of Ampersand.
owner
r;s~
I /\ goalkeeper;goalkeeper~
destination;"Algarve" |- spoken;"Portugese"
Every term is built out of relations, which are combined by operators. An term has one of the following 8 syntactic structures
Operators
The operators come in families. We advise novices to study only the rule operators, boolean operators and relational operators. There is a wealth of things you can express with just these operators. The residual operators seem harder to learn and the Kleene operators are not fully implemented yet. You can click the hyperlink to navigate to the semantics of each family.
Operators with different binding power may be used in the same term without brackets, because the binding power tells how it is interpreted. For example, means because has a higher binding power than .
Operators with the same binding power must be used unambiguously. For example: means something different than . In such cases Ampersand insists on the use of brackets, so readers without knowledge of the binding powers of the operators can read a term unambiguously.
Repeated uses of an associative operator does not require brackets. So is allowed because is associative.
When coding in Ampersand, these operators are typed with characters on the keyboard. The following table shows the operators in math and their equivalent in code:
To say things such as "the name of the owner", we want to string together multiple relations (viz. name
and owner
). Relational operators allow us to make such statements.
A relation can be altered by swapping the elements of every pair in the relation. Mathematically, is a different from . This operation is called the converse operator. It produces a new relation from an existing one. It is denoted by writing \smallsmile\ (pronounced 'wok' or ’flip’) after the relation name. This is how converse is defined:
If has type, then r\smallsmile\ has type .
The composition operator is denoted by a semicolon between two terms. It is pronounced as 'composed with'. Let us take a look at composed with . Let and be two relations, with the target of r being the same as the source of s. Then the composition of and is defined by:
If has typeand has type, then has type .
This page shows how you can type boolean (and other) operators in your Ampersand script.
Would you like a different explanation of the relational operators? This page explains the relational operators in terms of set theory. This page explains them in natural language. Click here for some algebraic rules about relational operators.
This section introduces the tool you will use during the course: RAP4. This tool stores Ampersand-scripts in which you can specify, analyze and build information systems. It runs on the internet, so all you need is a browser. Click here if you are a student of the Open University or here if you are not to start using it.
RAP4 is under development. New releases can be done daily. If you find problems with the software, please notify your tutor. If the software is to blame, we will ask you to make an issue in RAP's issue registration system. This way you can help improve Ampersand's tooling, for which the Ampersand team is very grateful.
During the remainder of this course, you will compile and run your own scripts in this way, so it pays to familiarize yourself with RAP4.
RAP4 keeps your work together under a student number. So click on the button 'login' on the left top of the screen.
Register with your own student number and e-mail. Create a password. Your student number is your account, but you can fill in a name. This name should not exist yet, so a green plus sign will appear. Click on it and your name is added to the database.
Notes:
About the user interface: Each time you change fields (e.g. using Tab), the form is updated. But you will not see what is the next active field. You may have to click again to ensure that your cursor is in the right field.
This application has no connection with the OU database, so be careful to fill in the right number on this and future occasions.
This login-screen is also the screen to logout later.
When RAP4 is updated, probably your account will be reset. You need to register again. We will inform you in the unlikely event that this happens during a course.
After logging in, you will see your login name or student number in the RAP4 window.
In the menu bar you will find:
A horn symbol. Just ignore that for now, because it contains debug settings.
a 3x3 grid, which contains some Ampersand extensions.
a plus (+) symbol. That is important, because it lets you create a new Ampersand script.
a person-like symbol. It lets you switch on/off some role dependent functionalities. If you have more than one role, just try it out and watch functionalities appear and disappear from the menu bar. As a student you typically have just one role (User) so this button is not very relevant for you.
Notes:
After a period of not using RAP4, you will be logged out automatically. In the current system, you may get errors or weird behaviour. Please navigate back to the login screen to check whether you are still logged in.
how can I make and run my first Ampersand script.
How can I describe functionality in a conceptual model?
How can I upload bulk data from spreadsheets into my application?
where to find the Repository for Ampersand Projects (RAP4)
to register yourself in RAP4
RAP4 is under development. You can expect to find teething problems (kinderziektes) in the software. Please notify us by making an issue in our issue registration system. This way you can help improve Ampersand's tooling, for which the Ampersand-team is very grateful.
This chapter describes the full language Ampersand. Please use it as a reference rather than an introductory course.
Watch this clip to learn how we use the words atom, concept, and relation. Below is a list of other words with a specific meaning in Ampersand.
Syntactic definitions are given where the underlying notions (e.g. rule, relation, pattern, etc.) are discussed. The metasyntax is singled out on a separate page. Because terms are defined in relation algebra, their semantics are explained in various ways to suit the background of each individual reader. Terms are the only algebraically defined things.
This section is organized by discussing each notion in isolation. Hyperlinks are added in the text to let the reader navigate on her own. The text is suitable for reference purposes, so there is no preferred order in reading.
Semantics tell us about meaning. About how to interpret terms and their operators.
We present the semantics of terms in 5 different (but equivalent) ways: one explanation in terms of logic, one in set theory, one in terms of axioms (algebraically), one in natural language, and one visual explanation. These ways are equivalent, so you can interpret a term in any of the presented ways. Any way will do; take your pick!
(the pages without hyperlinks are yet to be made).
To say things such as "the name of the owner", we want to string together multiple relations (viz. name
and owner
). Relational operators allow us to make such statements.
The meaning of relational operators and is best explained by means of examples.
Assume we have a relation, label[Contract*Colour]
, which contains the colour of labels on contracts. A fact "1834" label "blue"
means that contract 1834 has a blue label.
Also assume another relation stored[Contract*Location]
, which gives the location where a contract is stored. Fact "1834" store "cabinet 42"
means that contract 1834 is stored in cabinet 42.
A relation can be altered by swapping the elements of every pair in the relation. Mathematically, is a different from . In natural language, however, the meaning does not change. So if"1834" label "blue"
means that contract 1834 has a blue label, "blue" label~ "1834"
also means that contract 1834 has a blue label.
The sentence: "All contracts with a blue label are stored in cabinet 42." is represented as "blue" (label\stored) "cabinet 42"
. Literally it says: For every contract, if it has a blue label, then it is stored in cabinet 42.
The sentence "A contract with a blue label is stored in cabinet 42." can be represented as "blue" (label~;stored) "cabinet 42"
. Literally it says: There is a contract that has a blue label and is stored in cabinet 42.
The natural language translation for b r~ a
is the same as language translation for a r b
.
To say things such as pair ("peter","macbook")
is either in relation ownsa
or wantsa
, requires us to use boolean operators , , and .
Let us explain the meaning of relational operators , , and by means of examples.
Assume we have a relation, ownsa[Person*LaptopType]
, which contains the persons who own a particular type of laptop. A fact "peter" ownsa "macbook"
means that Peter owns a MacBook.
Also assume another relation wantsa[Person*LaptopType]
, which contains the persons who want a particular type of laptop. A fact "peter" wantsa "macbook"
means that Peter wants a MacBook.
The sentence: "Peter owns a MacBook or Peter wants a MacBook." is represented as
"peter"
(ownsa
wantsa
) "macbook"
.
The sentence: "Peter owns a MacBook and Peter wants a MacBook." is represented as
"peter"
(label
colour
) "macbook"
.
The sentence: "Peter owns a MacBook and Peter does not want a MacBook." is represented as
"peter"
(label
colour
) "macbook"
.
are used when "" is involved.
right residual : . In other words: is in the right residual of and means that for every , pair is in relation implies that pair is in .
left residual : . In words: is in the left residual of and
means that for every pair is in relation implies that pair is in .
diamond: . In words: For every , both and are true or both are false.
shows how you can type boolean (and other) operators in your Ampersand script.
Would you like a different explanation of the residual operators? explains them in natural language. for visualized examples about residual operators.
Family | binary operators | binding power | unary operators | binding power |
---|---|---|---|---|
operator name | code | math | remark |
---|---|---|---|
There is a pattern to this. A computer can generate a literal translation from the formula to natural language. However, that translation looks clumsy, verbose and elaborate. It is up to you to turn that in normal language. For examples . The systematic translation is given in the following table:
Would you like a different explanation of the relational operators? explains the relational operators in terms of set theory. An explanation in logic is given . for some algebraic rules about relational operators.
There is a pattern to this. A computer can generate a literal translation from the formula to natural language. However, that translation looks clumsy, verbose and elaborate. It is up to you to turn that in normal language. For examples . The systematic translation is given in the following table:
Would you like a different explanation of the relational operators? explains the boolean operators in terms of set theory. An explanation in logic is given . for some algebraic rules about boolean operators. If you want to see it explained visually in Venn-diagrams, .
type
purpose
SQL
closed
eq
ALPHANUMERIC
to represent strings of short length, i.e. less than 255 characters
VARCHAR(255)
yes
yes
BIGALPHANUMERIC
to represent large strings of limited length, i.e. less than 64 kb
TEXT
no
yes
HUGEALPHANUMERIC
to represent strings of arbitrary length
MEDIUMTEXT
no
no
PASSWORD
to represent passwords in a secure way
VARCHAR(255)
no
yes
BINARY
to represent uninterpreted binary data of short length
BLOB
no
no
BIGBINARY
to represent large binary data of limited length
MEDIUMBLOB
no
no
HUGEBINARY
to represent large binary data of arbitrary length
LONGBLOB
no
no
DATE
to represent dates compatible with ISO8601
DATE
yes
yes
DATETIME
to represent timestamps compatible with ISO8601
DATETIME
yes
yes
BOOLEAN
to represent True and False values
BOOLEAN
yes
yes
INTEGER
to represent positive and negative whole numbers in the range [-2^63..2^63 -1]
BIGINT
yes
yes
FLOAT
to represent floating-point numbers compatible with ISO8601
FLOAT
no
no
Object
to represent a key value for objects; it is not meant to be visible to end-users.
VARCHAR(255)
yes
yes
all other atoms
VARCHAR(255)
yes
yes
Word
Meaning
Example
Purpose
an indivisible item
"Peter"
to represent a thing
a name to categorize similar items
Person
Pair
two atoms: a source and a target atom
("Ida",5)
to state that two atoms are related
a set of pairs that is identifyable in a context by its name and type
r[A*B]
to build true statements and store pairs persistently in an application
a constraint, which is supposed to remain satisfied.
r;s |- t
to provide meaning in a given context
satisfy
A rule is satisfied (in a context) if the data (in that context) do not cause any violation of that rule.
to calculate violations at run-time helps users do the right things
a set of rules
PATTERN
...
ENDPATTERN
to gather rules that belong together for reusing them in different contexts
Population
a set of pairs in a context
POPULATION r[A*B] CONTAINS [ ("Ida",5), ("Bob",1) ]
to represent the facts (i.e. true statements) in an information system
a population together with a set of rules that are satisfied by the population.
CONTEXT
...
ENDCONTEXT
to maintain a consistent representation of a real life situation
View
A set of pairs that can be shown to users in a particular formulation.
to represent facts
A structure meant for "the outside world" to communicate with the system and possibly change the population.
INTERFACE Request FOR Customer
to let "the outside world" communicate with the system in a given context and possibly change its population
Multiplicity
A predefined property of a relation
UNI
, TOT
, SUR
, INJ
to constrain a relation with predefined properties
A combination of relations and operators that satisfy the Ampersand syntax
r;s-t
to express rules
Operator
a symbol used in combining terms into other terms.
-
, ~
, \/
, /\
, -
, ;
, \
, /
, |-
, =
to express more complex rules.
A rule that defines specialization between two (or more) concepts.
CLASSIFY A ISA B
To specify a building block for a classification hierarchy.
Role
A name for a group of people
ROLE Customer MAINTAINS paymentObligation
to talk about users without having any users
rules
1 (weakest)
2
prefix
4
postfix
3
Kleene
postfix
equivalence (equal)
=
use only in a rule
inclusion
|-
use only in a rule
intersect
/\
associative, commutative, idempotent
union
\/
associative, commutative, idempotent
difference (minus)
-
complement
-
in code: Prefix; in math: Overline
compose
;
associative
converse (flip)
~
postfix
left residual
/
right residual
\
diamond
<>
relational product
!
associative
cartesian product
#
deprecated
reflexive transitive closure
*
in code: not implemented; in math: Postfix
transitive closure
+
in code: not implemented; in math: Postfix
The boolean operators of Ampersand behave as one would expect in any boolean algebra. Union () and intersection () are both idempotent, commutative, and associative operators. In Ampersand we use a binary difference operator over with the usual semantics: . The (more customary) complement operator is a partial function, because Ampersand supports heterogeneous relation algebra.
The operator (union) satisfies the following axioms:
(commutativity of )
(associativity of )
(idempotence of )
The difference is the smallest relation that satisfies . Smallest means: If there is a for which , this implies that .
The intersection is defined as:
The complement operator is defined as . The type comes from the term(s) in which is embedded. If that type does not exist or if it is ambiguous, Ampersand will refuse to compile with an appropriate error message.
When a is used in a term, it stands for the set of pairs it contains at the moment it is evaluated. That set (also referred to as the contents of the relation) can change over time as users add or delete pairs from it.
When a relation is used in a term, we can simply use its name if that is unambiguous. For instance the name owner
refers to RELATION owner[Person*Building]
if that is the only relation the ampersand-compiler can link it to. In some cases, however the name alone is ambiguous. For example if there are two relations with the same name and different signatures. In such cases Ampersand will try to infer the type from the context. That however does not always succeed. In such cases, Ampersand generates an error message that asks you to remove the ambiguity by adding the correct type.
If a pair is an element of a relation , we write . Alternatively we may write .
For every concept , the term represents the identity relation. It is defined by:
The type of is . In Ampersand code you write I[C]
.
For every pair of concepts and the term represents the complete relation. It is defined by:
A relation is by definition a subset of the Cartesian Product of the source and target sets. So, if two different relations r and s are defined on the same source A and target B, then the ordinary set operators can be applied to produce a new relation.
intersection : is the set that contains the elements that are contained in relation as well as in , or
union : is the set that contains all elements that are contained either in relation or in , or
difference : is the set that contains the elements of relation that are not contained in , or
The complement (or negation) of a relation is defined by means of the difference operator:
complement : If is defined as , then is the set of all tuples in (the Cartesian product) that are not contained in . So
Note that the complement is defined in terms of and . So, two relations with the identical population yet a different type may have different complements.
shows how you can write these things in your Ampersand script.
Would you like a different explanation of the boolean operators? explains the boolean operators in logic.
To say things such as "the name of the owner", we want to string together multiple relations (viz. name
and owner
). Relational operators allow us to make such statements.
A relation that contains pairs of the form can be altered by swapping the elements of every pair in the relation. Mathematically, is a different from . This operation is called the converse operator. It produces a new relation from an existing one. It is denoted by writing (pronounced 'wok' or ’flip’) after the relation name. This is how converse is defined:
If has type , then has type .
The composition operator is denoted by a semicolon ; between two terms. It is pronounced as 'composed with', in this case: composed with .
The composition operation is defined as follows: Let and be two relations, with the target of r being the same as the source of s. Then the composition of and , is a relation with signature
Would you like a different explanation of the relational operators? explains the relational operators in logic. explains them in natural language. for some algebraic rules about relational operators.
For a visual presentation of the semantics of terms, we use .
Consider two relations: traveler[Trip*Person]
and dest[Trip*Destination]
. The first relation tells which persons have traveled on which trip. The diagram shows this as red dashed lines. The second relation links trips to destinations. It is depicted by dotted blue lines in the diagram.
Each pair (fact) in the diagram can be written as a fact in two ways, using the converse operator:
To say things such as "the name of the owner", we want to string together multiple relations (viz. name
and owner
). Relational operators allow us to make such statements.
There are two relational operators: the converse () and the composition (semicolon ). This page discusses the most important laws about these operators.
There are two things you should know about the converse operator. The first is that the converse of the converse gives you the relation itself, whatever that relation may be:
The second thing you should know is that arguments switch places if the converse is brought outside (or inside) brackets
The composition operator is denoted by a semicolon (;) between two terms. It is pronounced as 'composed with', in this case: composed with .
Composition is associative, which means:
Consider two relations: authorized[Account*Person]
and beneficiary[Account*Person]
. The first relation tells which persons are authorized to which accounts. The diagram shows this as red dashed lines. The second relation tells which persons stand to benefit from which accounts.. It is depicted by dotted blue lines in the diagram.
This diagram gives an example population of the relations authorized[Account*Person]
and beneficiary[Account*Person]
. Bob is authorized for account DE9382991 and Ann is authorized for account RS746620. Carl stands to benefit from account NL19RABO03992844 and Ann stands to benefit from account RS746620. Formally, we say:
By combining the relations authorized
and beneficiary
, we can derive the following true statements.
A different way to state the same is:
and
, , and
, , and
, , and
and
shows how you can write these things in your Ampersand script.
The type of is . In Ampersand code you write V[A*B]
.
Would you like a different explanation of the primitive terms? explains the primitive terms in logic. for the explanation of primitive terms in natural language.
From the diagram, we assume that each pair represents a true statement (i.e. a fact). The statements are given both formally and in natural language. The elaborate version is a literate translation of the . The ordinary version tells the same in a more human sounding manner.
The meaning stays the same, no matter how you place the brackets. So Ampersand lets you omit brackets entirely. You may write instead of or .
Composition has a left and a right identity. Let be a relation, then
shows how you can write these things in your Ampersand script.
Would you like a different explanation of the semantics of the relational operators? for an explanation in sets. explains them in natural language. explains the relational operators in logic.
Would you like a different explanation of the boolean operators? explains them in set theory. for the semantics of the boolean operators in algebra. you get their definitions in logic.
Formally
Natural language template
a (r;s) b
There exists an x : if a r x
then x s b
.
b r~ a
a r b
.
PURPOSE
-statements abundantlyThe purpose of a PURPOSE
-statement is to explain why something exists. Readers of your script will understand the script ten times better if they know why things exist. A good practice is not to cut corners and specify your purposes carefully and for as many things as you can.
Managing requirements can be difficult when different stakeholders have different concerns, individual users have strong opinions of their own, requirements are changing over time, or users are unable to articulate requirements when you most need it.
Now, let us assume that hurdle is taken and you have an approved list of requirements. How does this differ from specifications? In Ampersand, you state things as they will be built. A statement in Ampersand specifies your information system precisely. If you generate a system directly from your Ampersand script, the resulting system will help users to keep all rules satisfied. If software engineers build the system to specification, they must guarantee nothing less.
Requirements tell what users say they want. Specifications define unambiguously what to build. So write prose in your requirements and write Ampersand as your specification.
The pitfall is to mistakenly use the list of requirements as specifications. This is not uncommon, so be warned. Well-known consequences are confusion among software engineers, scope creep, and project overruns. Failure to make this distinction is an early warning for project failure.
A working Ampersand prototype and an understandable specification document are compelling evidence of the completeness of your specification. Especially if both have been generated from the same Ampersand script. Fortunately, requirements articulation takes a while so in many cases you can have your specification done by the time the list of requirements is approved. This means you can make the specifications as requirements are developing, not causing any delays other than needed for the requirements.
Making a good Ampersand script is difficult. Working in pairs increases your speed for a number of reasons:
you learn from each other. Switch pairs every now and then, if possible.
Developing thoughts works better and faster if you work together. Develop thoughts by discussing, challenging, and trying things in practice.
The ontology serves to codify language. Don't hesitate to change it as insights develop. Especially database builders who are careful to change their data models might have to acquire new reflexes, as for them the ontology may feel like a data model.
Start with the tiniest thing that works. As you expand it, see to it that it stays working. Taking tiny steps, compile and run eaoch one before taking the next step. Keep an eye on your data model as your model grows. And run a diagnosis every now and then.
Work towards things that work in every situation without exception. Leave out frills and fringe, because they will hinder future reuse. Do not hesitate to start over (refactor), because your design usually gets better.
Consider each choice and every decision you make carefully from a maintainer's perspective. Will your code be adaptable in five years' time, when you, your team, and all other stakeholders have been replaced by others?
More general solutions are more widely applicable, but also more abstract. More specific solutions are easier to understand because they are more concrete. Choose the right abstraction level, keeping your audience in mind.
Doing things right the first time pays off.
Names should remind the reader of the intended meaning. For that to happen, describe meanings concisely and precisely and choose short names that will remind readers of that meaning.
Rules without purpose may block transactions without proper cause, frustrating your user. Or they may produce avoidable work for them. With rules, less is better. Focus on rules that are strictly necessary.
Formally
Natural language template
a r b
or a s b
.
a r b
and a s b
.
a r b
and nota s b
.
Category
Logic
Sets
Axioms
Natural Language
Visual
primitive terms
axioms
visual
boolean
relational
residual
sets
axioms
products
logic
sets
axioms
natural language
visual
Consider two relations: traveler[Trip*Person]
and dest[Trip*Destination]
. The first relation tells which persons have traveled on which trip. The diagram shows this as red dashed lines. The second relation links trips to destinations. It is depicted by dotted blue lines in the diagram.
From this diagram, we can tell which statements are true (i.e. facts). The statements are given both formally and in natural language. The elaborate version is a literate translation of the . The ordinary version tells the same in a more human sounding manner.
The following statements do NOT follow from the population shown in the diagram:
To keep this chapter as readable as possible, we have chosen to omit some details that are irrelevant for practically all &-modelers. In the very rare case that these technicalities are of interest, the reader could have a look in , where all EBNF statements are in comments.
This page is meant as a reference for syntactical details and conventions, reserved words, etc.
The most effective way to learn Ampersand's syntax is to copy from existing scripts. This is learning by examples. This reference chapter is suitable to check things, and less suitable for learning.
Ampersand has reserved words, such as RELATION
, CONTEXT
, CONTAINS
. All reserved words are written in capital letters. They are introduced on the fly. You will find an exhaustive list of reserved words at the end of this page.
Untyped atoms are written between double quotes, e.g. "Peter"
or "KD-686-D"
. If you want to introduce a double quote inside an atom, escape it with a backslash, e.g. "the symbol \" is called double quote"
.
Numeric atoms always start with a digit, e.g. 4711
or 75.88E3
. The boolean atoms are TRUE
and FALSE
. Dates and timestamps follow the Excel-syntax, e.g. ??? The atom _SESSION
indicates the current user session, and is an instance of concept SESSION
. It is used in services.
Brackets must always match. For terms, we use round brackets (
and )
. For populations and services we use square brackets [
and ]
.
Constructs that contain ampersand statements are contexts and patterns. They always come in pairs: PATTERN
and ENDPATTERN
, and CONTEXT
and ENDCONTEXT
.
White space characters (spaces, tabs, CRLF) are meaningless. You can use them freely to layout your script in a way that helps you to recognize its structure.
A comment on a single line starts with --
. Everything after a --
symbol is ignored until the line ends. Multiline comments are wrapped between comment brackets {-
and -}
. Multiline comments may be nested.
Identifiers always start with a letter. Concepts start with a capital letter, as in Person
, Case
, A
, and Order
. Relation names start with a lower case letter, as in contains
, attr
, sessionLogin
, or r
.
terms are combined with operators. Binary operators may require brackets to avoid ambiguity. To save writing unneccessary brackets, some precedence rules are in place.
Within an operator category, you must place brackets to disambiguate. E.g. r/\s\/t
is not allowed. You have to write either (r/\s)\/t
or r/\(s\/t)
. Across categories, you may omit brackets because a higher precedence binds stronger. So r;s\/t
means (r;s)\/t
. (Note that (r;s)\/t
and r;(s\/t)
have different meanings). Associative operators (\/
, /\
, ;
) need not be disambiguated with brackets. So r\/s\/t
and (r\/s)\/t
and r\/(s\/t)
all mean exactly the same.
Keywords in Ampersand are always written in CAPITALS.
Keywords for the main structure of the code
ENDCONTEXT
ENGLISH
DUTCH
META
THEMES
ENDPATTERN
PRAGMA
UNI
INJ
SUR
TOT
SYM
ASY
TRN
RFX
IRF
PROP
CONTAINS
RULE
MESSAGE
VIOLATION
TXT
SRC
TGT
I
V
ONE
ROLE
MAINTAINS
Keywords for documentation
REF
REST
HTML
LATEX
MARKDOWN
INTERFACE
FOR
LINKTO
BOX
Keywords for identities
Keywords for views
VIEW
ENDVIEW
DEFAULT
TEMPLATE
HTML
Keywords for generalisations:
CLASSIFY
ISA
IS
Keywords for TType:
REPRESENT
TYPE
ALPHANUMERIC
BIGALPHANUMERIC
HUGEALPHANUMERIC
PASSWORD
BINARY
BIGBINARY
HUGEBINARY
DATE
DATETIME
BOOLEAN
INTEGER
FLOAT
AUTOINCREMENT
Reserved words for values of atoms:
TRUE
FALSE
--for booleans
_SESSION
Reserved words for concepts
ONE
SESSION
Experimental keywords:
SERVICE
EDITS
Deprecated keywords:
SPEC
KEY
PROCESS
ENDPROCESS
Contexts exist in Ampersand for the purpose of dealing with . Within one context there may be no contradictions.
Any statement can be true in context only. Within one context, there are no contradictions. As facts are true statements, we say that facts must exist inside a context.
Examples of contexts:
a single lawsuit in which all case data is contained;
the financial administration of a repair shop;
the life insurance department of a bank.
The world is full of contradictions. Examples:
Bob's personal income over March 2013 according to Bob's employer differs from Bob's personal income over March 2013 according to the National Tax Authority. (To resolve this, we must distinguish between the context of Bob's employer and the context of the National Tax Authority.)
The police can be convinced that Peter X commited the crime, yet his attorney is convinced he is innocent. (To make sense of the situation, a judge distinguishes the reasoning of the defense from the reasoning of the prosecution as different contexts. In fact, the judge will construct her own context to create the verdict )
A computer system can tell that the person with social security number 721-07-4426 was born on April 27th, 1943, while the same computer system tells in another screen that this person was born on May 3rd, 1952. This is inconsistent, because every person has only one birth date. (This situation should be reported as a software mistake.)
A context is specified by the context elements between the keywords CONTEXT
and ENDCONTEXT
. A context has a name. You can optionally specify the language and markup (see below).
To tell Ampersand what language your context is in, you can append a language directive to your context. Currently English and Dutch are supported. To do so, directly following the name of your context, you can specify
Where <language>
can be ENGLISH
or DUTCH
.
Directly following the optional language definition, you can optionally specify the format of texts in your PURPOSE
statements and MEANING
blocks. This allows you to use your favourite markup language within Ampersand, as long as it is one of REST
(Restructured Text), HTML
, LATEX
or MARKDOWN
. If you specify one of these words in your CONTEXT
definition, that value will be the default markup of all purposes and meanings in your context.
A context may contain different types of statements. The order of statements in a context is irrelevant for the software that Ampersand generates. However, the order is maintained when documentation is generated.
A concept statement defines a concept in natural language. A concept is a name for similar things. For example: Peter
, John
, and Barack
are things you might want to call Person
, whereas 45-NP-88
and KD-686-D
could be instances of the concept LicensePlate
.
This statement may occur anywhere within a context, either inside or outside a pattern.
This statement means that there exists a concept called <Uppercase identifier>
in the current context.
<Uppercase identifier>
specifies the name of the concept.
String
contains a definition of the concept. This definition is used by the documentation generator, which expects it to be a grammatically correct and complete sentence.
String?
is an (optional) reference to the source of the definition. It is meant for traceability.
The name of a concept starts with an uppercase.
A concept should be used for immutable concepts. E.g. use a concept Person
to express that a person will always be a person and will not change in, let us say, a table. However, don't use Employee
, because termination of an employee's contract causes a person to be an employee no longer. So employees are not immutable. To be an employee is a dynamic property, so model it as a relation.
The description will be printed in the functional specification, so please check that your definition is a complete sentence.
Concepts need not be defined. If you use a concept without a definition, Ampersand defines it for you (regardless of whether you defined it or not).
The module system in Ampersand is currently being developed. It isn't yet in the main branch. This page is being created as work progresses.
See for details.
An Ampersand specification consists of a CONTEXT file and a set of Modules. A module in Ampersand serves the dual purpose of controlling name-spaces and ordering definitions in multiple files.
We have been inspired by the .
To tell Ampersand what language your module is in, you can append a language directive to your module. Currently English and Dutch are supported. To do so, directly following the name of your context, you can specify
Where <language>
can be ENGLISH
or DUTCH
.
Directly following the optional language definition, you can optionally specify the format of texts in your PURPOSE
statements and MEANING
blocks. This allows you to use your favourite markup language within Ampersand, as long as it is one of REST
(Restructured Text), HTML
, LATEX
or MARKDOWN
. If you specify one of these words in your CONTEXT
definition, that value will be the default markup of all purposes and meanings in your context.
An IMPORT statement contains a reference to another module and contains information of what definitions are imported from that module together with information about possible name-changes.
A module may contain different types of statements. The order of statements in a context is irrelevant for the software that Ampersand generates. However, the order is maintained when documentation is generated.
This chapter discusses the and the in the following sections.
Would you like a different explanation of the residual operators? explains them in natural language. for the explanation of residual operators in logic.
Keywords for
Keywords for
Keywords for
A context represents a set of , which is the meaning of that context.
(For details on these formats, see ).
(For details on these formats, see ).
Formal statement
Elaborate natural language
Ordinary natural language
"Peter" (traveler~;dest) "Rome"
There is a trip that Peter has made, which has Rome as destination.
Peter has made a trip to Rome.
"Peter" (traveler~;dest) "Paris"
There is a trip that Peter has made, which has Paris as destination.
Peter has made a trip to Paris
statement
natural language
"RS746620" (authorized/\beneficiary) "Ann"
Ann is authorized for and stands to benefit from for account RS746620.
"NL19RABO03992844" (authorized\/beneficiary) "Carl"
Carl is authorized for or stands to benefit from account NL19RABO03992844.
"RS746620" (authorized\/beneficiary) "Ann"
Ann is authorized for or stands to benefit from account RS746620.
"DE9382991" (authorized\/beneficiary) "Bob"
Bob is authorized for or stands to benefit from account DE9382991.
authorized/\beneficiary = {("RS746620", "Ann")}
authorized\/beneficiary =
{ ("NL19RABO03992844", "Carl")
, ("RS746620", "Ann")
, ("DE9382991", "Bob") }
Formal statement | Elaborate natural language | Ordinary natural language |
| For each trip, if Peter has made the trip then its destination is Rome. | Every trip that Peter made has Rome as destination. |
| For each trip, if Peter has made the trip then its destination is Paris. | Every trip that Peter made has Paris as destination. |
| For each trip, if Paris is the destination then Peter has made that trip. | Every trip to Paris has been made by Peter. |
operator category | precedence | operators |
logic | 1 (weakest) | |- (subset), |
binary boolean | 2 |
|
binary relational | 3 |
|
unary prefix, unary postfix | 4 (strongest) |
|
RJ/20161220: the CONTEXT statement is currently being revised. It is expected that this will lead to changes in syntax in the course of 2017.
The data contained in a business system represents a view of (a very small part of) the real world. Ideally, this view must be consistent, meaning that there may be no contradictions within that view. Since different business systems have different ways of viewing the real world, and/or look at different parts of the real world, we need to be able to distinguish between such views. We use the term 'Context' to refer to an individual view. Thus, a Context is defined in terms of concepts, relations and rules, and it consists of atoms and links to populate them.
Any Ampersand model has one context. The model is true within its context and there is no knowledge in a model about other contexts.
The model is specified between the keywords CONTEXT and ENDCONTEXT. A context has a name.
Other models included with the INCLUDE statement become part of the context they are included in.
To tell Ampersand what language your context is in, you can append a language directive to your context. Currently English and Dutch are supported. To do so, directly following the name of your context, you can specify
Where can be ENGLISH
or DUTCH
.
Directly following the optional language definition, you can optionally specify the format of your texts (see PURPOSE statement). Ampersand understands some different markup styles. The default style is REST (Restructured Text)
where can be one of
REST
,
HTML
,
LATEX
,
MARKDOWN
.
(For details on these formats, see pandoc.org).
To facilitate reusing code, Ampersand allows its user to divide code over different files.
The INCLUDE
-statement includes the code of another Ampersand-script or the data of a .xlsx-file into the context.
This statement specifies files that need to be included before compiling. The filename is given in double quotes, including a path that is relative to the position of the main adl-file. The main adl-file is the file that is called with the command Ampersand.
Possible files to include are:
other adl-files
xlsx-files to include population
All code in the included adl-files will become part of the context of the main adl-file.
Make sure to include the adl-files before including xlsx-files.
Included files may contain INCLUDE
statements themselves. The files mentioned there are treated as though they were included in the main file. So their code is also part of the same context. Nested adl-files can have their own xlsx-files included.
For formatting your excel-file see the text on the Excel Importer.
A relation statement says that there exists a relation in a context. It introduces (defines, declares) the relation in the context. Each relation is a set that contains pairs of atoms. Over time, pairs can be inserted into or deleted from a relation.
A relation statement can have one of the following forms:
The second and third ways will become obsolete in future versions of Ampersand.
All three ways define a relation by its name, its source concept and its target concept. The name of a relation is a single word that starts with a lower case letter. The source and target concepts start with an upper case letter.
A relation statement may occur anywhere inside a context, both inside and outside of a pattern.
The optional <properties>
, <pragma>
, and <meaning>
-parts are discussed in the sequel.
A relation statement means that there exists a relation in the current context with the specified name, source concept and target concept.
The name, source concept and target concept together identify a relation uniquely within its context. As a consequence, the name of a relation does not have to be unique. E.g. name[Book*Name]
can be specified in the same context as name[Person*Name]
. Because they have different source concepts, these are different relations.
The <properties>
-part is meant for writing multiplicity constraints in a comma separated list between square brackets '[' and ']'. E.g. [UNI,TOT]
. The following multiplicity constraints are available:
UNI
(univalent)
INJ
(injective)
SUR
(surjective)
TOT
(total)
SYM
(symmetric)
ASY
(antisymmetric)
TRN
(transitive)
RFX
(reflexive)
IRF
(irreflexive)
PROP
(property)
Let's assume that we want to express that any person can live in one city only. So under this constraint "Joe Smith lives in New York" and "Joe Smith lives in Denver" cannot both be true at the same time.
In relation algebra, we say that the relation is univalent, which means that every atom in the source concept can only be paired with a single atom in the target concept. This is modeled as
A pragma is optional and is characterized by the reserved word PRAGMA
. The PRAGMA
is followed by two or three strings. It is used to construct sentences in natural language, using pairs from the actual population of a relation. A pragma specifies how we speak (in natural language) about any pair in the relation. Ampersand also uses pragmas to generate examples in the functional specification. Example of a pragma with three strings:
To use this pragma on the pair (John,Amsterdam)
results in the sentence "Student John flies the flag of Amsterdam in top."
. The two atoms are fitted in between the three strings. A pragma with two strings is identical to a pragma in which the third string is empty.
(The PRAGMA
keyword will become obsolete in a future version of Ampersand. It will be replaced by the VIEW
-statement which offers more flexibility in composing sentences.)
Example:
The PRAGMA
tells us that it makes sense to utter the phrase "Provider Mario's Pizza's has accepted order 12345."
A meaning is optional and is characterized by the reserved word MEANING
. It specifies the meaning of a relation in natural language. It is is meant to say in natural language what it means for a pair to be in the relation. The meaning is used to generate documentation with and is printed in the functional specification. A <meaning>
has the following form:
The <text>
-part is where the the meaning is written down. We support both:
a string, enclosed by double quotes,
e.g.
any text, starting with {+
and ending with +}
e.g.
The optional <language>
is specified as
IN ENGLISH
or
IN DUTCH
.
Example :
This is a way to override the default language.
Sometimes you need formatting in the meaning, such as dotted lists, italics, or mathematical symbols. For this purpose you have a choice in which syntax you specify the meaning. The optional <markup>
is one of :
REST
(Restructured text)
HTML
LATEX
MARKDOWN
Example :
Ampersand uses Pandoc to offer a choice for your markup. See pandoc.org for details.
This statement is a rule, which defines an identity on a concept. It is syntactic sugar for specifying a set of relations that identify atoms in a specific concept. For example, if relations pi
and rho
determine an atom of concept T
uniquely, you can write:
As the IDENT statement defines a rule, it can be in the same places as any other RULE.
where:
<label>
is the name of the rule. It can be a single word or a string (enclosed by double brackets). It is followed by a colon (:
) to distinguish the label from the concept that follows.
<Concept>
is the name of the Concept for atoms of which the rule specifies an identity
Between brackets are terms whose source concept must be <Concept>
. This is enforced by the type system.
translates into the following rule:
Note that
in case everye
is both univalent and total, e<>e~
equals e;e~
, and the rule is equivalent to:
in case every e
is univalent but not total, you should use the IDENT
statement (or the rule that it implements), because that also works when an e
is not populated.
Most things in your model are in it for a reason. To document these, you should use the PURPOSE statement.
PURPOSE
<type of thing>
<name>
<language>?
<markup>?
<list of references>?
{+
<anything>
+}
Where <type of thing>
and <name>
are the type and name of the thing that is refered to. This could be one of: CONCEPT
, RELATION
, RULE
, IDENT
, VIEW
, PATTERN
, INTERFACE
, CONTEXT
The optional and can be used to override the settings for language and markup. If omitted, these are inherited from the pattern of context where the PURPOSE statement is specified in.
| a statement to provide metadata to a script, such as author, company, etc. |
| a block of code that represents rules on a single and specific topic, at the user's discretion |
|
|
|
|
|
| a statement that makes a role responsible for satisfying a rule |
| a statement for presenting facts in a readable sentence |
| a unit of code that can be run independently and specifies interaction with a user or a computer |
| a statement to describe the purpose of a context or a context element |
| a statement that sums up the initial population of a relation |
| a statement to include another file in the context |
| a block of code that represents rules on a single and specific topic, at the user's discretion |
|
|
|
|
|
| a statement that makes a role responsible for satisfying a rule |
| a statement for presenting facts in a readable sentence |
| a unit of code that can be run independently and specifies interaction with a user or a computer |
| a statement to describe the purpose of a context or a context element |
| a statement that sums up the initial population of a relation |
Patterns are meant to isolate discussions and make solutions reusable, as known from design patterns.
A pattern is a set of rules that describes a theme or a general reusable solution to a commonly occurring problem.
For instance, if specific concerns about security arise, you might want to discuss this with stakeholders in security. With them you can discuss which rules in particular constitute your solution. Divide your problem in smaller pieces and discuss each piece with just the right stakeholders. This allows you to go deeper by talking to the right people. It saves time as well by freeing others from having to participate. An even larger benefit arises if you reuse patterns that have been discussed and scrutinized before. The best thing comes once your stakeholders agree. By that time, your pattern represents their agreement formally in Ampersand, so you can use it in the larger context of the information system.
Every pattern has the following form:
A pattern consists of any number of pattern elements in an arbitrary order. The following pattern elements are allowed:
A model can have as many patterns as you want. It has no effect on how the code is processed.
The service definition must be outside a pattern
A pattern contains rules in an arbitrary order. The context in which these rules are valid must contain the definition for each of the relations that are used in those rules. It is good practice to declare all relations in the pattern itself. That practice makes the pattern self-contained and therefore more suitable for reuse.
Ampersand advocates one theme in one pattern. Stakeholders confine their discussion to one theme, and deliver the result in one pattern.
In the current implementation of Ampersand, patterns are defined within a context. (This will change in a future version.) If you want to reuse patterns, you have to cut-and-paste them from one context to another. In the future, there will be a better mechanism for reusing patterns in different contexts.
Fact
Fact
"Peter" traveler~ "LBD-199"
"LBD-199" traveler "Peter"
"Peter" traveler~ "TSS-730"
"TSS-730" traveler "Peter"
"TSS-730" dest "Rome"
"Rome" dest~ "TSS-730"
"TSS-730" dest "Paris"
"Paris" dest~ "TSS-730"
"QRA-492" dest "Paris"
"Paris" dest~ "QRA-492"
statements
"NL19RABO03992844" beneficiary "Carl"
"DE9382991" authorized "Bob"
"RS746620" authorized "Ann"
"RS746620" beneficiary "Ann"
Formal statement | Elaborate natural language | Ordinary natural language |
| For each trip, if it has destination Rome, then it has been made by Peter. | Every trip to Rome has been made by Peter. |
Services are meant to expose functionality and data from a context, to let users or information systems interact with the system by creating, reading, updating, and deleting data.
Note: The service definition must be outside a pattern
The following figure is an example of a user interface, which shows the name, status, e-mail and co-workers of a person called "J. Lovell".
The specification of this user interface is given in the following service definition:
To understand this fragment, take notice of:
The name of this service is Person
. This name immediately follows the keyword INTERFACE
.
The term following the colon, I[Person]
, is the interface term of this service.
The service can be applied to any atom from the domain of the interface term. So this particular service is applicable to any atom of type Person
. In the screenshot, it applies to "J. Lovell"
.
The labels "Name", "Status", "Email", and "Works with" correspond to field names in the user interface.
Each term at the right of a field name specifies which data is presented in the field. For this reason it is called the field term for that field. Field name and field term are separated by a colon.
Of all pairs <"J. Lovell", x>
from the field term, the field displays the right atom x
. A field term always works on one specific atom on the left, which is "J. Lovell"
in this example.
Field terms are subject to type checking. The following relations provide an example for getting a type-correct service:
The source concepts of a field term must match the target concept of the interface term.
Looking at the screenshot, we can tell that "J. Lovell"
has one personName (which is "J. Lovell"
), it has no personStatus, one personEmail and three persons to work with in RELATION workswith
.
You can create structure in a service by nesting. Here is an example:
The specification of this service is given in the following code fragment.
Notice the following features:
1. The structure of a service is hierarchical. It consists of boxes within a box. This is because a field term may be followed by a BOX
with a list of subservices. Without it, it is just a field term. 2. When a field term is followed by a BOX
, every atom in the codomain of the field term is displayed in a box of its own on the screen. That box behaves like a service with the field term serving as interface term of that subservice. 3. By this mechanism, the hierarchical structure of the entire service translates directly to the hierarchical structure of the web-page in which it is displayed. 4. The source concept of a field term must match with the target concept of the field term outside the box.
5. The target concept of a field term that has a box, must match with the source concepts of each field inside that box.
Especially in more complicated services, you will find it nice to adapt the layout of the fields in the user interface. For this purpose, you can substitute the word BOX
by COLS
, ROWS
, or TABS
, as in the following code fragment. Note that these annotation have no meaning other than to change what the user interface looks like.
Notice the effect that these changes have on the user interface.
Notice the following features:
1. The keyword TABS
turns the box into a tabulated layout.
2. The keyword COLS
turns the layout 90 degrees into columns.
3. The keyword ROWS
is default for any box. It does not change the effect of BOX
.
Compile and run the script Project Administration Example. Start by reproducing everything that is shown above. It is quite likely that you will be trying out your own ideas before you get to the end... Have fun!
After finishing your assignment, you have learned:
to explain how a service definition is displayed on the screen of a user.
to predict which data items a service applies to, if you know which pairs are in an interface term.
to predict which data items are displayed, if you know which pairs are in a field term.
to explain which atoms are used in a sub-interface.
to understand what the keywords TABS
, COLS
, and ROWS
do to your display.
More than one service may apply to the same atom. That gives you a choice on runtime to which service you want to navigate. If no service applies, that atom is not navigable.
In this section we will make an Ampersand script that is based on an existing spreadsheet. This technique is useful for quickly adding population to an information system. Ampersand has a facility that allows you to import existing .xlsx files with minimal changes.
We can consider Ampersand as a finite system of relations. Every relation is a set of (ordered) pairs and each pair contains two atoms. However, in the real world we also store information in wider tables, as we do in spreadsheets and relational databases. Here is the trick. If we have two pairs that share the same left atom, e.g. (1, Abraham) and (1, Lincoln), we can put them in the same row. Using the same trick, we can interpret a row in a spreadsheet as a number of pairs.
Let us look at an example:
Since Ampersand works with relations, it must represent this table as relations. Three relations can do the job in the following manner:
Notice that the column names in the table correspond with the relation names in Ampersand. In the table we call them "attributes". So it makes sense to say that a relation in Ampersand can correspond with an attribute in a table.
In theory, the population of the Hawaii-script might just as well be given in a spreadsheet. This works in practice too. It looks like this:
Please copy this in a spreadsheet of your own. The element in the first column with square brackets tells Ampersand that a new table starts. The first row contains relation names. The second row contains concept names. The rows that follow contain pairs. Ampersand reconstructs those pairs as in the example above.
In practical applications, you might want to reuse data from existing spreadsheets. People tend to have lots of "informal administration" in spreadsheets, which gives you access to authentic population. Surely you need that data organized in rows, but fortunately that is reasonably common. In such cases, you just add two lines above each table to inform Ampersand about the relations that are populated. In other cases, you have some work organizing the spreadsheet for importing it.
You will find the Excel import function in the menu bar on the top right of your screen
.
This is what your upload screen looks like:
You can upload one or more .xlsx-files by dropping them in the drop zone or by selecting them. You have to upload the population with the green
Upload
button. At that time, all population from the .xlsx-file is added to the context and checked for inconsistencies. As a result, you may get errors when uploading. Only error-free spreadsheets will be uploaded successfully. As long as an error remains, the population in your context will not change.
Make a population of your own for the Hawaii-script and put it in a .xlsx spreadsheet. As described above. Make sure to delete the population statements from your Hawaii source code, to make sure that you get to see the population from your .xlsx-file. Generate a prototype from your Hawaii-application, upload your population in Excel and play around with the results.
After finishing your assignment, you have learned:
to upload population to your Ampersand application in the form of a spreadsheet in .xlsx-format;
to understand how a POPULATION
-statement relates to the contents of a spreadsheet;
that the contents of the spreadsheet is added to the population of your context, provided this does not lead to any conflict.
To facilitate reusing code, Ampersand allows its user to divide code over different files.
The INCLUDE
-statement includes the code of another Ampersand-script or the data of a .xlsx-file into the context.
This statement specifies files that need to be included before compiling. The filename is given in double quotes, including a path that is relative to the position of the main adl-file. The main adl-file is the file that is called with the command Ampersand.
Possible files to include are:
other adl-files
xlsx-files to include population
All code in the included adl-files will become part of the context of the main adl-file.
Make sure to include the adl-files before including xlsx-files.
Included files may contain INCLUDE
statements themselves. The files mentioned there are treated as though they were included in the main file. So their code is also part of the same context. Nested adl-files can have their own xlsx-files included.
A service is a component of an information system that exposes functionality and data from a , to let users or information systems interact by creating, reading, updating, and deleting data.
A service is a component of an information system. Its life starts when it is deployed and ends when it is pulled back. A typical instance is a user interface based on HTML-CSS that runs in a browser. But an application program interface (API) that serves other computers with web services is a perfectly valid instance as well.
The definition of a service specifies which data is presented to which users. For every different use of the system a different service can be defined. This may lead to a substantial amount of services for large and complex systems. However, one device will show one service only at any given moment in time.
gives syntactic details of services. Some more explanations .
Please note that the keyword INTERFACE
is still used. That may be confusing. In a future release of Ampersand the keyword INTERFACE
will become obsolete and the word SERVICE
will be used.
This example specifies three tabs. One shows students, one shows courses and one shows modules. This is what it looks like when run in a browser:
On the user screen each atom is displayed in some form as data. If a service exists for that atom, that is shown to the user as a hyperlink to which you can navigate.
When running an application in your browser, you are watching one user interface at any given moment in time. Each hyperlink on your screen represents an atom to which some service applies. To navigate to that user interface, you click on the hyperlink. You will see the service being applied solely to the atom you just clicked. To determine the atom(s) to which a service applies, each service has an interface term.
The next sections contain two examples:
This statement will be available in Ampersand vs. 4.
This statement provides syntactic sugar for defining tabular information conveniently. It introduces a number of relations and rules in a single statement, to simplify a script.
where:
<label>
is the name of the rule. It can be a single word or a string (enclosed by double brackets). It is followed by a colon (:
) to distinguish the label from the concept that follows.
<Concept>
is the name of the Concept for atoms of which the rule specifies an identity
Between brackets are terms whose source concept must be <Concept>
. This is enforced by the type system.
translates into the following declarations:
Multiplicity annotations are allowed. For example:
translates into the following declarations:
This statement makes nice combinations with the IDENT statement. For example to define two identities for persons:
This states that a person is uniquely defined by ssn
, but also by the combination of name
, birthplace
, and birthdate
. This statement can also be used to objectify (reify) an term e
If a user is tempted to replace the Create/Delete pair with a single equivalence, this becomes:
Patterns are meant to isolate discussions and make solutions reusable, as known from .
A pattern is a set of that describes a theme or a general reusable solution to a commonly occurring problem.
For instance, if specific concerns about security arise, you might want to discuss this with stakeholders in security. With them you can discuss which rules in particular constitute your solution. Divide your problem in smaller pieces and discuss each piece with just the right stakeholders. This allows you to go deeper by talking to the right people. It saves time as well by freeing others from having to participate. An even larger benefit arises if you reuse patterns that have been discussed and scrutinized before. The best thing comes once your stakeholders agree. By that time, your pattern represents their agreement formally in Ampersand, so you can use it in the larger context of the information system.
Every pattern has the following form:
A pattern consists of any number of pattern elements in an arbitrary order. The following pattern elements are allowed:
A model can have as many patterns as you want. It has no effect on how the code is processed.
The service definition must be outside a pattern
A pattern contains rules in an arbitrary order. The context in which these rules are valid must contain the definition for each of the relations that are used in those rules. It is good practice to declare all relations in the pattern itself. That practice makes the pattern self-contained and therefore more suitable for reuse.
Ampersand advocates one theme in one pattern. Stakeholders confine their discussion to one theme, and deliver the result in one pattern.
In the current implementation of Ampersand, patterns are defined within a context. (This will change in a future version.) If you want to reuse patterns, you have to cut-and-paste them from one context to another. In the future, there will be a better mechanism for reusing patterns in different contexts.
To store data in a database corresponds to populating the relations in a context. Atoms are the data and pairs of atoms are inserted and deleted during the lifetime of a relation.
All pairs in a relation are called the population of that relation. All atoms in a concept constitute the population of that concept. The population of all relations and concepts in a context make the population of that context.
There are two ways to populate a concept with atoms:
A POPULATION
statement defines the initial population of a concept or a relation.
An INCLUDE
statement defines the initial population from an xlsx-file (i.e. an Excel speadsheet)
to define an initial population allows you to work with larger populations. Often you can use an existing spreadsheet and adapt it to become acceptable as Ampersand input.
You can define atoms separately and you can define the pairs in a relation. Both methods result in added population for each concept.
The list of pairs is a comma-separated list between square brackets. Pairs are comma-separated pairs between round brackets. Each atom is enclosed in double quotes.
a statement that declares a
a statement that specifies generalization/specialization of
a declaration of a relation, stating the existence of a within the context
a description of a , to document its meaning
a statement that defines the atomic type of a
a statement that declares a
a statement that specifies generalization/specialization of
a declaration of a relation, stating the existence of a within the context
a description of a , to document its meaning
a statement that defines the atomic type of a
For formatting your excel-file see the text on .
Due to the complexity of services, its syntax and meaning are discussed in .
a to allow clients of a web shop to change their name and address and show them status information of their orders;
a to demonstrate how to get different interface structures under varying conditions.
<rule>
a statement that declares a rule
<classify>
a statement that specifies generalization/specialization of concepts
<relation>
a declaration of a relation, stating the existence of a relation within the context
<conceptDef>
a description of a concept, to document its meaning
<representation>
a statement that defines the atomic type of a concept
<roleRule>
a statement that makes a role responsible for satisfying a rule
<ident>
a rule that defines an identity on a concept
<viewDef>
a statement for presenting facts in a readable sentence
<purpose>
a statement to describe the purpose of a pattern or a pattern element
<population>
a statement that sums up the initial population of a relation
firstname
lastname
birth
1
Abraham
Lincoln
February 12, 1809
2
Barack
Obama
August 4, 1961
3
Calvin
Coolidge
July 4, 1872
4
Dwight
Eisenhower
October 14, 1890
[Subject]
pass
required
Subject
Student
Destination
Surfing
Brown
Hawaii
Surfing
Conway
Latin
Brown
Rome
World Religions
Applegate
World Religions
Brown
Rome
You don't have to put up with the Ampersand built-in layout options if they don't suit your purpose. You can change most anything by including your own code snippets. (to be done...).
The syntax of a service is best explained by means of examples. However, if you want to understand the syntax in detail, this section is what you are looking for.
A service specification has the following structure. It is identical for user interfaces (INTERFACE
) and application programming interfaces (API
).
The name of a service must be unique within the context. The term defines the atoms to which the interface can be applied. The (optional) crud annotation constrains the possible interactions a user can do. The (optional) views determine what the service will look like. If no view is specified, the service will look like the screenshot above. Finally the sub-interface contains all the contents, i.e. the fields, field names and the constraints on them.
The hierarchy of boxes in a service comes from the following (recursive) syntax of <subinterface>
.
A sub-interface may be defined on the spot (by <boxKey> <box>
) or it may link to another service to reuse its structure:
The boxKey is meant to tell the front-end application what the service looks like. The compiler uses templates to adapt an interface to specific needs regarding its HTML structure. Please read the documentation of templates for details.
If no htmlname is specified, Ampersand uses BOX <FORM>
by default.
A box is simply a list of service items (ifcItem
) separated by commas. Each service item specifies a field in the service or a sub-interface.
Each service item has a label that must be unique within the box. After the colon there is either a term or a text. The term specifies which data is related to the field it specifies if it has no sub-interface. If it does, it specifies the atoms on which the box is applied.
Suppose we have a delivery-hub that distributes orders over vendors and registers the subsequent deliveries. Let us define a service for clients, to allow clients to change their name and address and display their orders.
The service has a header, which is the first line in this example:
The word ClientInfo
is the name of this service. This name identifies the service , so it must be unique throughout the entire context.
This service is shown only to users with roles Client
or Vendor
. That is indicated by the restriction FOR Client,Vendor
. Without that restriction, the service is available for every user in any role.
The term to the right of the colon (:
) symbol is called the interface term. A service is called from an atom which must be in the domain of this term. Let, for example, Peter
be a Client
. As Peter
is an element of the domain of I[Client]
, the service can be called from that atom.
The same term, I[Client]
, is also used as box term for the box that follows the header. For every element in the codomain of the box term, a container (in HTML: <div>
) will be drawn on the user screen. That box serves as a subinterface, which is called with precisely one atom. With I[Client]
as box term, the codomain will contain just one atom, which is precisely the atom from which the service was called.
In this example, the outermost box contains seven box items and the innermost box two. Each box item has a label and an term. For example the box item "Name" : clientName
has "Name"
as its label and clientName
as term. The atom a
from which the box was called is used to select the pairs (a
,x
) from the term. All x
-es for which (a
,x
) is in clientName
will be displayed. Supposing that the relation clientName
associates only one name to a client, this specific box item displays just one name. However, in the fifth box item, the term orderedBy~ - V; orderAccepted~
may contain an arbitrary number of orders to be accepted by provider, all of which are shown.
|
|
|
|
|
| a statement that makes a role responsible for satisfying a rule |
| a rule that defines an identity on a concept |
| a statement for presenting facts in a readable sentence |
| a statement to describe the purpose of a pattern or a pattern element |
| a statement that sums up the initial population of a relation |
Services are meant to expose functionality and data from a , to let users or information systems interact with the system by creating, reading, updating, and deleting data.
Note: The service definition must be outside a pattern
The following figure is an example of a user interface, which shows the name, status, e-mail and co-workers of a person called "J. Lovell".
The specification of this user interface is given in the following service definition:
To understand this fragment, take notice of:
The name of this service is Person
. This name immediately follows the keyword INTERFACE
.
The term following the colon, I[Person]
, is the interface term of this service.
The service can be applied to any atom from the domain of the interface term. So this particular service is applicable to any atom of type Person
. In the screenshot, it applies to "J. Lovell"
.
The labels "Name", "Status", "Email", and "Works with" correspond to field names in the user interface.
Each term at the right of a field name specifies which data is presented in the field. For this reason it is called the field term for that field. Field name and field term are separated by a colon.
Of all pairs <"J. Lovell", x>
from the field term, the field displays the right atom x
. A field term always works on one specific atom on the left, which is "J. Lovell"
in this example.
Field terms are subject to type checking. The following relations provide an example for getting a type-correct service:
The source concepts of a field term must match the target concept of the interface term.
Looking at the screenshot, we can tell that "J. Lovell"
has one personName (which is "J. Lovell"
), it has no personStatus, one personEmail and three persons to work with in RELATION workswith
.
You can create structure in a service by nesting. Here is an example:
The specification of this service is given in the following code fragment.
Notice the following features:
1. The structure of a service is hierarchical. It consists of boxes within a box. This is because a field term may be followed by a BOX
with a list of subservices. Without it, it is just a field term. 2. When a field term is followed by a BOX
, every atom in the codomain of the field term is displayed in a box of its own on the screen. That box behaves like a service with the field term serving as interface term of that subservice. 3. By this mechanism, the hierarchical structure of the entire service translates directly to the hierarchical structure of the web-page in which it is displayed. 4. The source concept of a field term must match with the target concept of the field term outside the box.
5. The target concept of a field term that has a box, must match with the source concepts of each field inside that box.
Especially in more complicated services, you will find it nice to adapt the layout of the fields in the user interface. For this purpose, you can substitute the word BOX
by COLS
, ROWS
, or TABS
, as in the following code fragment. Note that these annotation have no meaning other than to change what the user interface looks like.
Notice the effect that these changes have on the user interface.
Notice the following features:
1. The keyword BOX <TABS>
turns the box into a layout with tabs.
2. The keyword BOX <TABLE>
turns the layout 90 degrees into columns.
3. The keyword BOX <FORM>
is default for any box. It does not change the effect of BOX
.
After finishing your assignment, you have learned:
to explain how a service definition is displayed on the screen of a user.
to predict which data items a service applies to, if you know which pairs are in an interface term.
to predict which data items are displayed, if you know which pairs are in a field term.
to explain which atoms are used in a sub-interface.
to understand what the keywords TABS
, COLS
, and ROWS
do to your display.
More than one service may apply to the same atom. That gives you a choice on runtime to which service you want to navigate. If no service applies, that atom is not navigable.
CRUD annotations are used in services to constrain the functionality of fields and boxes in an INTERFACE
-statement. This allows you to minimize the functionality for your users, to design for easy learning.
Each CRUD annotation comes right after a , so we can always refer to "the term" to which a CRUD annotation belongs. A CRUD annotation constrains the things your user can do with the target atoms and the pairs of its term.
The CRUD-annotation specifies Create, Read, Update, and Delete rights for the term it follows. Capital = allowed, Non-capital = not allowed. CRUD is the default, so if you specify nothing, everything is allowed. The following service definition illustrates this.
The user interface defined by this service is shown as a screenshot below. Notice that the lowercase r in the annotation of the Students box prevents showing the underlying box. The full CRUD functionality in Course yields 'create' functionality (the green plus-button), 'remove pair' functionality (red minus button), and 'delete atom' functionality (the red trash can button). The lowercase c, u, and d in the Modules box prevents displaying that functionality in the user interface.
The next sections give some more detailed information on the run time semantics for CRUD annotations as implemented in Ampersand.
A top-level Update or Create are common in my own scripts, e.g. to create an overview of People and be able to create a new Person: INTERFACE "People" : V[SESSION*Person] CRud COLS []
. And update is also possible.
The red minus is enabled by U
. It unlinks an atom (by deleting a pair from a relation) and leaves the atom alone.
The red trash bin is enabled by D
. It removes an atom and all pairs in which that atom is used.
To store data in a database corresponds to populating the relations in a context. Atoms are the data and pairs of atoms are inserted and deleted during the lifetime of a relation.
All pairs in a relation are called the population of that relation. All atoms in a concept constitute the population of that concept. The population of all relations and concepts in a context make the population of that context.
There are two ways to populate a concept with atoms:
A POPULATION
statement defines the initial population of a concept or a relation.
An INCLUDE
statement defines the initial population from an xlsx-file (i.e. an Excel speadsheet)
to define an initial population allows you to work with larger populations. Often you can use an existing spreadsheet and adapt it to become acceptable as Ampersand input.
You can define atoms separately and you can define the pairs in a relation. Both methods result in added population for each concept.
The list of pairs is a comma-separated list between square brackets. Pairs are comma-separated pairs between round brackets. Each atom is enclosed in double quotes.
a statement that declares a
a statement that specifies generalization/specialization of
a declaration of a relation, stating the existence of a within the context
a description of a , to document its meaning
a statement that defines the atomic type of a
Compile and run the script . Start by reproducing everything that is shown above. It is quite likely that you will be trying out your own ideas before you get to the end... Have fun!
Motivations for CRUD-functionality are found in the functionality.
Read | CRUD for boxes | CRUD for fields |
R | Read is allowed | Read is allowed |
r | Read is not allowed | Read is not allowed |
This statement will be available in Ampersand vs. 4.
This statement provides syntactic sugar for defining tabular information conveniently. It introduces a number of relations and rules in a single statement, to simplify a script.
where:
<label>
is the name of the rule. It can be a single word or a string (enclosed by double brackets). It is followed by a colon (:
) to distinguish the label from the concept that follows.
<Concept>
is the name of the Concept for atoms of which the rule specifies an identity
Between brackets are terms whose source concept must be <Concept>
. This is enforced by the type system.
translates into the following declarations:
Multiplicity annotations are allowed. For example:
translates into the following declarations:
This statement makes nice combinations with the IDENT statement. For example to define two identities for persons:
This states that a person is uniquely defined by ssn
, but also by the combination of name
, birthplace
, and birthdate
. This statement can also be used to objectify (reify) an term e
If a user is tempted to replace the Create/Delete pair with a single equivalence, this becomes:
The purpose of this statement is to automatically modify the population of a relation based on rules.
Since ampersand 4.4.0 the syntax of this statement is:
The <operator> can be one of :=
, :<
or >:
.
This statement may occur anywhere within a context, either inside or outside a pattern.
This statement means the population of the relation will automatically be kept respectively equal ( :=
), a subset (:<
) or a superset (>:
) of the population of the given term.
Both the sources and the targets of the relation and the term must match. An error message is given otherwise.
The relation must be specified in order to use it here, as is the case with any relation used in an expression.
To generate documentation, Ampersand is language aware.
Ampersand assigns a language to every text written as documentation, whether it is a MEANING
, PURPOSE
or other text except comment.
Ampersand does not recognize any language, so you must tell which language is meant. To tell Ampersand what language you use, you can append a language directive to a context, a meaning, and to a purpose statement. Currently English and Dutch are supported.
A language directive has the following syntax
Where <language>
can be ENGLISH
or DUTCH
.
The first example is a context declaration in which the language ENGLISH
is specified.
This means that all natural language elements within this context are written in ENGLISH
, unless specified otherwise.
The second example is a MEANING
, which can be used in a RULE
statement and in a RELATION
statement. This example uses a MEANING
in ENGLISH
:
The language directive IN ENGLISH
means that the meaning of the relation ptpic[Pattern*Image]
is written in ENGLISH
.
The third example is a PURPOSE
statement in which the language DUTCH
is specified.
This means that the contents of this purpose statement is written in DUTCH
.
Ampersand assumes that whatever is written is written in the language denoted in the language directive. It doesn't check whether that language is actually used, because it cannot recognize languages.
If a CONTEXT
has no language directive, IN ENGLISH
is used by default. If a CONTEXT
has a language directive, that language will be the default language of all natural language items within that context.
If a PURPOSE
statement or a MEANING
has no language directive, Ampersand assumes this to be the language of its context. So, the user needs to specify a language only if it is an exception to the default.
Documentation generated by the Ampersand-compiler is written in a single language, which is specified when the compiler is called.
Documentation generated by RAP3 is written in DUTCH
. Natural language items written in any other language are ignored. This is not a mistake, but a feature. RAP3 only "speaks Dutch" and ignores anything else.
The design considerations of Ampersand are treated as principles, not as laws. In case of conflicting design considerations, choices have been made.
An Ampersand context presents itself as a universe with constraints. This was chosen to allow for incremental development. Adding a constraint changes nothing to the semantics of other constraints.
One example of this is found in the CRUD annotations: A service provides all possible CRUD-functions, which are constrained by CRUD annotations.
The Ampersand engineer gets as much freedom as possible, to facilitate incremental development. Every obligation imposed on the Ampersand-engineer is a necessity.
One example is the freedom to define PURPOSE
statements. Although the Ampersand team feels strongly about the need to specify a purpose for almost everything, the choice is left to the user. Since there is no hard technical reason for having them, the compiler does not impose its use.
As a consequence, the Ampersand engineer can choose the order in which she adds statements. This is consistent with the order-free semantics of Ampersand.
The semantics of a script is well-defined and self-contained, to ensure predictable behaviour of information systems defined in Ampersand.
The prime example is the relation algebraic semantics of terms, which is defined unambiguously in a well-studied formalism that is over a century of age.
Tools must be reliable and may not distract their users from their real work: designing information systems. For this reason we have paid much attention to making reliable tools and to automate the process of designing and building.
An example is the generation of software by the Ampersand compiler, which makes Ampersand more than a design tool. But also the deployment automation with Docker exemplifies this principle.
Every Ampersand script, that passes the compiler without errors yields a working system. This makes it easy to focus on working systems, because partial implementations can be demonstrated and tried. (prototyping).
This principle makes it easy to neglect documentation.
CRUD | for a box | for a field. |
C |
c | Atoms cannot be created | Atoms cannot be created |
Update | CRUD for boxes | CRUD for fields |
U |
u | Update is not allowed | Update is not allowed |
Delete | CRUD for boxes | CRUD for fields |
D |
d | delete not allowed | delete not allowed |
Ampersand is meant for back-end design. It offers no features for front-end design. For that purpose we advise you use contemporary front-end tools for web-based applications. Your Ampersand application is designed to be adaptable, especially for this purpose.
However, Ampersand offers a few layout features that let you place items. It has three built-in layout options, colums, rows and tabs, which you can mix freely.
The column layout uses BOX <TABLE>
to instruct the front-end application to use a tabular layout in user interfaces. Here is an example of a service, which uses the table layout.
This service shows three columns in the user interface, Students, Course and Modules. The first column is not readable, because the CRUD annotation blocks this column for reading. It would have shown students in each row, because the target of V[SESSION*Student]
is Student
. The second column shows courses in two columns, Course and Modules. The third column shows modules in three columns. This is what the user will see on the screen.
The row layout uses BOX <FORM>
to instruct the front-end application to layout the user interface row by row. Here is an example of a service, which uses the row layout on the top level.
This service shows three rows in the user interface, Students, Course and Modules. The first column shows students in each of its rows. Each student is shown in the column layout. The second row shows courses in two columns, Course and Modules. Please read about templates if you are curious which other ways of displaying information there are besides BOX <FORM>
. Please read the explanation of CRUD annotations if you are curious about the CRUD annotations. This is what the user will see on the screen.
The column layout uses BOX <TABS>
to instruct the front-end application to tabs in the user interface. Here is an example of a service, which uses the column layout.
This service shows three tabs in the user interface, Students, Course and Modules. Only one tab is shown at a time, to avoid cluttered data. This is what the user will see on the screen.
We have discussed the COLS
, ROWS
, and TABS
layout options. Please note that these options do not change the semantics; whatever your options, Ampersand displays the same data in the same fields.
If these options are not enough, you can enhance your application with your own layouts.
As from version 4.0.0 Ampersand has a command structure that allows you to use Ampersand from the command line.
ampersand --version
to find out which version of Ampersand you are using.
ampersand --help
to summarize all level one commands
In practice, run ampersand --help
instead of consulting the following list, just to be sure that the commands match the version you are using. The following list has been taken from version 4.0.0.
The general structure of commands is ampersand [options]* COMMAND
. The following commands are available:
ampersand [options]* check <filename>
Check your model for syntax errors and type errors.
ampersand [options]* daemon <filename>
Check your model continuously while editing it.
ampersand [options]* data-analysis <filename>
Export a data model as a plain Ampersand script, for analyzing Excel data.
ampersand [options]* dev-output <filename>
Generate some diagnostic files, intended for developers of Ampersand.
ampersand [options]* documentation <filename>
Generate a functional design document, to kick-start your functional specification.
ampersand [options]* population <filename>
Generate a .xmlx file containing the populations of your script.
ampersand [options]* proofs <filename>
Generate a report containing proofs.
ampersand [options]* proto <filename>
Generate a prototype from your specification.
ampersand [options]* export <filename>
Generate a single .adl
-file of your script (prettyprinted)
ampersand [options]* uml <filename>
Generate a data model in UML 2.0 style.
ampersand [options]* validate <filename>
Compare results of rule evaluation in Haskell and SQL, for testing expression semantics. This requires command line PHP with MySQL support.
ampersand [options]* test <filename>
Run test suites in a given directory. This is meant to do regression testing during automatic build (e.g. Travis-ci)
The filename
in a command typically has suffix .adl
(which stands for Ampersand Description Language). If you omit the suffix .adl
, Ampersand does NOT add it for you. The filename conventions of your operating system apply (whether you have Windows, macOS, or Linux).
You may use one of the first three options to specify how verbose your output will be. The other options can be used at random and mixed freely.
--help
Show the help text. This is always up to date with the version of the compiler you are running. So consider ampersand --help
to be authoritative.
--verbosity VERBOSITY
Verbosity: silent, error, warn, info, debug
-V, --verbose
Enable verbose mode: verbosity level "debug"
--silent
Enable silent mode: verbosity level "silent"
--[no-]time-in-log
Enable/disable inclusion of timings in logs, for the purposes of using diff with logs (default: enabled)
--[no-]terminal
Enable/disable overriding terminal detection in the case of running in a false terminal
--terminal-width INT
Specify the width of the terminal, used for pretty-print messages
--outputDir DIR
Specify the directory where your output will be written to.
Every command can have options of its own. Use the command and add --help
to see which command specific options there are.
Example:
TODO: This example is subject to bitrot. It has to be redone.
This example defines a login/logout service, because it is familiar. We show this example to demonstrate how to get different interface structures under varying conditions.
The compiler uses templates to adapt an interface to specific needs regarding its HTML structure. Please read the documentation of templates first for details.
To link system activities to a person or organisation, we use the notion of Account
. To log in means to associate a session with the Account
of the user. This association is made in the relation sessionAccount
. To log out means to break that link, i.e. to remove the session/account pair from relation sessionAccount
. When logging in, it is customary that the user identifies herself. In this example we do this with a UserID
and Password
.
A UserId
is used to identify the user by a unique name. In this way, the (system generated) key of the user in the database is kept within the database.
To make it more difficult to use an other person's Account
, the system registers passwords. A Password
is a string of characters known to the user only. For this reason, the login service must not expose the password while the user is typing it.
To isolate a data space for one specific user, we use the notion of session. A SESSION
corresponds with the notion of session as used in browsers. Ampersand links the session called '_SESSION'
to the current browser session, which results in the behaviour one would expect of a browser session.
A login service allows a user to log in and log out of the system. Here is what it looks like in a browser:
Wonder what the 25al1rdkdfvmapkkqvuf5sroc5 means? Well this is the session number of the actual browser session. It is the value for which the atom
"_SESSION"
stands in your script.
When you type your name, it shows up in the field Userid, but when you type in the password it is obscured by dots
(
as we would expect
)
:
When we then type
<enter>
, the login functionality disappears and the logout functionality appears:
When you click the checkbox, you have logged out and will return to the first screen
To understand how it all works, let us discuss the code for this service:
If you analyse this code, notice the nested structure of BOX
-es. The service is a box on the top level with two sub-boxes labeled "Login"
and "Logout"
.
The top-level box has "_SESSION"[SESSION]
as its box-term. What you must remember is that the every atom of the codomain of that term causes one contain (HTML: <div>
). In this example, the codomain of "_SESSION"[SESSION]
is just one atom, which is the session identifier. That is shown in the title of the outmost box in the browser.
<HROWS>
We would expect to see two subboxes, one labeled "Login"
and another labeled "Logout"
. However, the outmost box was annotated with <HROWS>
. The H
stands for hidden. It means that empty subboxes will be hidden from the user. Now look at the box-terms of the "Login"
- and "Logout"
subboxes. Which elements are in the codomain of the box-term of the "Login"
subbox? It says: "All sessions without an account associated with it". Since there is only one session (i.e. the browser-session) this comes down to "the current session, provided there is no account associated with it." So if nobody is logged in in the current browser session, the session atom is the only atom. Otherwise there is no atom and the "Login"
subbox is not shown. Similarly, which elements are there to make the the "Logout"
subbox appear? That box-term shows all sessions associated with an account. Which would be the account of the current session, provided someone is logged in.
That explains why the "Login"
subbox is shown when nobody is logged in and the "Logout"
subbox is shown when someone is logged in.
So let us do the following experiment: change the
<HROWS>
annotation to
<ROWS>
. Then we will see both boxes:
Notice that both subboxes have the
H
in their annotations, so in the screeshot above the
"Logout"
subbox remains empty. However, when logged in, the other subbox remains empty:
How do you get the moment your script has started to run?
The runtime system of Ampersand contains a function that produces the current date. Here is an example how to use it:
If you run this program, this is what you'll see
The rule "Initialize today's date" tells us that there must be a date for every session. When your session starts, there is a session atom: _SESSION
. The relation sessionToday
does not relate that session atom to a date, so the rule is violated. As a consequence, the ExecEngine triggers the violation and calls the function SetToday
. That PHP-function creates the desired link in the relation sessionToday
. That is then displayed in the user screen.
If you want to check your script, generate documentation, generate prototypes or use any other feature of Ampersand, you need to run the Ampersand compiler. This page tells you how.
In many situations, you can avoid running the Ampersand compiler from the command line. For instance, by using a system such as . However, in situations that you run Ampersand from the command line, this page is the place to be.
We assume you have docker
running on your computer and that you are connected to the internet. In that case you don't have to install anything.
The following is the base command on Linux (works for bash as well as zsh)
On the Windows-10 command-line this looks slightly different (todo: check this!)
This runs the Ampersand compiler (from your command prompt). The first time you do this, docker will take some time to download the images it needs.
In the sequel we will use ampersand
as an alias for docker run -it -v "$(pwd)":/scripts ampersandtarski/ampersand
The standard behavior of ampersand
is affected by the following environment variables.
CCdbName Sets the name of the database that is to be generated. Can be overruled by --dbName
CCdirOutput Sets the default output directory for generated assets. Can be overruled by --outputDir
CCdirPrototype Sets the default directory where functional prototypes are being generated. Can be overruled by --proto
In order to enable multiple configurations of some functionality, Ampersand allows developers to specify code fragments that are conditionally ignored (or included, depending on your point of view). This allows you e.g. to include code that you need for debugging/development, but that is not needed in demonstrations. It also allows you to create modules, e.g. SIAM, that developers can re-use yet have control over the functionality that is included.
The preprocessor allows for
setting or clearing preprocessor variables. This is done by means of an extension of the INCLUDE
statement.
testing a preprocessor variable, and including or ignoring a subsequent text depending on the value of that variable.
The preprocessor syntax has been designed in such a way that scripts that use the preprocessor syntax can also be compiled by versions of Ampersand that do not support preprocessor syntax. In such cases, the preprocessor syntax is treated as comment (and hence ignored). Obviously, compiling scripts whose consistency relies on preprocessor statements cannot be expected to compile with versions of Ampersand that do not support the preprocessor syntax.
Here is an example of how preprocessor variables can be used within a script. In this example, a list of usernames and passwords is shown when the preprocessor variable Developing
is true. If that variable is false, all texts between the --#IF
and --#ENDIF
are treated as comments (ignored)
Preprocessor variables are assigned values in INCLUDE
statements, e.g. as follows:
Variables are set or cleared by specifying their names (in quotes) in a list following the --#
preprocessor directive. When a variable name is preceeded with a !
-character, its value is cleared (set to 'false'). Otherwise, its value is set (to 'true').
At the time of writing, the preprocssor specifications are as follows:
A line of text, that (a) starts with optional whitespace, (b) is followed by 2 or more -
characters, (nu is dat 2 -
chars) (c) is followed by optional whitespace, (dat mag nu nog niet) (d) is followed by #
and (e) is followed with optional whitespace, is not interpreted by the Ampersand parser, but is passed to the Preprocessor instead. The text behind the #
-character up till the end of the line is the TextToBePreprocessed
. TextToBePreprocessed
is defined by the (PCRE) regex ^\s*--+\s*#\s*(?P<TextToBePreprocessed>.*)$
. Note that Ampersand versions that do not support preprocessing will treat such texts as comment.
A preprocessor Keyword is the first word in TextToBePreprocessed
. Keyword
is defined by the (PCRE) regex (?P<Keyword>\w+\b)
when it is applied to TextToBePreprocessed
. In absolute terms, that would be ^\s*--+\s*#\s*(?P<Keyword>\w+\b).*$
followed by optional whitespace and keyword consisting of alphanumeric characters. Keywords are (thus) case sensitive. Examples: --#IF Debugging
or -- # ENDIF
Currently, valid keyword syntax is as follows (the (PCRE) regexes are assumed to be applied on TextToBePreprocessed
):
IF
, IFNOT
each take one argument - a variable.
Formally, this is defined by (PCRE) regex (?P<Keyword>IF|IFNOT)\s+(?P<Variable>\w+)
.
Examples --#IF Debugging
or --#IFNOT UserSpecifiesLoginMethod
ELSE
and ENDIF
do not take arguments.
The preprocessor treats any text following these syntaxes as comments (i.e.: ignores such texts)
Also the syntax of INCLUDE
statements is extended to include an optional comment that specifies a list of quoted variable names. Example INCLUDE "../SIAMv3/Login.ifc" --# [ "Debugging", "NoLogout" ]
. The (PCRE) regex is \bINCLUDE\s+"(?P<fileid>[^"]+)"(\s+(--#\s*)?\[\s*"(?P<var1>!?\w+)"(\s*,\s*"(?P<var2>!?\w+)")*\])?
where any text in groups var1
or var2
are variable names that may (optionally) be preceeded with a !
character. For each such variable names, a variable is created that can be referenced by its name. When the variable name was preceeded with a !
character, its value is initialized as 'false'; When the variable name was not preceeded with a !
character, its value is initialized as 'true'; If a variable with a specified name was already created, the newly created variable takes precedence. After a file inclusion terminates, the variables that the INCLUDE statement created are all destroyed.
When the preprocessor parses the file that is INCLUDE
d, preprocessor commands that evaluate a variable (such as IF
or IFNOT
) will use the value as defined in that INCLUDE
statement or (recursively) in that of a 'higher' INCLUDE
statement.
You configure the precise actions of the compiler by specifying on the command line. If you use the same configuration frequently, consider using a configuration file, so you don't have to remember all these options each time you call the compiler. The configuration file sits in the same directory as your model.
A + (plus) button is displayed that lets you create a new atom, but only if the box-expression is editable.
Enter a new atom and a +
button appears. Click the + to add that atom to the listed set of atoms. If you enter an atom that exists (Peter), you can select it.
Removing and/or adding a pair (src,tgt) is allowed if expr is editable and the atom exists. Deleting a pair is done with the - button; the atom will NOT be deleted.
Removing and/or adding a pair (src,tgt) is allowed if expr is editable and the atom exists. Deleting a pair is done with the - button; the atom will NOT be deleted.
Deleting a pair is done with the - (minus) button. Deleting an atom is done with the trash bin.
Delete atom (tgt) and all pairs in which it is used.
The command ampersand
takes a file as input. It must contain a valid ampersand script, i.e. a script that complies to the and semantics of ampersand. The compiler will not generate any output unless the script is valid.
We are happy to receive . However, please try to help us by first checking that it has not been reported already. You can do so by searching the issues. When in doubt however, don't hesitate to .
In case the Ampersand compiler is called by software and fails, it is useful to have an exit code to give some information about the nature of the failure. The Ampersand compiler :
Command-line options are used to tell the ampersand compiler what to do. This page lists the available options.
Some of the options are still experimental. Momentarily an effort is made to rationalize the options, so this may change at some point in the near future.
Since Ampersand-v3.5.3, it is possible to use a configuration file, reducing the need to rewrite the same options every time you use ampersand.exe. A configuration file can be used using the --config
option.
This text may deviate slightly from the Ampersand version you are running, especially as new options are introduced. The command ampersand --help
will give you the actual list.
Print a usage message briefly summarizing the most common command-line options and the bug-reporting address, then exit. When used in combination with --verbose
, it shows all command-line options. Use this to get the actual list of options of your Ampersand compiler.
Print the version number of Ampersand to the standard output stream. Please mention this information in every bug report you submit (see below).
--ECA
generate documentation with ECA rules.
--add-semantic-metamodel
The metamodel in Formal-ampersand is loaded together with your own model. Use this feature in conjunction with --meta-tables
to get a metamodel populated with your own script into the database.
--altGraphics
generate graphics in an alternate way. (you may experiment with this option to see the differences for yourself)
--atlas-without-terms
Temporary option to create an Atlas without terms. This feature is used in RAP3 for performance reasons.
--blackWhite
do not use colors in generated graphics. Use this feature if you must print in black and white, to obtain better results than printing a colored source on a black-and-white printer.
--config=config.yaml
By default, the Ampersand compiler looks in the working directory for a config file (.yaml
) with the same filename as the Ampersand script. Use this feature to redirect to another file. Use --sampleConfigFile
to get a template.
--crowfoot
generate crowfoot notation in conceptual models. This is used to better match the preferences of some database engineers in the generated documentation.
--crud-defaults=CRUD
Set the default CRUD function for services. This function is explained in interface terms. This feature is used temporarily to gain experience with CRUD and learn about its semantics.
--customizations=DIRECTORY [, DIRECTORY]*
copy one or more directories into the generated prototype. This overrules the default directory, which is called customizations
.
--dbName=NAME (-d)
database name. Use this for choosing the name of the SQL database. This overrules the environment variable CCdbName
. It defaults to the filename of your Ampersand script.
--dev, --ignore-invariant-violations
Allow building a prototype, even if there are invariants that are being violated. (See issue 728 on Github)
--diagnosis
diagnose your Ampersand script. Use this if you wish to generate a document containing only the diagnosis chapter.
--do-not-trim-cellvalues
Do not ignore leading and trailing spaces in .xlsx files that are INCLUDED in the script. Normally, Ampersand removes spaces around cell values in .xlsx files when transforming the cell value to atoms. Use this to enforce that spaces around cell values are meaningful.
--export[=file] (-e)
export as plain Ampersand script.
--force-reinstall-framework
re-install the prototype framework. This discards any previously installed version. Use this to eradicate any doubt about a fresh reinstall.
--fpa
Generate Function Point Analysis chapter. Use this to include a measure of the functional complexity (size) of the generated application into your functional specification document. This feature is currently out of order.
--fpa-excel
generate an Excel workbook (FPA_<filename>.xml). Use this to obtain the base data used in the function point analysis. This feature is currently out of order.
--fspec=FORMAT (-f)
generate a functional design document in specified output format (FORMAT=[Asciidoc, Context, Docbook, Docx, Html, Latex, Man, Markdown, Mediawiki, Opendocument, Org, Pandoc, Pdf, Plain, Rst, Rtf, Texinfo, Textile]). Use this to obtain documentation in the format of your own choice.
--gen-as-rap-model
generate populations for use in RAP3.
--haskell
generate internal data structure, written in Haskell. Use this for debugging.
--help (-h, -?)
get (this) usage information.
--services (-x)
generate services. This feature does not work properly at the moment.
--language=LANG
Pick 'NL' for Dutch or 'EN' for English, as the language to be used in your output. Without this option, the output is written in the language of your context. Text snippets in other languages than the one specified are ignored. Use this to get a functional specification in the language of your choice.
--meta-file
Generate a .adl file that contains the relations of formal-ampersand, populated with the meta-population of your own .adl model.
--meta-tables
Populate the metamodel of Ampersand with the contents of your own script. Use this feature in conjunction with --add-semantic-metamodel
to get a metamodel populated with your own script into the database. This is used for higher-order purposes, specifically in RAP3.
--namespace=NAMESPACE
prefix database identifiers with this namespace, in order to isolate namespaces within the same database. This feature was used in RAP2 to isolate students' work in separate tables.
--newNormalizer
Use the new optimizer at your own risk. Used for research purposes.
--noDiagnosis
omit the diagnosis chapter from the functional design document.
--noGraphics
omit the generation of graphics during the generation of the functional design document.
--oldNormalizer
use the old optimizer at your own risk. Used for research purposes.
--outputDir=DIR (-o)
output directory. Use this if you want the Ampersand compiler to redirect the output to a location of your choice. This overrules the environment variable CCdirOutput
.
--pop-xlsx
Generate a .xmlx file containing the populations of your script. Meant to be used as an Excel-file in which you can add bulk data and reuse that for loading the data into your application.
--proofs
generate derivations in HTML-format. Use this to see how Ampersand derives computer instructions from your rules.
--proto[=DIRECTORY] (-p)
generate an information system. Use this to verify your analysis or to obtain a working prototype from your Ampersand script. In some cases, the result will be good enough for production. This option overrules the environment variable CCdirPrototype
.
--prototype-framework-version=VERSION
tag, branch or SHA of the prototype framework on Github. Use this to select a specific version when generating an information system.
--reference-table
generate a table of references in the Natural Language chapter, for instance for legal traceability.
--sampleConfigFile
write a sample configuration file (sampleconfig.yaml). Use this to save yourself the trouble of looking up an example configuration file.
--sql-bin-tables
generate binary tables only in the SQL database. Use this to verify that the generated system works with binary tables as well as with wide tables.
--sqlHost=HOSTNAME
set SQL hostname (Defaults to `localhost`). Use this to let the generated system know which database to connect to.
--sqlLogin=USER
set SQL user name (Defaults to `ampersand`). Use this to let the generated system log into the database.
--sqlPwd=PASSWORD
set SQL password (Defaults to `ampersand`). Use this to let the generated system log into the database.
--sqldump
generate a dump of SQL queries. Use this for debugging purposes.
--test
Used for test purposes only.
--testRule=RULE
Show contents and violations of specified rules. Use this for diagnostic purposes.
--uml
Use this to generate conceptual models as a UML 2.0 data model.
--validate
Compare results of rule evaluation in Haskell and SQL. Use this to debug the SQL code generator to validate the meaning of all rules, which are evaluated both in the compiler and in the database. This option requires command-line PHP with MySQL support.
--verbose (-V)
run the compiler in verbose mode. Use this for diagnostic purposes.
--version (-v)
show version and exit. Please use this when reporting bugs on Github.
This chapter contains technical details about the backend framework.
This chapter is meant for Ampersand users that want to build prototypes that automatically fix violations for specific rules. The idea behind this is quite simple: all it takes is another way of specifying violation texts. In practice, however, it takes some effort to learn how to do this correctly. Therefore, we only encourage you to do this if you are sufficiently motivated to spend this effort, i.e. if you are convinced it is worth your while.
Before studying this chapter, make sure you know how to predict violations. You need to understand how Ampersand computes violations, given a certain population.
Did you ever wonder how you can make your computer prevent rules from being violated? For that purpose, you must specify what your prototype will do the moment it signals a violation. This chapter tells you how.
In essence, an Ampersand prototype is a database application that helps its users to keep rules satisfied. Keeping a rule satisfied happens in one of the following ways: 1. Your prototype imposes a rule. Violations are not tolerated. The prototype does not accept any change of data that violates the rule. As a result, the rule remains satisfied all the time. Such rules are called invariants. 2. Your prototype signals each violation to a designated role. The signal does not go away until the user has eliminated the violation. The rule is called process rule because it prompts users to do some work. Notice that a violation of a process rule may persist. That is because it is meant to be resolved by persons rather than a computer. 3. Your prototype restores a violation the moment it occurs. It does so by means of a built-in robot, which we call the ExecEngine. Such rules are called automated. 4. The rule cannot be violated because of the way Ampersand is built. These rules are called laws. No effort is needed to maintain them, because they are always true.
This chapter is about the third category: automated rules. The idea is to prevent violations by acting in time, to satisfy the violated rule. This is nice for your users, who have no concern with those violations.
This chapter introduces automated rules by example. We will first create a rule, which a user must keep satisfied. We will then automate that process by adding instructions for the ExecEngine.
Most of the examples are taken from the demo script Project Administration Example. You can compile and run this script, and reproduce several of the examples that follow.
InsPair
and DelPair
)Consider the following example:
The following rule defines coworkers. Two different persons are coworker if they work in the same project. As a person can be either a project leader or a member, we get this rule:
This rule basically says that coworker
is shorthand for the much more complicated term (pl\/member)~;(pl\/member)-I
. Quite useful indeed. Now suppose this rule is satisfied in the system. Then some manager assigns a new person, Harry, to the project Zeus-III. To administer that fact in the system, he adds a pair ("Zeus-III", "Harry")
to the relation member
. Now there is a problem. The prototype will not accept this input, because our rule is violated. For all present workers in the project now have Harry as a new coworker. That should be administered in the relation coworker
in order to satisfy the rule.
One way to do that is to allow the manager to edit the relation coworker. This is not very convenient for that manager. He will be irritated, as he is forced to enter a number of pairs into the relation coworker
that is equal to the number of persons in the project plus the number of projectleaders of that project. This rule is typically a candidate for automation.
We have to consider that whenever a person is added to the project, that person must be added to coworker
as well. But when a person is discharged from the project, that person must be removed from coworker
. We can split the rule in two, knowing that r=s
is always equivalent to both r|-s
and s|-r
.
Let us discuss both rules, starting with the first one. The ROLE
statement assigns rule r1
to the ExecEngine. The instruction for the ExecEngine is given in the VIOLATION
string. It will be executed for each violation of rule r1
.
Elaborating on this example, just which violations will the ExecEngine resolve? Suppose the project has Alfred and Bob on the team before Harry is assigned. This means that the relation coworker
contains ("Alfred", "Bob")
and ("Bob", "Alfred")
for starters. When the pair ("Zeus-III", "Harry")
is added to the relation member
, we get the following violations: ("Alfred", "Harry")
, ("Harry", "Alfred")
, ("Bob", "Harry")
, and ("Harry", "Bob")
. So, the following instructions will be given to the ExecEngine:
Note that the violations of rule r1
are precisely the pairs the ExecEngine must add to coworker
to satisfy rule r1
. The function InsPair
is a predefined ExecEngine function, that adds to the population of a relation. The corresponding function DelPair
removes pairs from the population of a relation. In the example, it is used to remove people from coworker
that no longer share a project.
Notes:
The examples use SRC I
or TGT I
to produce atoms that are to be inserted or deleted. However, I
may be any term whose source concept is the same as that of the preceeding SRC
or TGT
.
The SRC <term>
and TGT <term>
is a set of pairs (a,b), where a is the source atom or target atom of the violation and b is a set of atoms that is the result of <term>
. In the examples given, this set of atoms has cardinality 1 (which is most often the case). However, if it is empty, that is considered regular behaviour, and this will hence not result in an error. Also, if it has a cardinality > 1, then InsPair
will insert them all whereas DelPair
will produce an error.
InsAtom
) and ({EX}
)Consider the following example:
The following rule states that for every project leader, an assignment must exist that applies to one person and one project, basically assigning that person to be a project leader for the Project.
This calls for two different things: first, the automated creation of an atom in the concept Assignment
, and second the consecutive population of relations project
and assignee
using this newly created atom.
This is specified as follows:
First, note that we have three consecutive statements: an InsAtom
command followed by two InsPair
s. Using the phrase {EX}
in front of each statement allows the interpreter of the violation texts to recognize each individual command and its arguments. In order to ensure that you do not forget about this, you may want to consider habituating yourself to always use {EX} before any function.
The first statement assigns the rule Create Assignment
to the ExecEngine. The prototype will send all violations of this rule to the ExecEngine. The rule says that for every project with a project leader, there must be an assignment. Without that assignment, the rule is violated. The VIOLATION
statement specifies that a new Assignment
must be made for each violation. For that purpose, we use the predefined function InsAtom
. This function takes a single argument, being the concept within which an atom has to be generated (Assignment
in the example).
The second statement calls the InsPair
function in order to populate the relation project
, in the manner we described above. Note that at the position where we want to specify the newly created Assignment atom, we use the phrase _NEW
. The third statement calls the InsPair
function in a similar fashion, and thus populates the relation assignee
.
Note that
in an InsPair
(or DelPair
), the source-atom or the target-atom (or both) can be the keyword _NEW
.
the keyword _NEW
refers to the last atom that was created by the (last) InsAtom
statement that was executed in the violation.
when using _NEW
, the corresponding concept (obviously) MUST be the same as the concept as specified in the InsAtom
statement.
Here is how it works. Suppose the pair ("Zeus-III", "Rhea")
is added to the relation pl
, meaning that Rhea
is being made a project leader of project Zeus-III
. This produces a violation ("Zeus-III", "Rhea")
of the rule Create Assignment
. The associated VIOLATION statement produces the text
which is passed to the ExecEngine, which splits the text in three statements
and subsequently executes them. Executing the InsAtom
statement creates a new atom in concept Assignment
(let's say it is Assignment_3495812395
. The keywords _NEW
in the InsPair statements are then replaced by Assignment_3495812395
, so that ("Assignment_3495812395", "Zeus-III")
is inserted into relation project[Assignment*Project]
, and ("Assignment_3495812395", "Rhea")
is inserted into relation assignee[Assignment*Person]
.
DelAtom
)In our example, whenever a project participant is discharged from his task, the corresponding Assignment needs to be deleted. We can do this by means of an automated rule:
The function 'DelAtom' is predefined, and takes two arguments: 1. the concept from which an atom is to be deleted; 2. the actual atom to be deleted.
Note that when an atom is deleted, also every pair (in any relation) is deleted if either its source atom or target atom is the deleted atom.
_;
)When you try to create or delete pairs with atoms that contain texts, you may find that some texts contain the semi-colon. When such a text is used in a violation statement, this will be interpreted as an argument separator, causing all sorts of unexpected results. This can be prevented by using _;
rather than ;
as an argument separator. However, the ExecEngine must be made aware that this alternative argument separator is used. This is done by mentioning it immediately at the beginning of a function call, as in the below example:
Of course, if the SRC or TGT atom is a text that contains the characters _;
, the problem still remains...
TransitiveClosure
)Consider the r :: A * A [IRF,ASY]
. In relation algebra, terms such as r+
or r*
are allowed, designating the transitive closure of r
. The +
and *
operators are currently not supported in Ampersand.
This section describes a workaround that allows you to use transitive closures.To do so, we simply define a relation rPlus :: A * A
and/or rStar :: A * A
, and define the following automated rules to populate these relations:
While this works (certainly in theory), a practical issue is that it quickly becomes very timeconsuming as the population of r
grows, up to an unacceptable level. Also, Ampersand prototypes have a time limit (30 or 60 seconds) for an ExecEngine run. In order to make transitive closures a bit more practicable (but certainly not workable for 'real' software), we can use the predefined ExecEngine function TransitiveClosure
, as follows:
What this does is the following. Any time that r
is being (de)populated, the rule Warshall on r
is violated. This calls the (predefined) function TransitiveClosure
with its four arguments, the result of which is that 1. the relation rPlus
is computed as the (smallest) transitive closure of r
(using the Warshall algorithm); 2. the relation rCopy
is made to have the same population as r
, thereby resolving all violations of the rule.
Note that if you want to use (the equivalent of) r*
somewhere in an term, the most practical way is to use the term (I \/ rPlus)
at that spot.
As an Ampersand user, you are used to getting error messages from the compiler. Yet, errors in rules for the Exec-engine are not signalled by the compiler. Instead, you get run-time error message that some inexperienced users find hard to work with, as it requires some knowledge of the backgrounds.
Here are some tips. 1. Most (all?) predefined functions check for a valid number of arguments. If the error message relates to the number of arguments, 1. you have missed out on a ;
. The function NewStruct
is well-known to produce this error, because of the wealth of arguments allowed. Learning and maintaining a strict discipline regarding how you write such (e.g. NewStruct
) statements is a big help in preventing this error from occurring. 2. you may have to many ;
s. Of course, you may just mistakenly having written too many ;
s. Another, less known cause is where a violation occurs on an atom that happens to be a text containing one or more ;
characters. This will cause the ExecEngine to interpret the text as multiple arguments, which (usually) results in an illegal number of arguments error. The cure is to use the _;
separator rather than the ;
separator (see the appropriate section above). 2. Most (all?) predefined functions that have arguments to specify a relation definition, will check (at run-time) whether or not this relation is actually defined (at define-time). Misspellings in relation or concept names (e.g. capitalizations) often cause this error. 3. You should specify a relation just with its name, e.g. project
(not: project[Assignment*Project]
). The reason for this is that it (currently) is the ExecEngine itself that parses the violation string (rather than the Ampersand compiler). This very simple parser does not handle [Assignment*Project]
-like constructs. 4. For the same reason (simple ExecEngine parser), there is no type checking for the ExecEngine functions. This means that you must check yourself whether or not the type of atom(s) you want to insert or delete match with the source or target atom of the relation you try to (de)populate. 5. Look at the log window to get more information on what is actually happening when the ExecEngine executes. You can turn it on by clicking on the left-most icon of the icon-list that is at the right hand side in the menu bar. There, you turn on the 'Show log window'. In the log window, you can select what you do and do not see. Options you may want to select include 'ExecEngine', 'RuleEngine' and 'Database'. 6. If everything else fails, read the error messages and log lines slowly and carefully, as they (sometimes unexpectedly) do provide information that may actually help you to resolve the issue at hand.
For the time that researchers are working on this problem, you will have to live with all this. It makes programming of automated rules initially error-prone and time consuming, but when you get the hang of it, it gets better. Still, the best piece of advice we can currently give here is:
Keep automated rules simple.
Test thoroughly.
The ExecEngine currently is a simple one. Whenever it executes, it evaluates the automated rules one after another. Whenever an automated rule produces violations, the associated violation text is executed for every such violation.
While rules are most often evaluated in the order in which they are defined, you really should not make any assumptions about the evaluation order (nor about the order in which violations of a rule are processed). Hence, it may happen that the violations are processed 'out of order', resulting in violations of automated rules that could 'easily' have been fixed.
To overcome this issue, the ExecEngine (by default) simply runs itself again, until all automated rules have no violations any more, or until the maximum amount of such reruns has been reached - this limit is set to guarantee that execution terminates. The default number of maximum reruns is 10 (decimal). You can modify this setting in LocalSettings.php
, , by (including and/or) modifying the following texts:
For research or debugging purposes, it may sometimes be neccesary to have further control over the manner in which the ExecEngine does. There are three possibilities for running the ExecEngine:
Automatically. This is the default behaviour. Turning the autoRerun feature off means that the ExecEngine will always run only once when called. You can specify this in the file LocalSettings.php
, by replacing the text true
by false
in the line that contains the text:
Config::set('autoRerun', 'execEngine', true);
Manually. This is when you, as a user, clik on the refresh/reset options
icon in a prototype, and the select Run execution engine
. Note that if you also use logins, you must have been assigned a role that allows you to do this, or you won't see this option.
By using the ExecEngine function RerunExecEngine
, which takes one argument (an explanatory text, that is used for logging - see the example below). Whenever the ExecEngine calls this function, a flag is set requesting a rerun. When, at the end of an ExecEngine run, this flag is set, the ExecEngine will run itself again.
Here is an example of how RerunExecEngine
can be used to create a transitive closure:
The prototype has some built-in extensions. Some are experimental, others are pretty stable. This chapter describes them.
The extensions are described from a user perspective. You may expect enough information to use the extension you want. If not, please notify the authors.
The extensions are NOT described from an implementors perspective. If you wish to change the extensions, you will need more information than is contained in this text. Please contact the authors for that purpose.
An Ampersand Module is a coherent set of Ampersand scripts that:
provide a specific functionality, and
are set up in such a way that re-using them in different prototypes is easy.
An example is the SIAM module (SIAM = Session Identity and Access Management Module). This module provides login functionality and extendable registrations for e.g. persons, organizations and accounts. Also, it provides functionality that allows for access control (of INTERFACEs) based on roles, as well as on account attributes.
The SIAM module is set up in such a way that it is easy to re-use. Developers may INCLUDE a script (for which a template is provided) that imports the appropriate functionalities into the prototype. By tailoring this INCLUDE-script, a developer may turn specific features on or off. This is much easier than having to develop the functionality all by himself.
The current set of modules include:
Messaging - sending messages to people, roles and other recipients by variious means, e.g. email.
Sets - perhaps the simplest module of all, implementing set- and subset functionality.
Sequences - functions for creating sequences of items, adding items at different ends
SIAM - i.e. Session, Identity and Access Management.
To run a database that can be used by the Ampersand prototype framework, you can easily use a Docker image from: docker.pkg.github.com/ampersandtarski/prototype-db/prototype-db
Code | Name | Meaning |
0 | Success | Compilation has terminated without failures |
2 | Fatal |
10 | Invalid | The script is not valid and the compiler has produced error messages to help you diagnose your mistake(s). |
20 | Inconsistent | The population would violate invariants. The compiler cannot generate a violation-free database. |
30 | Invalid SQL |
50 | Ampersand violations | There are sanity checks on your script that have produced violations, so the compiler will not generate an application. |
60 | Composer | The installation of Composer failed, so the front-end application will not work. This is most likely a configuration error. |
70 | Wrong arguments | The command-line arguments by which the compiler was called contain errors. Inspect the compiler output for a diagnosis. |
80 | Back-end | The compiler failed to install the prototype framework. This is most likely a configuration error. |
Hookpoint use the following naming convention:
camelCasing
start with pre or post to define if hooks are called before or after the following position
specify classname or file where hookpoint is positioned
specify functionname where hookpoint is positioned
optionally specify postion within function where hookpoint is positioned
Current list of hookpoints:
More hookpoints will be defined when needed.
This chapter is intended for programmers who wish to know more about the software Ampersand generates. There can be many reasons, such as wanting to change the user experience, add or change functionality in views and/or controls, or simply to use the API of an Ampersand application. In this chapter you will find more details of the applications you generate.
In general, any information system has a structure like the one depicted below:
An information system is meant to support users (e.g. Peter, Sally, Daisy). Differences among users can be handled by using roles (e.g. customerRep, sysMgr, MgmtSupporter). In this diagram, users are coloured to depict different roles.
An information system consists of a number of services. We distinguish user facing services and non-user facing services. User facing services (e.g. register a client, sanitize case files, login) can be made available for a limited number of roles, giving each user access to precisely the services he or she is meant to see. In the diagram, user-facing services are colored corresponding to the roles they serve. Non-user facing services are not colored. Therefore, they are used exclusively by other software. Services can be either stateful or stateless. In the diagram, stateful services are drawn with a data container inside.
Services communicate by means of streams or by means of remote calls.
Currently, Ampersand generates correct information systems with one stateful service, which is the database. All other services are stateless and client-facing.
An Ampersand information system is deployed as a whole. Therefore it qualifies as a "monolithic" system.
Let us look at a typical Ampersand Application called RAP, as an example:
This example demonstrates how Ampersand applications function on the web. The application is deployed on a docker platform to facilitate frequent deployment anywhere in a robust manner and to isolate the internals from the outside world. Its structure has been defined statically (in docker-compose) to allow automated maintenance in production. The application itself is implemented as a statefree service, rap4
. It uses a database service, db
, for persistent storage. It is connected to the internet by a proxy which takes care of https and http traffic on ports 443 and 80 respectively. Two local networks separate data traffic to facilitate future work load balancing. The components db
, phpmyadmin
, and proxy
are open source components which we have reused from the internet. The component rap4
has been generated by Ampersand and has the structure shown in the following section.
Let us take a look at the structure of any system that Ampersand generates.
The diagram shows an Ampersand framework (Ampersand FW, i.e. the green area), which is a database application that works as a stateful service. It ensures that all invariants are kept satisfied in production, as changes to the database are being made. So the integrity of the data is defined by the rules in the Ampersand script and perpetuously maintained in the back-end of the application.
The framework is encapsulated by an application programming interface (API, the yellow area), which exports the functionality in a standardised way. Every application that interfaces through that API will therefore automatically preserve the integrity of data.
On top of the API, the application comes with a front-end application (the blue area). This web-application has a conventional structure, based on the well-known Model-View-Control (MVC) pattern used in many web-applications.
The Ampersand compiler (the orange thing on the right) generates the application as a collection of HTML-pages (views) and JavaScript pages (controls), together with static code that is loaded from a framework. So the framework and the API are generic components, in which the semantics are "injected" as JSON files from the Ampersand compiler.
The structure described above is reflected in the directory structure generated by Ampersand:
So if you look in your directory, the generated application will look like this:
The following figure shows the view-files to the left, the controller-files in the middle, and the services used by the controllers to the right.
You might want to know who is using your application. Or you might want to offer each one of your users some privacy when using your application. Logging in, passwords, authorizations, are typically used for such purposes. This field, also known as Identity and Access Management is covered in .
The gives you a selection of ways to organise that, ready for you to use.This module is located in the ampersand-models repository on . It is maintained by from a closed repository at TNO (git@ci.tno.nl:ampersand/models.git).
Deploying your Ampersand application has been automated, so you can deploy fast and deploy anywhere. Read this section for the quick "how-to's", examples, and the bigger picture behind it.
Different aspects of the Ampersand user's environment can be containerized 1. Ampersand compiler 1. Modelling environment for Ampersand user (incl. VSCode extensions) 1. Prototype environment, including:
Apache webserver with PHP
Ampersand compiler
PHP-composer
NPM (Node Package Manager)
Gulp
Multi-stage prototype build, only:
Apache webserver with PHP
Generated code
Prototype database
MariaDB with default user/password
A docker-compose file is available to deploy prototype, database and supporting tools (like phpMyAdmin)
Detailed technical instructions are at under the directory listing. This page provides more general and summarized information as context.
The contains a docker-compose and Dockerfile to generate, build and run a prototype application.
Run: docker-compose up -d
to deploy the following services:
Apache webserver
Serves your prototypes
Available in the browser at http://localhost:80
phpMyAdmin dashboard
Available in the browser at http://localhost:8080
MariaDB database
Not directly exposed on host
Click on the green “Code” button and pull down to “Download ZIP”
Download the zip and copy the directory on your laptop
With a command line interface:
docker-compose up –d
you may need to enter “docker network create proxy” and repeat “docker-compose up –d”. The second time is a lot faster
Go to the Docker desktop app
Find rap-master or the name you gave this docker app
Click the play button (the triangle)
Go to “localhost” on your browser and RAP should be running there as it does on the course server
If that doesn’t work then to back to docker and stop and restart rap4 but enter “2020” as the port and go on the browser to “localhost:2020”
To use the Ampersand compiler from the command line without installing Ampersand, you can call on Docker. This page gives you the quick "how-to's" for this purpose.
To run the Ampersand compiler from any computer that runs docker, use a Docker image from our Ampersand repository on GitHub: docker.pkg.github.com/ampersandtarski/ampersand/ampersand
Make a shortcut tag to save typing:
Different tags are available, e.g.:
:latest -> development branch It contains the most recent developments that have passed the automated test sets.
:stable -> master branche This contains the latest stable release of ampersand. Use it for the lowest risk.
:[branch] -> specific branch This allows you to pick a version yourself
:v3.17 -> specific tags/releases To use a specific previous version.
This alternative presumes you have docker
installed on your computer and it can be found (i.e. the path is set correctly).
If you experience problems downloading from docker.pkg.github.com
, you may first have to log in with an appropriate token. Generate a token and be sure to switch on all repo-rights and the read:packages
-right. With that token log in:
Deploying your Ampersand-script involves building an application, baking an image, deploying it on your local docker platform, and running the result from your browser. Most of that process is automa
Make sure that ports 80 and 443 on your laptop are available. (In other words: if you run a web server on your laptop, bring it down.)
Make sure that docker is running on your laptop.
git clone into an empty directory, so you have all the necessary files needed to deploy your application. We will call this the working directory.
Substitute the file "MyScript.adl" in the working directory for the Ampersand script you want to run.
Edit the file .env
to choose a root password for the database and an ampersand password for your application that accesses this database. Please choose safer passwords than the ones shown, which are merely examples. DON't publish the .env
file once it contains your passwords. If you make your own repository, take care that your passwords do not accidentally appear on github.
Edit the file Dockerfile
and substitute the filename "MyScript.adl" for the file name of your Ampersand script.
Open a command line interface (CLI) and navigate to this directory
Call "docker compose build". This step bakes your image. Docker stores that image on your laptop.
Call "docker network create proxy". The configuration uses a docker network called "proxy" to connect to ports 80 and 443 of your laptop, so you can use your browser to play with your application
Call "docker compose up -d". This instructs docker to deploy your application.
Go to your browser and navigate to localhost
to access you application.
Press the red install button on your application to spin up the database under your application.
Now you are set to go and tinker with your application.
to be done
This is a software error in the Ampersand compiler, that should never have occured in operational use. Please .
An SQL query gives other results than the semantics of Ampersand prescribes. This should never occur, so please .
Install Docker from and start the desktop app
Go to
RAP's GitHub site has more technical install instructions at
Hookpoint
Extensions that use it
postDatabaseReinstallDB
ExecEngine
postDatabaseUpdate
Mutation (experimental), Mqtt (experimental)
postDatabaseInsert
Mutation (experimental), Mqtt (experimental)
postDatabaseDelete
Mutation (experimental), Mqtt (experimental)
preDatabaseCloseTransaction
ExecEngine
postDatabaseCloseTransaction
postDatabaseAddAtomToConceptInsert
Mqtt (experimental)
postDatabaseAddAtomToConceptSkip
postDatabaseDeleteAtom
Mqtt (experimental)
postDatabaseStartTransaction
postDatabaseCommitTransaction
Mqtt (experimental)
postDatabaseRollbackTransaction
When a relation is used in a term, it stands for all pairs it contains at the moment it is evaluated. Those pairs (also referred to as the contents or population of the relation) can change over time as users add or delete pairs from it.
When a relation is used in a term, we can just use its name if that is unambiguous. For instance the name owner
refers to RELATION owner[Person*Building]
if that is the only relation the ampersand-compiler can link it to. In some cases, however the name alone is ambiguous. For example if there are two relations with the same name and different signatures. In such cases Ampersand will try to infer the type from the context. That however does not always succeed. In such cases, Ampersand generates an error message that asks you to remove the ambiguity by adding the correct type.
If a pair is an element of a relation , we write . Alternatively we may write , since we know that is a set.
For every concept , the term exists. It refers to the identity relation. It means that for every and we have:
The type of is . In Ampersand code you write I[C]
.
For every pair of concepts and the term refers to the complete relation. For every and we have:
The type of is . In Ampersand code you write V[A*B]
.
Would you like a different explanation of the primitive terms? This page explains the primitive terms in terms of set theory. Click here for the explanation of primitive terms in natural language.
The notation means that the pair (a,b) is in relation . This page defines when pair (a,b) is in relation (the intersection of and ), (the union of and ), (the difference of and ).
intersection : . In other words: if the pair is both in relation and , then it is in the intersection of and .
union : . In words: if the pair is in the relation or in , then it is in the union of and .
difference : . In other words, the term contains all pairs from that are not in .
The complement (or negation) of a relation is defined by means of the difference operator:
complement : If is defined as , then is the set of all tuples in (the Cartesian product) that are not contained in . So
Note that the complement is defined in terms of and . So, two relations with an identical population yet a different type may have different complements.
This page shows how you can type boolean (and other) operators in your Ampersand script.
Would you like a different explanation of the boolean operators? This page explains the boolean operators in terms of set theory.
Under construction
This chapter contains material to help you mature your skills in Ampersand. They are somewhat larger than the exercises that are embedded in the theory. That makes these exercises suitable for classroom projects.
There may be exercises in another language than English, usually for a good reason.
Currently, there is only one exercise, the VOG (Verklaring Omtrent Gedrag). This exercise requires you to read pieces of Dutch legislation, so this exercise is in Dutch.
Ampersand is great for rapid prototyping. We advise you to do that on the web. But sometimes you want to run your prototypes on your own computer(s). For different purposes there are different ways of doing that. This chapter shows you how.
You can use any text editor to create Ampersand scripts. However, for those that use the Visual Studio Code (vscode) editor, there is language support. All you have to do is search for the vscode extension "Ampersand (ADL) language support" and install it, and then choose the coloring theme called "Ampersand".
Using Ampersand offline does not require you to install Ampersand. Ampersand runs in Docker so you can use it independently and on almost any platform. Here is an explanation of how to do this (don't mind the title of that page). It can be summarized as follows:
Make sure Docker runs on your laptop or install it if it doesn't.
Copy the files Dockerfile
and docker-compose.yml
and adapt them for your own Ampersand prototype. Read this if you don't know where to find them.
Run your .adl
-file on the Docker platform.
DIY-engineers will find instructions in section Installing the tools manually. You need a webserver that can run javascript, PHP7, the PHP composer, and a (My)SQL or MariaDB database server. For generating functional specifications, you might use LaTeX, Markdown, Word .docx and other formats. This chapter gives an overview of the Ampersand production line for whoever needs to circumvent the automated process.
RAP4 is an Ampersand repository, in which multiple users can store and use their Ampersand scripts. Consult the tools we use at Ampersand. This is work in progress.
If you want to change the Ampersand compiler for your own purposes, you need access to the source files, and a Haskell development environment. This section still has to be written. It will describe the software process for developing Ampersand itself.
The remainder of this chapter explains in detail all the things you need to get you up and running with Ampersand. The instructions presume that you are familiar with your own computers.
Even though Ampersand was designed for prototyping, we are taking applications such as RAP2 and RAP3 to production. As the development of Ampersand is going in the direction of production software, we must be prepared for questions. Currently, I can hardly answer any questions about security. This page is for the purpose to discuss security questions, such that we are at least on the same ground wrt security. If any changes to Ampersand emerge from that, we should create separate issues for them. Here is a list of questions.
How is access control arranged in an Ampersand application? Answer: This can be arranged by using the SIAM modules, which provide role-based access controls, login possibilities and password security.
How does an Ampersand application log critical activities, and transactions that deal with sensitive data? Answer: The runtime system used the Monolog-framework to support all runtime logging. It allows selective logging of precisely the right actions, at the control of the designer.
How does Ampersand encrypt data? Answer: It doesn't. All data is stored as-is in the database.
How does an Ampersand application control access for purposes that are known only to the Ampersand application designer? Answer: The designer can use the ROLE mechanism to provide different services to different roles. Also, the designer can model these purposes in the Ampersand-script and take it from there. In the latter case, every possible access control scheme can be built.
How does an Ampersand application prevent injection flaws, by which hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization? Answer: Currently, the Ampersand application is not secured against injection flaws.
How can we know that application functions related to authentication and session management are implemented correctly? Is there a chance that attackers can compromise passwords, keys, or session tokens, or exploit other implementation flaws to assume other users’ identities? Answer: The authentication and session management are described in the SIAM-module in Ampersand itself. So we have a mathematical handle on this, which gives more certainty than hand-crafted code. We have no security assessment on the SIAM-code for this risk. Of course, when this is embedded in for example a SSO-service, we would have to look for specific risks incurred by that. At the moment I have no idea how good or bad an Ampersand-application will do on this risk.
Can an attacker execute scripts in the browser in which the Ampersand-session is running, and hijack user sessions, deface web sites, or redirect the user to malicious sites? Answer: There are currently no protections against Cross-Site Scripting.
Can an attacker get hold of a reference to an internal implementation object, such as a file, directory, or database key? Answer: The Ampersand language offers facilities to hide direct object references from the user. This is not the case in the API. A user with API-access can find direct object references.
How do we know that a secure configuration is defined and deployed, and that security settings are defined, implemented and maintained? Answer: The security configuration concerns more than the Ampersand-application alone. It touches on frameworks, application server, web server, database server and platform, and all components in the landscape in which it performs its duty. The Ampersand-configuration items are described in the architecture. Their parameters have been set to defaults that are "generally secure" without jeopardizing their functioning. Hardening of the database is left to the person who installs the Ampersand-application.
Does Ampersand have extra protection for sensitive data, such as credit cards, tax IDs, and authentication credentials? Answer: No.
Does an Ampersand application re-verify access rights in every API-call? Answer: No
Suppose the browser has been taken over maliciously. Can an Ampersand application be tempted to send a forged HTTP-request, including the session cookie and any other automatically included authentication information? Answer: We don't know
How well are libraries, frameworks, and other software modules protected? Are their privileges restrained? How? Answer: We don't know
Is it conceivable that an Ampersand application forwards its user to other pages and websites? Answer: The Ampersand-programmer uses the (technical) data type URL
for hyperlinking the user to other sites. She must ensure the trustworthiness of the URL's used in order to build a trustworthy web-application.
In this assignment you will practice the analysis of a legal procedure by using Ampersand. Since the legal procedure used here is in Dutch, this assignment is only given in the Dutch language. The purpose of this assignment is to practice the use of Ampersand in a real-life situation. Before the assignment, your tutor will explain the way of working for this type of analysis. During the assignment, your tutor will occasionally explain features of Ampersand that you might need.
In deze opdracht oefent u met het analyseren van wet- en regelgeving. Dit is een typerend voorbeeld voor de manier waarop Ampersand in de praktijk kan worden gebruikt. Het resultaat van deze opdracht is een conceptuele analyse van het proces van aanvragen en verstrekken van de Verklaring Omtrent Gedrag (VOG).
De Verklaring Omtrent Gedrag - ten onrechte door sommigen "verklaring van goed gedrag" genoemd - is het onderwerp van deze casus. Wat de VOG voor burgers betekent beantwoordt overheidsdienst "Justis" in haar voorlichting op internet. De formele regels hierover staan in de wet en regelgeving, zoals ontsloten op wetten.nl. Paragraaf 1 van de Beleidsregels VOG-NP-RP 2013 leidt dit onderwerp in:
Het Centraal Orgaan Verklaring Omtrent het Gedrag (COVOG) geeft op grond van de Wet justitiële en strafvorderlijke gegevens (Wjsg) namens de Minister van Veiligheid en Justitie verklaringen omtrent het gedrag (VOG) af aan natuurlijke personen (VOG-NP) en rechtspersonen (VOG-RP).
Bij een VOG-aanvraag wordt onderzoek gedaan naar het justitiële verleden van een natuurlijke persoon of een rechtspersoon en zijn bestuurders, vennoten, maten of beheerders. Daarbij wordt het belang van de aanvrager afgewogen tegen het risico voor de samenleving in het licht van het doel van de aanvraag. Naar aanleiding hiervan wordt verklaard of al dan niet is gebleken van bezwaren tegen die natuurlijke persoon of rechtspersoon en wordt de VOG geweigerd respectievelijk verstrekt.
In deze casus wordt in tweetallen gewerkt. Je maakt een Ampersand-script die de regels rond het aanvragen en afgeven van de VOG weergeven.
Scope 1: de administratieve afhandeling. Dit betreft hetgeen beschreven is in paragraaf 4 van de Beleidsregels VOG-NP-RP 2013. We beperken ons tot de elektronische procedure voor natuurlijke personen.
Scope 2: beoordeling van de aanvraag. Dit betreft hetgeen beschreven is in paragraaf 3 van de Beleidsregels VOG-NP-RP 2013. We beperken ons tot aanvragen van natuurlijke personen.
Bestudeer (voor zover relevant en voor zover de tijd het toelaat) de wettelijke bronnen en verwerk deze in een Ampersand-script. Dit werkstuk kun je te zijner tijd laten uitgroeien tot een volwaardig prototype voor een systeem dat VOG-aanvragen registreert en afhandelt.
Indien de docent deze opdracht beoordeelt, zullen de volgende criteria worden toegepast:
Is het ingeleverde conceptueel model compileerbaar in Ampersand?
Zijn er concepten, die in een adminstratie voor het uitreiken van verklaringen omtrent gedrag noodzakelijk zijn en die niet in het script aanwezig zijn?
Zijn er relaties, die in een adminstratie voor het uitreiken van verklaringen omtrent gedrag noodzakelijk zijn en die niet in het script aanwezig zijn?
Zijn er concepten in het script aanwezig, die in een adminstratie voor het uitreiken van verklaringen omtrent gedrag overbodig zijn?
Zijn er relaties in het script aanwezig, die in een adminstratie voor het uitreiken van verklaringen omtrent gedrag overbodig zijn?
Zijn er regels in Beleidsregels VOG-NP-RP 2013, die niet in het conceptuele model voorkomen?
Zijn er regels, die niet traceerbaar zijn naar een regel in Beleidsregels VOG-NP-RP 2013
Is van elke relatie en van elke regel de betekenis vastgelegd in een MEANING
?
Is van elke relatie en van elke regel vastgelegd waartoe hij bestaat, d.m.v. een PURPOSE
?
Consider the following script. You can compile and run it op een RAP server.
This script contains a RULE
called orderInAssortment
. By editing fields you can add orders, clients, providers, etc. Find out what RULE orderInAssortment
means by trying to violate that rule. Why does this rule exist? Describe the meaning and the purpose of this rule. It may help to play with the prototype and discussing this rule with your peers. Add your meaning and purpose to the script and make sure it compiles and runs.
By playing with the prototype, you have learned the meaning of RULE orderInAssortment
.
You have learned how to include a purpose and a meaning with a rule. Remember that you can add a purpose not just for any rule, but for relations, concepts, services and contexts as well.
The SIAM Module implements functionalities for managing Sessions, Identies and authentication (login). Also, it implements Accounts, Roles and a primitive yet extendable registration for people and organizations.
This chapter informs developers about:
how to include the SIAM module into a prototype;
what configuration/tinkering options he has;
what he should or should not do.
Playing with the module's functionality allows you to assess whether or not the implemented functionality is valid for your purposes. This section tells you how to do this.
The meaning of residual operators , , and is best explained by means of examples.
Assume we have a relation, label[Contract*Colour]
, which contains the colour of labels on contracts. A fact "1834" label "blue"
means that contract 1834 has a blue label.
Also assume another relation stored[Contract*Location]
, which gives the location where a contract is stored. Fact "1834" store "cabinet 42"
means that contract 1834 is stored in cabinet 42.
The sentence: "All contracts with a blue label are stored in cabinet 42." is represented as "blue" (label\stored) "cabinet 42"
. Literally it says: For every contract, if it has a blue label, then it is stored in cabinet 42.
The sentence: "All contracts that are stored in cabinet 42 have a blue label." is represented as "blue" (label~/stored~) "cabinet 42"
. Literally it says: For every contract, if it is stored in cabinet 42, then it has a blue label.
The sentence: "All blue labeled contracts and no others are stored in cabinet 42." is represented as "blue" (label~<>stored) "cabinet 42"
. Literally it says: For every contract, if it has a blue label, then it is stored in cabinet 42 and if it is stored in cabinet 42, then it has a blue label.
There is a pattern to this. A computer can generate a literal translation from the formula to natural language. However, that translation looks clumsy, verbose and elaborate. It is up to you to turn that in normal language. For examples click here. The systematic translation is given in the following table:
Would you like a different explanation of the residual operators? This page explains them in logic. Click here for visualized examples about residual operators.
When a is used in a term, it stands for a set of facts that are assumed true on the current time in the current context. Those facts (also referred to as the contents or the population of the relation) can change over time as users add or delete facts from it.
When a relation is used in a term, we can simply use its name if that is unambiguous. For instance the name owner
refers to RELATION owner[Person*Building]
if that is the only relation the ampersand-compiler can link it to. In some cases, however the name alone is ambiguous. For example if there are two relations with the same name and different signatures. In such cases Ampersand will try to infer the type from the context. That however does not always succeed. In such cases, Ampersand generates an error message that asks you to remove the ambiguity by adding the correct type.
If a pair is an element of a relation , we write to denote the fact. It means that we consider to be true (within the current context).
Every atom in a concept identifies itself. If for example concept "Person" contains atoms {"Ann", "Bob", "Cecil"}, "Ann" identifies "Ann", "Bob" identifies "Bob", and "Cecil" identifies "Cecil". This makes "Ann" and "Bob" different atoms (unequal).
Would you like a different explanation of the primitive terms? explains the primitive terms in logic. for the explanation in set theory.
Formally
Natural language template
a (r\s) b
For every x
: if x r a
then x s b
.
a (r/s) b
For every x
: if b s x
then a r x
.
a (r<>s) b
For every x
: if a r x
then x s b
and if x s b
then a r x
.
To generate documentation, Ampersand is language aware.
Ampersand assigns a language to every text written as documentation, whether it is a MEANING
, PURPOSE
or other text except comment.
Ampersand does not recognize any language, so you must tell which language is meant. To tell Ampersand what language you use, you can append a language directive to a context, a meaning, and to a purpose statement. Currently English and Dutch are supported.
A language directive has the following syntax
Where <language>
can be ENGLISH
or DUTCH
.
The first example is a context declaration in which the language ENGLISH
is specified.
This means that all natural language elements within this context are written in ENGLISH
, unless specified otherwise.
The second example is a MEANING
, which can be used in a RULE
statement and in a RELATION
statement. This example uses a MEANING
in ENGLISH
:
The language directive IN ENGLISH
means that the meaning of the relation ptpic[Pattern*Image]
is written in ENGLISH
.
The third example is a PURPOSE
statement in which the language DUTCH
is specified.
This means that the contents of this purpose statement is written in DUTCH
.
Ampersand assumes that whatever is written is written in the language denoted in the language directive. It doesn't check whether that language is actually used, because it cannot recognize languages.
If a CONTEXT
has no language directive, IN ENGLISH
is used by default. If a CONTEXT
has a language directive, that language will be the default language of all natural language items within that context.
If a PURPOSE
statement or a MEANING
has no language directive, Ampersand assumes this to be the language of its context. So, the user needs to specify a language only if it is an exception to the default.
Documentation generated by the Ampersand-compiler is written in a single language, which is specified when the compiler is called.
Documentation generated by RAP3 is written in DUTCH
. Natural language items written in any other language are ignored. This is not a mistake, but a feature. RAP3 only "speaks Dutch" and ignores anything else.
In this section we will make an Ampersand script that is based on an existing spreadsheet. This technique is useful for quickly adding population to an information system. Ampersand has a facility that allows you to import existing .xlsx files with minimal changes.
We can consider Ampersand as a finite system of relations. Every relation is a set of (ordered) pairs and each pair contains two atoms. However, in the real world we also store information in wider tables, as we do in spreadsheets and relational databases. Here is the trick. If we have two pairs that share the same left atom, e.g. (1, Abraham) and (1, Lincoln), we can put them in the same row. Using the same trick, we can interpret a row in a spreadsheet as a number of pairs.
Let us look at an example:
Since Ampersand works with relations, it must represent this table as relations. Three relations can do the job in the following manner:
Notice that the column names in the table correspond with the relation names in Ampersand. In the table we call them "attributes". So it makes sense to say that a relation in Ampersand can correspond with an attribute in a table.
In theory, the population of the Hawaii-script might just as well be given in a spreadsheet. This works in practice too. It looks like this:
Please copy this in a spreadsheet of your own. The element in the first column with square brackets tells Ampersand that a new table starts. The first row contains relation names. The second row contains concept names. The rows that follow contain pairs. Ampersand reconstructs those pairs as in the example above.
In practical applications, you might want to reuse data from existing spreadsheets. People tend to have lots of "informal administration" in spreadsheets, which gives you access to authentic population. Surely you need that data organized in rows, but fortunately that is reasonably common. In such cases, you just add two lines above each table to inform Ampersand about the relations that are populated. In other cases, you have some work organizing the spreadsheet for importing it.
You will find the Excel import function in the menu bar on the top right of your screen
.
This is what your upload screen looks like:
You can upload one or more .xlsx-files by dropping them in the drop zone or by selecting them. You have to upload the population with the green
Upload
button. At that time, all population from the .xlsx-file is added to the context and checked for inconsistencies. As a result, you may get errors when uploading. Only error-free spreadsheets will be uploaded successfully. As long as an error remains, the population in your context will not change.
Make a population of your own for the Hawaii-script and put it in a .xlsx spreadsheet. As described above. Make sure to delete the population statements from your Hawaii source code, to make sure that you get to see the population from your .xlsx-file. Generate a prototype from your Hawaii-application, upload your population in Excel and play around with the results.
After finishing your assignment, you have learned:
to upload population to your Ampersand application in the form of a spreadsheet in .xlsx-format;
to understand how a POPULATION
-statement relates to the contents of a spreadsheet;
that the contents of the spreadsheet is added to the population of your context, provided this does not lead to any conflict.
firstname
lastname
birth
1
Abraham
Lincoln
February 12, 1809
2
Barack
Obama
August 4, 1961
3
Calvin
Coolidge
July 4, 1872
4
Dwight
Eisenhower
October 14, 1890
[Subject]
pass
required
Subject
Student
Destination
Surfing
Brown
Hawaii
Surfing
Conway
Latin
Brown
Rome
World Religions
Applegate
World Religions
Brown
Rome
This statement is a rule, which defines an identity on a concept. It is syntactic sugar for specifying a set of relations that identify atoms in a specific concept. For example, if relations pi
and rho
determine an atom of concept T
uniquely, you can write:
As the IDENT statement defines a rule, it can be in the same places as any other RULE.
where:
<label>
is the name of the rule. It can be a single word or a string (enclosed by double brackets). It is followed by a colon (:
) to distinguish the label from the concept that follows.
<Concept>
is the name of the Concept for atoms of which the rule specifies an identity
Between brackets are terms whose source concept must be <Concept>
. This is enforced by the type system.
translates into the following rule:
Note that
in case everye
is both univalent and total, e<>e~
equals e;e~
, and the rule is equivalent to:
in case every e
is univalent but not total, you should use the IDENT
statement (or the rule that it implements), because that also works when an e
is not populated.
The purpose of a rule is to constrain data. Refer to the chapter about rules in the tutorial for examples and a practice oriented explanation.
A rule statement defines something that should be true. It does not define the enforcement.
A <rule>
has the following syntax:
A <label>
is optional. It can be a single word or a string (enclosed by double brackets) followed by a colon (:
).
An expression can be any of:
Expression BinaryOperator Expression
UnaryOpPre Expression
Expression UnaryOpPost
a (reference to a) relation (including an optional signature, when required to disambiguate):
A relation by name
I
(the Identity relation)
V
(carthesian product) Note that this can also be used to denote the empty relation, by using the unary negation operator: '-v'
A singleton expression (the value of an atom)
an expression enclosed in brackets.
The following operators are available to build expressions:
Binary operators
equivalence: =
composition: ;
inclusion: |-
intersection: /\
union: \/
difference: -
left residual: /
right residual: \
diamond: <>
relative addition: !
cartesian product: #
Unary operator (pre-operator)
complement: -
Unary operators (post-operator)
conversion (flip): ~
Reflexive, transitive closure: *
(Kleene star) --currently not implemented
transitive closure: +
(Kleene plus) --currently not implemented
The meaning of a rule can be written in natural language in the Meaning part of the RULE statement. It is a good habit to specify the meaning! The meaning will be printed in the functional specification. The meaning is optional.
The <text>
part is where the the meaning is written down. We support both:
a simple string, enclosed by double quotes
any text, starting with {+
and ending with -}
The optional language is specified as
IN ENGLISH
or
IN DUTCH
.
The optional Markup is one of :
REST
(Restructured text)
HTML
LATEX
MARKDOWN
If you need specific markup, there are several options to do so. The default markup is used, but you can override that here. We rely on Pandoc to read the markup.
Messages may be defined to give feedback whenever the rule is violated. The message is a predefined string. Every message for a rule should be for another Language.
A violation message can be constructed so that it gives specific information about the violating atoms:
Every segment must be of one of the following forms:
TXT
String
SRC
Expression
TGT
Expression
A rule is violated by a pair of atoms (source, target). The source atom is the root of the violation message. In the message the target atoms are printed. With the Identity relation the root atom itself can be printed. You can use an expression to print other atoms. Below two examples reporting a violation of the rule that each project must have a project leader. The first prints the project's ID, the second the project's name using the relation projectName:
VIOLATION ( TXT "Project ", SRC I, TXT " does not have a projectleader")
VIOLATION ( TXT "Project ", SRC projectName, TXT " does not have a projectleader")
By default rules are invariant rules. By preceding the rule statement with a role specification for this rule, the rule becomes a process rule.
tbd