Rules validation for travel planning system6377932Abstract An airline travel planning system is described. The system includes a server computer executing a server process including a search process to search for set of pricing solutions in accordance with at least one destination and at least one origin. The search process represents the set of pricing solutions in the form of a directed acyclic graph. The system also includes a client computer executing a client process on the set of pricing solutions. The client process has a manipulation process that manipulates the set of pricing solutions in response to user preferences. Several processes are described including a process responsive to user preferences and to set of pricing solutions that provides pricing solutions sorted by said user preference, a process that sorts set of pricing solutions to produce a subset of said set of pricing solutions in accordance with user specified preferences, and a process that prunes from the directed acyclic graph nodes that are no longer contained within the subset of set of pricing solutions. Claims What is claimed is: Description BACKGROUND
TABLE 1
Node Type Children Object
0 OR Nodes 1, 2, 3
1 AND Nodes 10, 14,
17, 17
2 AND Nodes 4, 5
3 AND Nodes 13, 15,
19, 19
4 OR Nodes 8, 9
5 OR Nodes 6, 7
6 AND Nodes 14, 16
7 AND Nodes 15, 18
8 AND Nodes 13, 16
9 AND Nodes 13, 18
10 OR Nodes 11, 12
11 Itin. Slice 1: BOS.fwdarw.LAX UA023
12 Itin. Slice 1: BOS.fwdarw.DFW UA100,
DFW.fwdarw.LAX UA103
13 Itin. Slice 1: BOS.fwdarw.SAN NW222
14 Itin. Slice 2: LAX.fwdarw.BOS UA515
15 Itin. Slice 2: SAN.fwdarw.BOS NW223
16 Fare UA BOS-LAX One-way "Y"
17 Fare UA BOS-LAX Round-trip "QE7NR"
18 Fare NW BOS-SAN One-way "F"
19 Fare NW BOS-SAN Round-trip "H7NR"
This pricing-graph represents a total of nine pricing solutions. These solutions can be extracted from the pricing-graph descending from the root node, node 0. At every OR node a choice between children is made, and the choice determines the pricing-solution that results. At every AND node each child branch is descended, and the results are combined. The term BOS.fwdarw.LAX UA023 is an itinerary which uses standard nomenclature to represent airports BOS and LAX, airline UA, and flight number 023. In general, conventional nomenclature used in the airline industry will be used herein. The set of pricing-solutions that represented in the pricing-graph is presented in TABLE 2 below.
TABLE 2
Solution
Number Itineraries Fares
1 Slice 1: BOS.fwdarw.LAX UA023 UA BOS-LAX RT "QE7NR"
Slice 2: LAX.fwdarw.BOS UA515 UA BOS-LAX RT "QE7NR"
2 Slice 1: BOS.fwdarw.LAX UA023 UA BOS-LAX OW "Y"
Slice 2: LAX.fwdarw.BOS UA515 UA BOS-LAX OW "Y"
3 Slice 1: BOS.fwdarw.LAX UA023 UA BOS-LAX OW "Y"
Slice 2: SAN.fwdarw.BOS NW223 NW BOS-SAN OW "F"
4 Slice 1: BOS.fwdarw.DFW UA100, UA BOS-LAX RT "QE7NR"
DFW_LAX UA103
Slice 2: LAX.fwdarw.BOS UA515 UA BOS-LAX RT "QE7NR"
5 Slice 1: BOS.fwdarw.DFW UA100, UA BOS-LAX OW "Y"
DFW_LAX UA103
Slice 2: LAX.fwdarw.BOS UA515 UA BOS-LAX OW "Y"
6 Slice 1: BOS.fwdarw.DFW UA100, UA BOS-LAX OW "Y"
DFW_LAX UA103
Slice 2: SAN.fwdarw.BOS NW223 NW BOS-SAN OW "F"
7 Slice 1: BOS.fwdarw.SAN NW222 NW BOS-SAN OW "F"
Slice 2: LAX.fwdarw.BOS UA515 UA BOS-LAX OW "Y"
8 Slice 1: BOS.fwdarw.SAN NW222 NW BOS-SAN RT "H7NR"
Slice 2: SAN.fwdarw.BOS NW223 NW BOS-SAN RT "H7NR"
9 Slice 1: BOS.fwdarw.SAN NW222 NW BOS-SAN OW "F"
Slice 2: SAN.fwdarw.BOS NW223 NW BOS-SAN OW "F"
The pricing-graph encodes the requirement that two itineraries are combined, one from slice 1 and one from slice 2, to form a pricing solution. Further, each itinerary is spanned by fares. In this case each pricing solution involves two fares, and round-trip fares are combined with like round-trip fares. In most circumstances, the number of nodes in the pricing-graph is small compared to the number of pricing-solutions those nodes represent. In many cases, a graph of 10,000 or so nodes can represent more than 1,000,000,000 pricing-solutions. Referring now to FIG. 3A, the nodes of the pricing graph corresponding to Table 1 are shown, as an example. This figure illustrates the manner in which nodes in the pricing graph data structure as represented in Table 1 are combined to provide the pricing solutions shown in Table 2. Using pricing solution No. 1 (from TABLE 2) as an example, it can be shown that starting at the top of the graph at node 0, node 0 allows for a choice between nodes 1, 2, and 3. For pricing solution No. 1, Node 1 is chosen. Node 1 is the AND node that points to nodes 10 and 14, and has two pointers to node 17. Node 10 is an OR node which provides a choice of either nodes 11 or nodes 12. Node 11 as shown in FIG. 3A corresponds to a terminal node, the itinerary (BOS-LAX UA 023). Node 12 corresponds to a terminal node, the itinerary BOS-DFN UA 100, DFN-LAX UA 103. This second choice in node 10 will provide pricing solutions corresponding to numbers 4-6, respectively. Therefore, selecting node 11 provides the itinerary for the first slice of solution 1. The fare for pricing solution 1 is provided by node 17 which has two pointers, one for each slice, to the fare "US BOS-LAX RT QE7NR" corresponding to the fare shown for pricing solution no. 1 in Table 2 for the first slice. The second itinerary for pricing solution no. 1 is provided by node 14 which is referenced in AND node 1 that points to the itinerary LAX-BOS UA 515. The corresponding fare is also from terminal node 17 since it is a round trip fare UA BOS-LAX RT QE7NR. A second one of the pricing solutions, for example, the pricing solution 4 incorporating the terminal node 12 is provided by starting at node 0, and using node 1. Node 1 is an AND node requiring that nodes 17 (twice), node 10, and node 14 be included. Node 10 is an OR node as mentioned above and is used to select node 12 which is the itinerary including segments "BOS.fwdarw.DFW UA 100" and "DFW.fwdarw.LAX UA 103". From node 1, node 14 the return itinerary LAX-BOS UA 515 also is reached. Node 17 also is chosen which contain the round trip fares. Similarly, the remaining ones of the pricing solutions can be extracted from the pricing graph in the same manner as the two examples given above. As mentioned above, a graph will typically have many more pricing solutions than nodes in the graph. The example just illustrated in conjunction with FIG. 3A has 9 pricing solutions and 19 nodes which is an exception to that general rule. Another example of a pricing graph which does satisfy that general observation is shown in conjunction with FIG. 3B. Referring now to FIG. 3B, a pricing graph is shown having 43 nodes NO-N42 that when combined represent 856 pricing solutions. Each node in the pricing graph has a number associated with it corresponding to the number of pricing solutions that is represents. In order to make this illustration of manageable size, identifiers (representing the nodes of the terminals) are substituted in the pricing graph for the actual terminal objects of the graph. Thus, as shown in FIG. 3B, outbound and return itineraries, and fare nodes are represented by the Nodes N20-N42 This pricing graph (TABLE 3) has 9 itineraries which can be combined with 14 fares represented by 13 AND nodes and 7 OR nodes. The pricing objects are represented by 23 nodes. The pricing graph has a combined total of 43 nodes to represent 876 pricing solutions. FIG. 3B shows examples of a pricing graph for a round trip LAX-BOS journey. This example shown in FIG. 3B is generally more representative of an outcome of a faring search. That is, generally the pricing graph represents more pricing solutions than nodes contained in the graph.
TABLE 3
Node Type Children Object
0 AND Nodes 1, 6, 11
1 OR Nodes 2, 3, 4
2 AND Nodes 5, 40
3 AND Nodes 41, 41
4 AND Nodes 42, 42
5 OR Nodes 39, 40
6 OR Nodes 7, 8, 9
7 AND Nodes 20, 10
8 AND Nodes 21, 10
9 AND Nodes 22, 10
10 OR Nodes 23, 24,
25, 26
11 OR Nodes 12, 13, 14,
16, 17, 18
12 AND Nodes 27, 15
13 AND Nodes 28, 15
14 AND Nodes 29, 15
15 AND Nodes 30, 31, 32
16 AND Nodes 33, 19
17 AND Nodes 34, 19
18 AND Nodes 35, 19
19 OR Nodes 36, 37, 38
20 Itin. Slice 1: LAX.fwdarw.DFW NW100,
DFW.fwdarw.BOS AA223
21 Itin. Slice 1: LAX.fwdarw.DFW NW137,
DFW.fwdarw.BOS AA223
22 Itin. Slice 1: LAX.fwdarw.DFW NW137,
DFW.fwdarw.BOS AA414
23 Fare DFW, LAX NW "Y" OW
24 Fare DFW, LAX NW "F" OW
25 Fare DFW, LAX NW "C" OW
26 Fare DFW, LAX NW "QA7" OW
27 Itin. Slice 2: BOS.fwdarw.DFW AA67,
DFW.fwdarw.LAX CO716
28 Itin. Slice 2: BOS.fwdarw.DFW AA67,
DFW.fwdarw.LAX CO717
29 Itin. Slice 2: BOS.fwdarw.DFW AA67,
DFW.fwdarw.LAX CO719
30 Fare DFW, LAX CO "F" OW
31 Fare DFW, LAX CO "C" OW
32 Fare DFW, LAX CO "Y" OW
33 Itin. Slice 2: BOS.fwdarw.DFW AA852,
DFW.fwdarw.LAX DL186
34 Itin. Slice 2: BOS.fwdarw.DFW AA852,
DFW.fwdarw.LAX DL180
35 Itin. Slice 2: BOS.fwdarw.DFW AA852,
DFW.fwdarw.LAX DL343
36 Fare DFW, LAX DL "F" OW
37 Fare DFW, LAX DL "C" OW
38 Fare DFW, LAX DL "Y" OW
39 Fare DFW, BOS AA "QE7NR" RT
40 Fare DFW, BOS AA "QE7IP" RT
41 Fare DFW, BOS AA "QE14NR" RT
42 Fare DFW, BOS AA "QE21NR" RT
THE FARING SYSTEM Referring now to FIGS. 4A and 4B, the faring process 18 includes a process 80 to retrieve itinerary sets for all slices in an itinerary. The itinerary sets are provided from the scheduler process 16 for each slice of a journey where a slice corresponds to a direction of travel. Thus, for example, for a round trip journey there would be two slices, one for the outbound part of the journey and one for the return part of the journey. The faring process 18 decomposes 82 the itinerary into faring atoms. As used herein, faring atoms refer to a sequence of flight segments or equivalently legs that are spanned by a single fare. For example, the itinerary UA005 from DFW to BOS at 12:30 on 12NOV UA010 from BOS to YYZ at 18:00 on 12NOV AC121 from YYZ to YVR at 01:00 on 13NOV permits the following faring-atoms as shown in TABLE 4.
TABLE 4
Faring-Atom Number Legs and Departure Times
1 DFW.fwdarw.BOS UA005 12NOV 12:30
2 BOS.fwdarw.YYZ UA010 12NOV 18:00
3 DFW.fwdarw.BOS UA005 12NOV 12:30
BOS.fwdarw.YYZ UA010 12NOV 18:00
4 YYZ.fwdarw.YVR AC121 13NOV 01:00
A faring atom is represented by a data structure that preferably includes the following fields as shown in TABLE 5:
TABLE 5
Faring-Atom fields Use
legs-and-departure-times A list of legs and their departure times and
dates.
faring-market The faring-market that this faring-atom is in.
cached-results A storage space used to eliminate redundant
computation in the rule-checking process. As
rule record-2s are applied to faring-atoms, the
results are stored in this field. If the same
record-2 is applied again, the answer is
retrieved rather than recomputed.
priceable-unit-labels A list of the priceable-unit-labels that the
faring-atom enters into.
After the faring process 18 decomposes the itineraries into faring atoms, the faring process 18 retrieves fares 84 and rules 86 for each faring atom by accessing the fares/rules database 20a mentioned above. At this point a fare's routing is retrieved from a routing database and applied to a faring atom. If the routing test fails, the fare cannot be applied to the faring atom and a fare component is not built. The faring process 18 applies the rules 88 to the faring atoms to produce fare components. Fare-components are combinations of faring-atoms and fares. Fare-components (TABLE 6) are produced if a fare's rules pass a preliminary check on a faring-atom. They are used to store deferred rules (e.g., deferred record-2s and combinability record-2s) that are applied at a later stage of processing 88a. Fare components also store extra information produced during the rule-checking process, such as information about surcharges and penalties and discounts that are applied to the base fare price.
TABLE 6
Fare-Component fields Use
fare The fare-component's fare.
faring-atom The fare-component's faring-atom.
deferred-record-2s A list of non-category-10 record-2s that have
not been fully evaluated.
combinability-record-2 If the fare's rules include a category-10
("Fare Combinability" record-2, it is stored
here.
surcharges A list of surcharges, penalties, discounts and
other pieces of information produced during
the rule-checking process.
From the fare components the faring process 18 constructs 90 priceable units. For certain types of rules such as those which require access to fares and/or flights from outside of the fare component, those rules are stored in the fare component for later or deferred evaluation. The priceable unit process 90, takes valid fare components and constructs priceable units from the fare components. This process 90 involves grouping fare components from different slices and checking fare component combination restrictions. At this stage of processing, the rules deferred in step 88 are reapplied. Priceable units are represented by priceable-unit-cores and priceable-unit-labels. Priceable-unit-cores are collections of fares and other information associated with fares within a priceable-unit, such as discounts and penalties and surcharges. Priceable-unit-cores (TABLE 7) are referenced by priceable-unit-labels.
TABLE 7
Priceable-Unit-Core
fields Use
fares A list of fares.
slice-numbers A list of the slices the fares originate from.
surcharges A list of surcharges, penalties, discounts and
other pieces of information produced during the
rule-checking process.
Priceable-unit-labels group a set of priceable-unit-cores with sets of faring-atoms. Together, they are used to represent sets of priceable-units (TABLE 8).
TABLE 8
Priceable-Unit-Label
fields Use
priceable-unit-cores A set of priceable-unit cores.
slice-numbers A list of the slices the fares and faring-atoms
originate from.
faring-atom-sets A list of sets of faring-atoms, one per slice.
When all the fare components within a priceable unit are known, rules that were deferred from the processing 88 are applied 92 to the priceable unit sets of faring atoms. After evaluation of the deferred record-2s at the priceable unit stage, the itineraries and priceable units are grouped together into complete set of pricing solutions. This occurs by a link process 94 that links itineraries to corresponding pricing units from different slices to provide 96 the pricing solution. At this juncture, any remaining cross priceable unit fare combinability checks are performed to eliminate invalid combinations. The linking process involves two additional data structures slice-label-sets and open-label-sets. Slice-label-sets group itinerary divisions by the multi-slice priceable-unit-labels they can enter into. In each slice of a journey, a unique slice-label-set is constructed for every set of multi-slice priceable-unit-labels. Each slice-label-set stores both the set of multi-slice priceable-unit-labels and a set of itinerary-label-holders, which contain single-slice priceable-unit-labels on a per-itinerary basis. Each slice-label-set is a pair of an itinerary and a set of division-label-holders. Each of these division-label-holders is a pair of a division and a set of sets of single-slice priceable-unit-labels (TABLE 9).
TABLE 9
Use
Slice-Label-Set fields
multi-slice-PU-labels A set of multi-slice PU-labels.
itinerary-label-holders A set of itinerary-label-holders.
Itinerary-Label-Holder fields
itinerary An itinerary.
division-label-holders A set of division-label-holders.
Division-Label-Holder fields
division An itinerary division.
single-slice-PU-label-sets A set of sets of single-slice PU-labels.
Open-label-sets (TABLE 10) are used to summarize the state of the linking process 94. Each is a set of "open" multi-slice priceable-unit-labels and a set of backward-links. Each of these backward-links is a pair of a slice-label-set and an open-label-set.
TABLE 10
Use
Open-Label-Set fields
open-PU-labels A set of open multi-slice FU-labels.
backward-links A set of backward-links.
Backward-Link fields
slice-label-set A slice-label-set.
open-label-set An open-label-set.
The pricing solution resulting from the linking process 94 is used to construct a pricing graph from the various data structures built during the preceding processes. This pricing graph is transmitted to the client process or can be stored for later use or transmission. A pseudocode representation of the high level processing logic involved in the above search procedure is set out below in TABLE 11.
TABLE 11
price-itinerary-sets(itinerary-sets, fare-database, rule-database,
routing-database, environmental-information)
//
// itinerary-sets is a set of sets of itineraries, one per slice.
// environmental-information contains information about the passenger,
the current date, the location
// where tickets will be purchased, and other non-itinerary-based
information that is necessary for applying
// fare rules.
//
Let faring-market-sets = {}
// Construct itinerary-divisions, faring-markets and faring-atoms.
Let slice-number = 1
For itinerary-set in itinerary-sets
//
// create-divisions constructs the itinerary-divisions,
faring-markets and faring-atoms for
// all the itineraries within a slice. It returns a set of
faring-markets.
faring-market-sets += create-divisions(itineraries, slice-number,
fare-database)
slice-number += 1
// Apply fare rules, constructing fare-components in each
faring-market.
For faring-market-set in faring-market-sets
//
// apply-fare-rules constructs fare-components for each faring-market
within a slice.
// This process contains pseudo-code for apply-fare-rules.
apply-fare-rules(faring-market-set, fare-database, rule-database,
routing-database, environmental-information)
// Create priceable-units.
// for create-priceable-units
create-priceable-units(faring-market-sets)
// Link itineraries between slices. This procedure returns either nil,
if there are no pricing-solutions, or
// a "root" open-label-set. This process is described in
link-itineraries
Let root-object = link-itineraries(itinerary-sets)
If (root-object = nil)
return(nil)
// Create the pricing-graph from the data-structures that have been
built in the preceding steps.
// This process includes psedo-code for create-pricing-graph.
Let root-node = create-pricing-graph(root-object)
// Return the pricing graph.
return(root-node)
Referring now to FIG. 5, the process 82 to decompose an itinerary into faring atoms includes a retrieval process 100 that retrieves all itineraries for all slices in a journey. For each itinerary in each slice, the process 82 groups faring atoms by faring markets at 104 and partitions itineraries into the divisions of faring atoms at 106. Referring now to FIG. 6, itineraries are partitioned into divisions of faring atoms by examining 110 for each itinerary whether or not the itinerary includes more than one leg 112 on the same airline 114. For each sequence on the same airline, a faring-atom is produced. If the sequence has more than one leg, the sequence is also split into multiple faring-atoms (at 116), resulting in more than one division of the itinerary into a set of faring-atoms. The process checks 118 whether fares exist for the airline in the markets spanned by each faring atom. Otherwise, the process will branch from the examination process 112 and the airline check process 114 to a fare check process 118 to check in the fare database 20a that a fare exists for the airline in the market spanned by the faring atom. If all of the faring atoms within a division have at least one fare in the market, a division for the market is produced at 120. Another possible implementation creates divisions by producing all possible partitions of legs into faring-atoms. A high-level pseudocode representation for the algorithm that generates faring atoms, faring markets and faring divisions for each itinerary within a slice is set forth below in TABLE 12.
TABLE 12
create-divisions(itineraries, slice-number, fare-database)
Let faring-atoms = {}
Let faring-markets = {}
Subroutine get-faring-market(origin-airport, destination-airport,
airline)
Let origin-city = city(origin-airport)
Let destination-city = city(destination-airport)
Let previous-faring-market = find(<origin-city, destination-city,
airline>, faring-markets)
If (previous-faring-market)
return(previous-faring-market)
Else
If (fares-exist(origin-city, destination-city, airline))
Let faring-market = new-faring-market()
faring-market.slice-number = slice-number
faring-market.origin-city = origin-city
faring-market.destination-city = destination-city
faring-market.airline = airline
faring-market.faring-atoms = {}
faring-markets += faring-market
return(faring-market)
Else
return(nil)
Subroutine get-faring-atom(legs-and-departure-times, origin-airport,
destination-airport, airline)
Let previous-faring-atom = find(legs-and-departure-times,
faring-atoms)
If (previous-faring-atom)
return(previous-faring-atom)
Else
Let faring-market = get-faring-market(origin-airport,
destination-airport, airline)
If (faring-market <> nil)
Let faring-atom = new-faring-atom()
faring-atom.faring-market = faring-market
faring-atom.legs-and-departure-times = legs-and-departure-times
faring-atom.priceable-unit-labels = {}
faring-atom.cached-results = {}
faring-market.faring-atoms += new-faring-atom
faring-atoms += faring-atom
return(faring-atom)
Else
return(nil)
Subroutine get-online-divisions(legs-and-departure-times,
origin-airport, destination-airport, airline)
Let online-divisions = {}
Let number-of-legs = length(legs-and-departure-times)
Let single-faring-atom = get-faring-atom(legs-and-departure-times,
origin-airport, destination-airport, airline)
If (single-faring-atom <> nil)
online-divisions += list(single-faring-atom)
For i from 1 to number-of-legs - 1
Let legs-and-departure-times1 = legs-and-departure-times[1 . . . i]
Let legs-and-departure-times2 = legs-and-departure-times[i+1 . . .
number-of-legs]
Let destination-airport1 = destination-airport(faring-atom-legs1)
Let origin-airport2 = origin-airport(faring-atom-legs2)
If (is-not-same-flight-segment(legs-and-departure-times1,
legs-and-departure-times2))
Let faring-atom1 = get-faring-atom(legs-and-departure-times1,
origin-airport,
destination-airport1, airline)
Let faring-atom2 = get-faring-atom(legs-and-departure-times2,
origin-airport2,
destination-airport, airline)
If (faring-atom1 <> nil and faring-atom2 <> nil)
online-divisions += list(faring-atom1, faring-atom2)
return(online-divisions)
For each itinerary in itineraries
Let divisions = { {} }
Let legs-and-departure-times = itinerary.legs-and-departure-times
Referring now to FIG. 7, a process 88 to apply the faring rules to faring atoms is shown. The input to the application process 88 includes the fare/rules database 20a and faring markets 130. For each faring atom in each faring market, a fare and corresponding rules are retrieved 132 from fare/rules database 20a. The rules are applied to the faring-atoms at 134. Because faring-atoms are shared across itineraries, it is only necessary to apply a fare's rules to a faring atom once no matter how many itineraries the faring-atom may appear in. The results of rule applications are cached 136. Caching of a rule minimizes computational effort. This is because the rule application process 88 involves many redundancies, because different fares share rule restrictions. Valid fare/faring-atom combinations are stored 138 in the form of fare-components. Referring to FIGS. 8A and 8B, a process 132 for retrieving rules and footnotes from the rules database 20a containing the ATPCO rules, routes and fares includes retrieving 150 general rules commonly referred to as record_0's for each faring atom in a faring market. The retrieved general rules are searched 152 to find the first record_0 matched to the faring atom to produce a matched record_0. If there is a matched record_0, it is stored at 154. Whether or not there are matched record_0's, the process 132 retrieves 156 application rules commonly referred to as record_1 rules. The retrieved application rules are searched to find 158 the first record_1 matched to each of the faring atoms. The first matched record_1's is stored 160. If after traversing through all the record_1's there are no matches found, the process will return a "FAIL" at 162 and terminate indicating that the faring atom cannot be used by the faring process 18. If there is a match, the process 132 retrieves 164 category controls (commonly referred to as record_2's). The process 132 will find 166 the first record-2 in each category that matches the fare. Record_2's or the category control records typically comprise a large number of categories currently 30 different categories. The process is run for each category. It is not necessary that every category have a match and in many instances many if not most categories will not have a match. Rules in those categories that have a match are stored at 168 and the process continues to run at 170 until all categories have been traversed. If all categories have not been traversed, a pointer to a next category 172 is set and the next category is retrieved 164. Record-3's are retrieved 176 as part of the rule application process 132. The ATPCO rule retrieval process 132 that retrieves the rules for a fare includes record-matching processes 150, 156, and 164(FIG. 8A) that may depend on the departure date of the faring-atom. To minimize computational effort expended in rule retrieval 132, rules for a fare are not retrieved once for every faring-atom, but at most once per departure-date. To further minimize computation, a caching mechanism is employed. Referring now to FIG. 8C, a process that checks dates for rule retrieval includes retrieving 177 a current date from a faring market that contains faring atoms with multiple travel dates, and a stored date corresponding to a latest stored date that a result for the rule remains valid. The current date is compared 178 to the stored date and if the rule still remains valid (i.e., the current date falls within a bound set by the stored date) the rule is not retrieved and instead rules that had been cached are used. If the stored date for the rule is not valid then a new rule is retrieved 179 and a new date is subsequently stored 180 for the new rule. Referring now to FIG. 9, a process 134 for applying the rules retrieved with process 132 is shown. The rule application process 134 operates on each faring atom. The process 134 applies 181 the record-1 records to check for booking codes etc. The process 134 determines 182 whether each record-2 was cached in the faring atom. If a record-2 was cached in the faring atom, the process returns 183 the cached results. Otherwise, the process 134 applies 184 the record_2's for each of the stored record_2 categories. Rules provisions are expressed as "record_2s", which are retrieved 132, as described in FIGS. 8A and 8B. These record_2s express logical relations over so called "record_3s", which are records that contain detailed provisions. Individual procedures are provided for evaluating each record_3 as applied to a faring atom. Each record_3 procedure returns either DEFER, FAIL, PASS, NO_MATCH or UNAVAILABLE, and these results are combined according to the logic in the record_2 to produce a result of either DEFER, FAIL or PASS for the entire record_2. The proper procedures for applying record_3s and for combining their results according to record_2s are described in the ATPCO documentation. The "PASS" value is an extension used here since not all record_3s can be fully evaluated on the basis of the faring-atom alone. The RECORD_2 result is either PASS, FAIL or DEFER (the other two values are from record_3s). As a result of returning a cached result or of the application of the record_2's, the process can return one of five possible results, "DEFER", "PASS", or "FAIL." The record as well as its results DEFER, PASS, or FAIL, are cached at 136 in the faring atom. The result FAIL causes the process 134 to exit 190. Whereas, returning a pass or a defer permits the process 134 to continue to examine remaining record-2s. A defer or pass result is stored 185 and it is determined 186 whether all record-2s have been processed. If all records have not been applied/examined if cached, the next record-2 is retrieved at 186a. After all record-2s have been examined, if pass results have been provided for all, the PASS result causes the process 134 to construct 188 fare components and exit 190. If at least one DEFER result was returned process 134 constructs 187 the fare components, stores 189 deferred record-2's in the faring component and exits 190. The routines 188, 189 and 190 thus correspond to the stored valid faring atom combination routine 138 (FIG. 7). APPLICATION OF RECORD-3S The information contained in record-3s varies by category. For example, category-5 record-3s, which specify advanced-purchase restrictions, contain fields that specify how long in advance of travel time a fare must be reserved, how long after a reservation a fare must be purchased, and so on. Category-4 record-3s, which specify flight-restrictions, contain fields that restrict flight-numbers, aircraft-type, airline, and whether flights are direct or non-stop. Every category has a different procedure for evaluating a faring-atom. As discussed above the record-3 procedures that evaluate a faring-atom returns one of five values, and may return some other information such as discounts, penalties and surcharges. A value of PASS or FAIL can only be returned if that answer can be determined without examining any faring-atom other than the one the fare spans. The ATPCO rules distinguish between fare-component and priceable-unit restrictions. Most restrictions on travel route, flight-numbers, and aircraft-type are fare-component-based, i.e., restrict only the flights in the faring-atom governed by the fare. On the other hand, minimum and maximum-stay restrictions are priceable-unit-based, i.e., apply to joint properties of all the faring-atoms within a priceable-unit. A minimum-stay requirement for a round-trip fare, for example, constrains the combination of outbound and return faring-atoms. Generally speaking, FC-based record-3s will be able to return either PASS or FAIL, while PU-based restrictions may need to be deferred. Deferring rules means checking them at a later point, however. This is a more computationally expensive process, because it must be done for combinations of faring-atoms within a priceable-unit, and the number ways faring-atoms can be combined to create priceable-units can be quite large, and grows quickly with the size of the priceable-unit. For this reason, whenever possible it is desirable for record-3 application not to result in a value of DEFER. Many properties of faring-atoms can be bounded. For example, the earliest and latest departure-time within a faring-market, or within a slice, can be recorded, as well as the minimum and maximum number of connections within the faring-market and so forth. This information can often be used to evaluate priceable-unit restrictions at the fare-component level. A simple example of this is given below. In this example, it is assumed that a certain fare's rules require at least a 3-day layover at the intermediate point of a round-trip priceable-unit, measured from the departure-times of the fare-components. The fare is used for the first half (outbound travel) of the priceable-unit, in the NW CHI_MSP faring-market in slice 1. If there are exactly two slices in the query, then the fare-component that covers return travel must come from the NW MSP_CHI faring-market in slice 2. Suppose that the following faring-atoms exist (TABLE 13). (The airport ORD is in the city Chicago.)
TABLE 13
Slice 1 NW CHI_MSP Slice 2 NW MSP_CHI
faring-atoms faring-atoms
ORD_MSP NW220 MSP_ORD NW301
12APR97 13:00 15APR97 19:00
ORD_MSP NW220 MSP_ORD NW577
13APR97 13:00 16APR97 12:00
ORD_MSP NW220 MSP_ORD NW301
14APR97 13:00 16APR97 19:00
In each faring-market, the earliest and latest departure-times can be calculated. In this case, the earliest departure-time in the slice-2 NW MSP_ORD market is Apr. 15, 1997 19:00, and the latest departure-time is Apr. 16, 1997 19:00. When the minimum-stay requirement restriction is applied to the first faring-atom, its departure time of Apr. 12, 1997 13:00 can be compared to the two outer bounds on return-travel departure-time, Apr. 15, 1997 19:00 and Apr. 16, 1997 19:00. In this case, the minimum-stay requirement is met even for the earliest possible return travel time, so the faring-atom unconditionally passes the restriction. Similarly, for the third faring-atom, since the restriction fails even for the latest possible return-travel departure-time, the faring-atom unconditionally fails the minimum-stay requirement. But for the second faring-atom, because the restriction fails for the earliest possible return time, but passes the latest possible return time, it is necessary to defer the application of the restriction. GENERAL TIME BOUNDS Many priceable-unit-based categories restrict times. Categories 3, 5, 6, 7, 8, 9, 10 and 14 are usually priceable-unit-based. Categories 3 and 14 usually restrict the departure-date of the first flight in a priceable-unit. Category 5 specifies how far in advance of travel fares must be purchased, and this is usually measured from the departure-date of the first flight in a priceable-unit. Categories 6 and 7 specify minimum and maximum-stays at stopovers within a priceable-unit. In many cases these categories do not need to be deferred. This is especially true if, as in the above example, time-bounds are known for other faring-markets in the journey, and the range of faring-markets that might enter into a priceable-unit with the faring-atom in not great. It is a relatively simple matter to record for each faring-market the earliest and latest departure-date of any faring-atom within the faring-market. This can be done as faring-atoms are constructed. The problem remains of how to know what other faring-markets might participate in a priceable-unit with the faring-atom at hand. CATEGORY-3 Pseudo code for an example of a procedure that implements record-3 category-3, "Seasonality Restrictions" is shown in TABLE 15. Each category-3 record-3 an example of which is shown in TABLE 14 specifies a permissible date range for travel, via a start-date and an end-date, either of which may be left blank. The default interpretation of category-3 is that these date restrictions apply to the departure-date of the first flight of the priceable-unit. This interpretation can be modified in two ways. First, if a certain field is set, then the category becomes fare-component based. In other words, the date restrictions apply to the departure-date of the first flight within the fare-component. Second, a geographic specification may be provided that alters the measurement of the departure-date. For example, the geographic specification may dictate that the relevant date is the departure-date of the first transoceanic flight. Category-3s (TABLE 14) also includes a field that specifies whether the record-3 is available. If it is not, that is an indication that some information is missing and the record-3 should not be used for pricing a ticket. In this case, the record-3 application must return UNAVAILABLE. Finally, a category-3 may include a specification of a date range that the category-3 is valid for. If travel is outside of these dates, the record-3 application must return NO-MATCH.
TABLE 14
Category-3 field Example
Earliest Permitted Travel Date nil
Latest Permitted Travel Date 19OCT97
Fare-Component Based false
Geographic Specification nil
Earliest Record-3 Valid Date 15MAY88
Latest Record-3 Valid Date nil
Available true
The logic of the procedure that processes the record-3 is as follows. If the record-3 is not available, UNAVAILABLE is returned. If travel is outside of the valid date-range of the record-3, NO-MATCH is returned. Then, processing branches depending on whether the record-3 is priceable-unit based (the default), or fare-component based. If fare-component based, and there is no geographic specification, the departure date of the faring-atom is compared to the date-range of the record-3, and either PASS or FAIL is returned. If a geographic specification is provided, then this is used to compute the relevant travel date, and the same procedure applies. If, on the other hand, the record-3 is priceable-unit based, then broad time-bounds checks are used. If there is no geographic specification, the earliest and latest possible priceable-unit departure-dates are retrieved and compared to the date-range of the record-3. If they both succeed, PASS is returned. If they both fail, FAIL is returned. Otherwise DEFER is returned. Finally, if the record-3 is priceable-unit based and includes a geographic specification, then DEFER is returned. The following pseudo-code implements the processing of record-3 category-3 in the case where the record-3 must be evaluated given only a single faring-atom from the priceable-unit.
TABLE 15
apply-record-3-FC-category-3(record-3, faring-atom, passenger-information,
current-date)
If (record-3.available = false)
return(unavailable)
Let date = departure-date(faring-atom)
If ((record-3.earliest-record-3-valid-date <> nil and
record-3.earliest-record-3-valid-date > date) or
(record-3.latest-record-3-valid-date <> nil and
record-3.latest-record-3-valid-date < date))
return(no-match))
If (record-3.fare-component-based = true)
Let travel-date = date
If (record-3.geographic-specification <> nil)
travel-date =
apply-geographic-specification(record-3.geographic-specification,
faring-atom)
If ((record-3.earliest-permitted-travel-date <> nil and
record-3.earliest-permitted-travel-date > travel-date) or
(record-3.latest-permitted-travel-date <> nil and
record-3.latest-permited-travel-date < travel-date))
return(fail)
Else
return(pass)
Else If (record-3.geographic-specification <> nil)
return(defer)
Else
Let earliest-travel-date =
earliest-priceable-unit-departure-date(faring-atom)
Let latest-travel-date =
latest-priceable-unit-departure-date(faring-atom)
Let result = pass
If (record-3.earliest-permitted-travel-date <> nil)
If (record-3.earliest-permitted-travel-date >
latest-travel-date)
result = fail
Else If (record-3.earliest-permitted-travel-date <=
earliest-travel-date)
result = defer
If (record-3.latest-permitted-travel-date <> nil)
If (record-3.latest-permitted-travel-date <
earliest-travel-date)
result = fail
Else If (result <> fail and
record-3.latest-permitted-travel-date >= latest-travel-date)
result = defer
return(result)
There can be another version of this application procedure, as shown in TABLE 16 dedicated to the case where all of the faring-atoms within the priceable-unit are known. This procedure is simpler, because there is no need for time bound checks since all times are known exactly. This procedure is used to evaluate deferred record_3's (see TABLE 24).
TABLE 16
apply-record-3-PU-category-3(record-3, fares, faring-atoms,
prime-faring-atom, passenger-information, current-date)
If (record-3.available = false)
return(unavailable)
Let date = departure-date(prime-faring-atom)
If ((record-3.earliest-record-3-valid-date <> nil and
record-3.earliest-record-3-valid-date > date) or
(record-3.latest-record-3-valid-date <> nil and
record-3.latest-record-3-valid-date < date))
return(no-match))
Let travel-date = date
If (record-3.fare-component-based = true)
If (record-3.geographic.specification <> nil)
travel-date =
apply-geographic-specification(record-3.geographic-specification,
prime-faring-atom)
Else
travel-date = departure-date(faring-atoms)
If (record-3.geographic-specification <> nil)
travel-date =
apply-geographic-specification(record-3.geographic-specification,
faring-atoms)
If ((record-3.earliest-permitted-travel-date <> nil and
record-3.earliest-permitted-travel-date > travel-date) or
(record-3.latest-permitted-travel-date <> nil and
record-3.latest-permited-travel-date < travel-date))
return(fail)
Else
return(pass)
Referring now to FIG. 10, the process 90 for constructing priceable units is shown. The term "priceable unit" as used herein represents a fundamental unit at which many fare restrictions apply. For example, round trip fares often include minimum stay requirements and these can only be expressed when both an outbound and a return faring atom are combined. This occurs at the level of the priceable unit. The process 90 of constructing priceable unit cores and pricing unit labels is organized as several nested procedures as follows. The process enumerates 200 a collection of faring markets. Collections of faring markets are enumerated 200 with each faring market from a different slice by an algorithm that depends on the type of a priceable unit that is constructed. For example, for a round trip priceable unit two faring markets are chosen on the same carrier and between the same cities but in opposite directions. The process 90 also enumerates collections of sets of faring components at 202. For each faring market in a collection of faring markets its faring components are partitioned into sets of fare components that have the same fare and the same combinability record-2s. Collections of these sets are enumerated with one set chosen from each faring market resulting in a collection of fares and associated collection of sets of fare components. At this juncture, any combinability record 2-s are evaluated to insure that the fares may be used together in a priceable unit. The process 90 also enumerates 204 collections of fare components. Thus, given a collection of sets of fare components from 202, the process evaluates any deferred record 2-s on collections of fare components in the enumeration process 204. These collections are constructed by selecting one fare component from each set. The process of evaluating deferred rules on collections of fare components outputs results in the form of a list of factored representations of priceable units. Thus, the output is a logical OR of logical ANDs of logical ORs of fare components. From the factored representations produced in 204 the process produces priceable-unit-labels 206 and priceable-unit-cores 208 with some sharing occurring between these structures to ensure that the number of priceable-unit-cores and priceable-unit-labels is kept to a minimum. The pseudo-code below (TABLE 17) summarizes enumerating collections of faring markets process 200. It takes as input a set of sets of faring-markets, containing one set per slice. These are the faring-markets generated by the calls to "create-divisions" (120 FIG. 6), as described above.
TABLE 17
create-priceable-units(faring-market-sets)
Let number-of-slices = length(faring-market-sets)
Let priceable-unit-labels = {}
For slice-number1 from 1 to number-of-slices
For faring-market1 in faring-market-sets[slice-number1]
Let airline = faring-market1.airline
// Create one-way priceable-units.
priceable-unit-labels = create-PUs-in-markets1(faring-market1,
priceable-unit-labels, one-way)
For slice-number2 from slice-number1 + 1 to number-of-slices
For faring-market2 in
faring-markets-on-carrier(faring-market-sets[slice-number2], airline)
// Create single and double open-jaws.
priceable-unit-labels = create-PUs-in-markets2(faring-market1,
faring-market2,
priceable-unit-labels, open-jaw)
If (faring-market1.destination-city = faring-market2.origin-city)
// Create round-trips and circle-trips of size 2.
If (faring-market2.destination = faring-market1.origin)
priceable-unit-labels = create-PUs-in-markets2(faring-market1,
faring-market2,
priceable-unit-labels, round-trip)
priceable-unit-labels = create-PUs-in-markets2(faring-market1,
faring-market2,
priceable-unit-labels, circle-trip2)
For slice-number3 from slice-number2 + 1 to number-of-slices
For faring-market3 in
faring-markets-on-carrier(faring-market-sets[slice-number3], airline)
If (faring-market2.destination-city =
faring-market3.origin-city)
// Create circle-trips of size 3.
If (faring-market3.destination-city =
faring-market1.origin-city)
priceable-unit-labels =
create-PUs-in-markets3(faring-market1, faring-market2,
faring-
//
// More iterations for circle-trips of lengths 4 and 5.
//
. . .
// Store priceable-unit-labels in faring-atoms.
For priceable-unit-label in priceable-unit-labels
For faring-atom-set in priceable-unit-label.faring-atom-sets
For faring-atom in faring-atom-set
faring-atom.priceable-unit-labels += priceable-unit-label
This pseudo-code iterates over faring-markets in different slices, and passes faring markets to one of several possible create-PUs-in-markets procedures. These procedures vary by size of priceable-unit produced. The code ensures that the faring-markets are in the correct format for the type of priceable-unit produced, and that the priceable units are all on the same airline. This last restriction is motivated by efficiency since rarely do carriers permit priceable-units with fares from more than one airline. Each call to create-PUs-in-markets returns an updated set of priceable-unit-labels. At the end of the procedure, these priceable-unit-labels are stored in their component faring-atoms. There are many other combinability restrictions that limit the manner in which fare components can be combined into priceable continuous units. Even when searching for fares for a small number of itineraries, there can be a very large number of possible pricing units because of the large number of possible fares that can exist. It is preferred to represent these priceable units in a compact manner so as to minimize the computation involved in their construction. The faring algorithm does not actually construct a data-structure for every priceable-unit. Instead, priceable-units are represented by a combination of two data structures: priceable-unit-cores (PU-cores) and priceable-unit-labels (PU-labels). PU-core data structures contain all the information associated with an individual priceable-unit except its faring-atoms. Thus, each PU-core contains a set of fares (one fare per fare-component in the priceable-unit) and any other information associated with those fares, such as discounts, surcharges and penalties. PU-label data structures compactly represent connections between faring-atoms and PU-cores. At this stage of processing, a collection of fares has been fixed on, and for each fare there is a set of fare-components. Priceable-units are constructed by selecting one fare-component from each set and evaluating any deferred rules. The simplest manner that this could be accomplished would be to enumerate complete collections of fare-components and to apply the deferred record-2s from within these fare-components. Often, this method can be made more efficient in some cases by use of the function get-OR-AND-OR-form as will be described. That function takes a collection of sets of fare-components, evaluates any deferred rule-conditions, and returns a representation of the set of valid priceable-units. This representation is in OR-AND-OR form. In other words, it takes the form of a set of collections of sets of fare-components. This is very close to a set of priceable-unit-labels except that since the sets are of fare-components rather than faring-atoms, there are no PU-cores. The inner sets of fare-components returned by get-OR-AND-OR-form are guaranteed to have the same fares, surcharges, discounts, penalties and so on. PU-cores and PU-labels are constructed from the output of get-OR-AND-OR. The pseudo-code below summarizes this procedure. It iterates over the inner AND-OR form, constructing PU-cores (if no identical PU-core already exists) and PU-labels (if no identical PU-label already exists). PU-labels are constructed by mapping from fare-components to faring-atoms. PU-cores are stored on PU-labels.
TABLE 18
create-PUS-from-fare-components(faring-markets, fares, fare-component-sets,
existing-PU-labels,
environmental-information)
Let slice-numbers = {}
Let PU-labels = existing-PU-labels
Let PU-cores = {}
For faring-market in faring-markets
slice-numbers += faring-market.slice-number
For AND-OR in get-OR-AND-OR(faring-markets, fare-component-sets,
environmental-information)
//
// AND-OR is a collection of sets of fare-components, representing
all the priceable-units
// that can be constructed by choosing one fare-component from each
set.
//
Let PU-core = nil
Let surcharges = {}
Let faring-atom-sets = {}
For fare-component-set in AND-OR
surcharges += first(fare-component-set).surcharges
Let faring-atom-set = {}
For fare-component in fare-component-set
faring-atom-set += fare-component.faring-atom
faring-atom-sets += faring-atom-set
// Find an existing PU-core with these fares and surcharges, or
construct a new one.
For test-PU-core in PU-cores
If (test-PU-core.surcharges = surcharges)
PU-core = test-PU-core
If (PU-core = nil)
PU-core = new-PU-core()
PU-core.fares = fares
PU-core.surcharges = surcharges
PU-core.slice-numbers = slice-numbers
// Find an existing PU-label with these faring-atoms, or construct a
new one.
Let PU-label = nil
For test-PU-label in PU-labels
If (test-PU-label.faring-atom-sets = faring-atom-sets)
PU-label = test-PU-label
If (PU-label = nil)
PU-label = new-PU-label()
PU-label.faring-atom-sets = faring-atom-sets
PU-label.slice-numbers = slice-numbers
PU-label.priceable-unit-cores = {}
PU-labels += PU-label
PU-label.priceable-unit-cores += PU-core
return(PU-labels)
To understand the role PU-cores and PU-labels play in the faring algorithm, it may be helpful to look at an example, involving a round-trip journey between BOS and MSP. In this example, there are four outbound itineraries and four return itineraries, each of which is spanned by a single faring-market. For both the outbound and return itineraries, there is a choice between two airlines, UA and NW. Both of these airlines offer two round-trip fares and one one-way fare. This situation is summarized in TABLE 19 below.
TABLE 19
Faring-market Faring-Atoms Fares
Slice 1: UA BOS.fwdarw.MSP UA100 UA BOS-MSP RT "Q"
BOS.fwdarw.MSP BOS.fwdarw.MSP UA200 UA BOS-MSP
RT "M14"
UA BOS-MSP OW "Y"
Slice 1: NW BOS.fwdarw.MSP NW300 NW BOS-MSP
RT "HE7"
BOS.fwdarw.MSP BOS.fwdarw.MSP NW400 NW BOS-MSP
RT "Q7NR"
NW BOS-MSP OW "F"
Slice 2: UA MSP.fwdarw.BOS MSP.fwdarw.BOS UA111 same as for the outbound
MSP.fwdarw.BOS UA222 UA faring-market
Slice 2: NW MSP.fwdarw.BOS MSP.fwdarw.BOS NW333 same as for the outbound
MSP.fwdarw.BOS NW444 NW faring-market
Assume that in each of the four faring-markets (i.e., BOS-MSP UA, BOS-MSP NW, MSP-BOS UA and MSP-BOS NW), fare-components have been constructed for every combination of faring-atom and fare. The fare-components built from the fare "NW BOS-MSP RT HE7" contain a deferred record-2 that is checked during priceable-unit construction. This record-2 does not permit outbound travel on flight "NW300" combined with return travel on flight "NW444." When constructing round-trip priceable-units, round-trip fares are combined with like round-trip fares. This situation permits the construction of a total of 23 priceable-units, as shown in TABLE 20.
TABLE 20
Priceable-Unit Slice-1 Slice-2
Number and Type Faring-Atom Slice-1 Fare Faring-Atom Slice-2
Fare
1 Round-trip BOS .fwdarw. MSP UA100 RT "Q" MSP .fwdarw. BOS UA111
RT "Q"
2 Round-trip BOS .fwdarw. MSP UA100 RT "M14" MSP .fwdarw. BOS UA111
RT "M14"
3 Round-trip BOS .fwdarw. MSP UA100 RT "Q" MSP .fwdarw. BOS UA222
RT "Q"
4 Round-trip BOS .fwdarw. MSP UA100 RT "M14" MSP .fwdarw. BOS UA222
RT "M14"
5 Round-trip BOS .fwdarw. MSP UA200 RT "Q" MSP .fwdarw. BOS UA111
RT "Q"
6 Round-trip BOS .fwdarw. MSP UA200 RT "M14" MSP .fwdarw. BOS UA111
RT "M14"
7 Round-trip BOS .fwdarw. MSP UA200 RT "Q" MSP .fwdarw. BOS UA222
RT "Q"
8 Round-trip BOS .fwdarw. MSP UA200 RT "M14" MSP .fwdarw. BOS UA222
RT "M14"
9 Round-trip BOS .fwdarw. MSP NW300 RT "HE7NR" MSP .fwdarw. BOS NW333
RT "HE7"
10 Round-trip BOS .fwdarw. MSP NW300 RT "Q7NR" MSP .fwdarw. BOS NW333
RT "Q7NR"
11 Round-trip BOS .fwdarw. MSP NW300 RT "Q7NR" MSP .fwdarw. BOS NW444
RT "Q7NR"
12 Round-trip BOS .fwdarw. MSP NW400 RT "HE7NR" MSP .fwdarw. BOS NW333
RT "HE7"
13 Round-trip BOS .fwdarw. MSP NW400 RT "Q7NR" MSP .fwdarw. BOS NW333
RT "Q7NR"
14 Round-trip BOS .fwdarw. MSP NW400 RT "HE7NR" MSP .fwdarw. BOS NW444
RT "HE7"
15 One-way BOS .fwdarw. MSP NW400 RT "Q7NR" MSP .fwdarw. BOS NW444
RT "Q7NR"
16 One-way BOS .fwdarw. MSP UA100 OW "Y"
17 One-way BOS .fwdarw. MSP UA200 OW "Y"
18 One-way BOS .fwdarw. MSP NW300 OW "F"
19 One-way BOS .fwdarw. MSP NW400 OW "F"
20 One-way MSP .fwdarw. BOS UA111 OW
"Y"
21 One-way MSP .fwdarw. BOS UA222 OW
"Y"
22 One-way MSP .fwdarw. BOS NW333 OW
"F"
23 One-way MSP .fwdarw. BOS NW444 OW
"F"
Even in this example, the list of possible priceable-units is long (23 units). The reason that there are so many priceable-units is because production of priceable-units involves several choices (of fares and faring-atoms). In TABLE 21 below, each entry represents a choice (an OR) of either faring-atoms or PU-cores. Each row represents a collection (an AND) of these choices. And finally, the entire table represents a choice (an OR) over these collections. Collectively, this OR-AND-OR table provides a compact representation of the 23 priceable-units.
TABLE 21
Label Slice-1 Slice-2 Priceable-
Number Faring-Atom Options Faring-Atom Options Unit-Core Options
1 BOS .fwdarw. MSP UA100 MSP .fwdarw. BOS UA111 1: RT "Q", 2: RT
"Q"
BOS .fwdarw. MSP UA200 MSP .fwdarw. BOS UA222 1: RT "M14", 2: RT
"M14"
2 BOS .fwdarw. MSP NW300 MSP .fwdarw. BOS NW333 1: RT "Q7NR", 2: RT
"Q7NR"
BOS .fwdarw. MSP NW400 MSP .fwdarw. BOS NW444
3 BOS .fwdarw. MSP NW300 MSP .fwdarw. BOS NW333 1: RT "HE7", 2: RT
"HE7"
4 BOS .fwdarw. MSP NW400 MSP .fwdarw. BOS NW333 1: RT "HE7", 2: RT
"HE7"
MSP .fwdarw. BOS NW444
5 BOS .fwdarw. MSP UA100 1: OW "Y"
BOS .fwdarw. MSP UA200
6 BOS .fwdarw. MSP NW300 1: OW "F"
BOS .fwdarw. MSP NW400
7 MSP .fwdarw. BOS UA111 2: OW "Y"
MSP .fwdarw. BOS UA222
8 MSP .fwdarw. BOS NW333 2: OW "F"
MSP .fwdarw. BOS NW444
Each row of TABLE 21 is a priceable-unit-label (PU-label), an object that factors a set of priceable-units into a collection of choices that have no further dependencies. There is a choice for every faring-atom involved in the priceable-unit, and a choice of a priceable-unit-core (PU-core). Each PU-core contains the same number of fares as there are faring-atom choices. In the case where there are no constraints between faring-atoms in different slices, PU-labels are a very compact representation of priceable-units. PU-label #1, for example, represents a total of eight different priceable-units. In cases where there are interactions between the faring-atoms in different slices, several PU-labels can be produced for a single PU-core. An example of several PU-labels is shown for the NW RT "HE7" fare represented by PU-labels numbers 3 and 4. These priceable-unit-labels and priceable-unit-cores are used by the linking procedure 94 (FIG. 4B) to associate itineraries from more than one slice to fares. ENUMERATING COLLECTIONS OF SETS OF FARE-COMPONENTS Each of the faring-markets that is passed to create-PUs-in-markets has a set of fare-components produced by applying fare rules procedure 88. Referring now to FIG. 10A, enumerating collections of sets of fare-components 202 (described by pseudo-code below) partitions the fare-components in each faring-market into sets such that every fare-component in a set has the same fare and the same combinability record-2s. Fare combinability restrictions are specified in record-2s rule category 10. Any category-10 record-2s in a fare's rules is stored in the combinability-record-2 field in the fare-components. Once fare-components are partitioned 202a into sets, collections of these sets are enumerated 202b, by selecting one set from each faring-market. For each fare there is a choice of fare-components. At this point, when the fares within a priceable-unit have been fixed, any category-10 record-2s that was deferred is applied 202c to determine whether the fares may be used together in a priceable-unit. This is accomplished by applying 202c each fare's combinability record-2 (if it has one) to every other fare within the priceable-unit. The code below (TABLE 22) is written for two faring-markets within a priceable-unit, as would be the case for round-trips, open jaws and circle-trips of size two. Similar code would be used for priceable-units of other sizes.
TABLE 22
partition-fare-components-into-sets(faring-market)
//
// Partition fare-components into sets based on fare and combinability
record-2.
//
Let fare-component-sets = {}
For fare-component in faring-market.fare-components
Let fare = fare-component.fare
Let combinability-record-2 = fare-component.combinability-record-2
Let previous-set = nil
For test-set in fare-component-sets
Let test-fare-component = first(test-set)
If ((fare = test-fare-component.fare) and
(combinability-record-2 =
test-fare-component.combinability-record-2))
previous-set = test-set
If (previous-set = nil)
fare-component-sets += list(fare-component)
Else
previous-set += fare-component
return(fare-component-sets)
create-PUs-in-markets2(faring-market1, faring-market2, existing-PU-labels,
PU-type, environmental-information)
Let fare-component-sets1 =
partition-fare-components-into-sets(faring-market1)
Let fare-component-sets2 =
partition-fare-components-into-sets(faring-market2.)
Let PU-labels = existing-PU-labels
For fare-components1 in fare-component-sets1
For fare-components2 in fare-component-sets2
Let fare1 = first(fare-components1).fare
Let fare2 = first(fare-components2).fare
Let combinability-record-2-1 =
first(fare-components1).combinability-record-2
Let combinability-record-2-2 =
first(fare-components2).combinability-record-2
// Check fare combinability requirements, by applying each fares's
combinabilty
// record-2 to all the other fares within the priceable-unit.
If ((combinability-record-2-1 = nil or
apply-combinability-record-2(combinability-record-2-1, fare2,
PU-type) = pass) and
(combinability-record-2-2 = nil or
apply-combinability-record-2(combinability-record-2-2, fare1,
PU-type) = pass))
PU-labels = create-PUs-from-fare-components(list(faring-market1,
faring-market2),
list(fare1, fare2),
list(fare-components1, fare-components2),
PU-labels, environmental-information)
return(PU-labels)
The procedure create-PUs-in-markets2, after it has selected two fares and two sets of fare-components and verified fare combinability restrictions, calls the procedure 202d create-PUs-from-fare-components to evaluate deferred rules and construct priceable-unit-labels and priceable-unit-cores. CONSTRUCTING PRICEABLE-UNITS At this stage of processing, a collection of fares is determined, and for each fare there is a set of fare-components. Priceable-units are constructed by selecting one fare-component from each set and evaluating any deferred rules. Referring now to FIG. 11, a process 204 to enumerate collection of fare components is shown. The process 204 can enumerate 212 a collection of sets of fare-components, enumerate 214 fare components by selecting one component from each set, apply or evaluate 216 any deferred rule-conditions, and return a compact representation 218 of the set of valid priceable-units. A preferred technique to accomplish this uses a "GET_OR_AND_OR" operation described below TABLES 24, 26 and 27. The representation process 218 produces an OR-AND-OR representation of the priceable units. The process 218 produces a set of collections of sets of fare-components similar to that in FIG. 20, that will later be transformed into priceable-unit-labels and priceable-unit-cores by processes 206 and 208 described further in TABLE 22. The inner sets of fare-components returned by get-OR-AND-OR-form have the same fares, surcharges, discounts, penalties and so on. The procedure 218 get-OR-AND-OR, takes a collection of fare-component sets and enumerate collections of fare-components by selecting one from each set. It evaluates any deferred record-2s, and constructs a set of valid priceable-units. This set is transformed into a factored OR-AND-OR form, and returned. Referring back to FIG. 10, PU-cores and PU-labels are constructed 210 at process 206 and 208 from the output of get-OR-AND-OR process 204. The pseudo-code below and FIGS. 12-13 summarizes this procedure. Construction 210 iterates over the inner AND-OR form, producing PU-cores 206 (if no identical PU-core already exists) and PU-labels 208 (if no identical PU-label already exists). PU-labels are produced by mapping fare-components to faring-atoms and PU-cores are stored on PU-labels. FACTORING PRICEABLE-UNITS Referring now to FIGS. 12-15, the get-OR-AND-OR process 218 to construct the priceable unit representation is shown and is also described in detail below through pseudo-code. As shown in FIG. 12 and in pseudo-code in TABLE 23 below, three different high-level procedures are used, depending on whether priceable-units are one 220, two 222, or three or more 224 fare-components.
TABLE 23
get-OR-AND-OR(faring-markets, fare-component-sets,
environmental-information)
Let size = length(faring-markets)
If(size = 1)
return(get-OR-AND-OR-1(faring-markets, fare-component-sets,
environmental-information)
Else If (size = 2)
return(get-OR-AND-OR-2(faring-markets, fare-component-sets,
environmental-information)
Else
return(get-OR-AND-OR-3+(faring-markets, fare-component-sets,
environmental-information)
Two auxiliary functions are used in the get-OR-AND-OR procedures. The first, apply-deferred-record-2s 218a, takes a collection of fare-components (a potential priceable-unit) and evaluates any deferred record-2s they might have. In contrast to the initial stage of rule application, here all the fares and faring-atoms within the priceable-unit are known. It returns either PASS, FAIL or DEFER (in this case, DEFER means that the record-2s cannot be evaluated even at the priceable-unit level: they involve journey-level constraints). In such a case the priceable-unit is not produced (TABLE 24.)
TABLE 24
apply-deferred-record-2s(fare-components, environmental-information)
Let faring-atoms = {}
Let fares = {}
For fare-component in fare-components
fares += fare-component.fare
faring-atoms += fare-component.faring-atom
For fare-component in fare-components
For record-2 in fare-component.deferred-record-2s
If (apply-record-2-PU(record-2, fares, faring-atoms,
fare-component.faring-atom,
environmental-information)
<> pass
return(fail)
return(pass)
The second auxiliary function, partition-fare-components-by-surcharges 218b, (TABLE 25) takes a set of fare-components and partitions it into subsets that have the same secondary characteristics: the same surcharges, discounts, penalties, etc.
TABLE 25
partition-fare-components-by-surcharges(fare-components)
Let partitions = {}
For fare-component in fare-components
Let found-partition = false
Let surcharges = fare-component.surcharges
For partition in partitions
If (first(partition).surcharges surcharges)
found-partition = true
partition += fare-component
If (found-partition = false)
partitions += list(fare-component)
return(partitions)
FACTORING PRICEABLE-UNITS OF SIZE ONE Referring now to FIG. 13, the get-OR-AND-OR function 230 for priceable-units of one fare-component (one-way priceable-units) is shown. It is passed only a single fare-component set 232, and applies 216 deferred record-2s. The final set of valid fare-components is partitioned 234 into sets with the same surcharges, penalties, and discounts. The partitioned sets 236 are placed into the proper OR-AND-OR representation 238 to represent them in a compact form.
TABLE 26
get-OR-AND-OR-1(faring-markets, fare-component-sets,
environmental-information)
Let valid-fare-components = {}
For fare-component in first(fare-component-sets)
If (apply-deferred-record-2s(list(fare-component),
environmental-information)
valid-fare-components += fare-component
Let OR-AND-OR = {}
For OR in
partition-fare-components-by-surcharges(valid-fare-components)
Let AND-OR = list(OR)
OR-AND-OR += AND-OR
return(OR-AND-OR)
FACTORING PRICEABLE-UNITS OF SIZE TWO Referring to FIG. 14, two-component priceable-units include round-trips and two-component open-jaws and circle-trips. They are common and should be computed efficiently and represented compactly. The function get-OR-AND-OR-2240 efficiently computes and represents two component priceable units (242-246). Combinations of fare-components are not enumerated unless it is necessary for evaluation of deferred record-2s. The resulting set of priceable-units is also represented in a compact OR-AND-OR form. Pseudo code for the get-OR-AND-OR-2 procedure is set forth below (TABLE 27). The process 240 enumerates priceable units 248 by selecting one fare component from each set. The get-OR-AND-OR-2 process 240 tests deferred record-2s and, if the test is passed, adds the resulting valid priceable unit to the OR-AND-OR representation.
TABLE 27
get-OR-AND-OR-2(faring-markets, fare-component-sets,
environmental-information)
Let OR-AND-OR {}
Subroutine find-AND-OR(surcharges1, fare-component-set2)
//
// Return any AND-OR from OR-AND-OR that has fare-components
with surcharges surcharges1 in its
// first set of fare-components, and has fare-component-set as
its second set of fare-components.
//
For AND-OR in OR-AND-OR
If (first(first(AND-OR)).surcharges = surcharges1 and
second(AND-OR) = fare-component-set2)
return(AND-OR)
return(nil)
Subroutine add-uniform-cross-product(fare-component-set1,
fare-component-set2)
//
// Add the priceable-units that can be had by selecting one
element from fare-component-set1 and
// one element from fare-component-set2. Both sets are uniform
with respect to surcharges.
//
Let AND-OR = find-AND-OR(first(fare-component-set1).surcharges,
fare-component-set2)
If (AND-OR = nil)
OR-AND-OR += list(fare-component-set1, fare-component-set2)
Else
first(AND-OR) = append(first(AND-OR), fare-component-set1)
Subroutine add-cross-product(fare-component-set1.
fare-component-set2)
//
// Add the priceable-units that can be had by selecting one
element from fare-component-set1 and
// one element from fare-component-set2.
//
Let uniform-fare-component-sets1 =
partition-fare-components-by-surcharges(fare-component-set1)
Let uniform-fare-component-sets2 =
partition-fare-components-by-surcharges(fare-component-set2)
For uniform-fare-component-set1 in uniform-fare-component-sets1
For uniform-fare-component-set2 in
uniform-fare-component-sets2
add-uniform-cross-product(uniform-fare-component-set1,
uniform-fare-component-set2)
Subroutine enumerate-priceable-units(fare-component-set1,
fare-component-set2)
//
// Enumerate priceable-units by selecting one fare-component
from each set. Test deferred record-2s,
// and if they pass, add the resulting priceable-unit to the
OR-AND-OR representation.
//
For fare-component1 in fare-component-set1
Let valid-fare-components2 = {}
For fare-component in fare-component-set2
If (apply-deferred-record-2s(list(fare-component1,
fare-component2), environmental-information))
valid-fare-components2 += fare-component2
If (valid-fare-components2 <>({})
add-cross-product(list(fare-component1),
valid-fare-components2)
Let fare-component-set1-with-rules = {}
Let fare-component-set1-without-rules = {}
Let fare-component-set2-with-rules = {}
Let fare-component-set2-without-rules = {}
For fare-component1 in first (fare-component-sets)
If (fare-oomponent1.deferred-record-2s = nil)
fare-component-set1-without-rules +=
fare-component1
Else
fare-component-set1-with-rules +=
fare-component1
For fare-component in second(fare-component-sets)
If (fare-component.deferred-record-2s = nil)
fare-component-set2-without-rules +=
fare-component2
Else
fare-component-set2-with-rules +=
fare-component2
// There is no need to enumerate combinations of
fare-components that have no deferred rules.
add-cross-product(fare-component-set1-without-rules,
fare-component-set2-without-rules)
// For the remainder of fare-components, though, explicit
enumeration is necessary.
enumerate-priceable-units(fare-component-set1-with-rules,
fare-component-set2-without-rules)
enumerate-priceable-units(fare-component-set1,
fare-component-set2-with-rules)
return(OR-AND-OR)
FACTORING PRICEABLE-UNITS OF SIZE THREE OR GREATER Properly enumerating all possible combinations of fare-components for priceable-units of size three or greater is computationally burdensome, though possible. Referring now to FIG. 15, a preferred procedure 260 finds a subset of possible priceable-units. In particular, it extracts 262 those fare-components that have no deferred record-2s, and build priceable-units from them. Since there are no deferred record-2s, there are no intra-priceable-unit constraints and it is possible to construct a factored representation. Priceable-units of size three or greater tend to have more deferred record-2s. This may somewhat reduce the effectiveness of the extracting procedure 262. The prevalence of deferred record-2s rules occurs because in complicated journeys, time-bounds used in an initial rule application tend to be broadly specified. At this stage of processing time bound ranges can be tightened, because the faring-markets that comprise the priceable-unit are known. Therefore, deferred record-2s can be reapplied 264 to faring-atoms in the same manner that they are applied in the initial rule application. If all deferred record-2s pass, then the faring-atom is retained 266. If a record-2 fails or is deferred, the faring-atom is discarded. The function reevaluate-deferred-record-2s (TABLE 28) performs this filtering. It takes a set of faring-markets and a fare-component set, and sets time-bounds based on the faring-markets. It reevaluates deferred record-2s for each fare-component in the set, and returns the set of fare-components that have all their record-2s pass.
TABLE 28
reevaluate-deferred-record-2s(faring-markets, fare-component-set,
environmental-information)
set-time-bounds(faring-markets)
Let fare-components = {}
For fare-component in fare-component-set
Let result = pass
Let deferred-record-2s = {}
For record-2 in fare-component.deferred-record-2s
Let record-2-result, record-2-surcharges =
apply-record-2-FC(record-2, fare-component.faring-atom,
environmental-information)
If (record-2-result = pass)
fare-component.surcharges += record-2-surcharges
Else If (record-2-result = defer)
deferred-record-2s += record-2
Else
result = fail
If (result = pass)
fare-component.deferred-record-2s = deferred-record-2s
fare-components += fare-component
return(fare-components)
The procedure 268 that factors priceable-units of size three or greater, get-OR-AND-OR-3+, (TABLE 29) applies reevaluate-deferred-record-2s to each set of fare-components, to filter them. It then partitions the resulting sets based on surcharges, and takes the cross-product of these sets to construct the proper OR-AND-OR representation. The procedure for the last case does not return all possible valid priceable-units.
TABLE 29
get-OR-AND-OR-3+(faring-markets, fare-component-sets,
environmental-information)
Let OR-AND-OR = { {} }
For fare-component-set in fare-component-sets
Let valid-fare-components =
reevaluate-deferred-record-2s(faring-markets, fare-component-set,
environmental-information)
Let new-OR-AND-OR = {}
For OR in
partition-fare-components-by-surcharges(valid-fare-components)
For previous-AND-OR in OR-AND-OR
new-OR-AND-OR += postpend(previous-AND-OR, OR)
OR-AND-OR = new-OR-AND-OR
return(OR-AND-OR)
LINKING ITINERARIES Priceable-units-labels associate faring-atoms from one or more slices with fares. In the pricing-graph representation 38' set of pricing solutions, sets of priceable-unit-labels are used to link itineraries from different slices. The pricing graph representation 38' of pricing-solutions 38 is constructed by selecting a set of priceable-unit-labels. Each of these PU-labels may or may not project onto a given slice of a journey. For example, in a round-trip journey a round-trip priceable-unit-label will project onto both slices, while a one-way priceable-unit-label will project onto only one slice of the journey. Once a set of PU-labels has been chosen, in any slice any itinerary may be chosen so long as it has some division that has faring-atoms containing exactly the PU-labels that project onto that slice. The choice of itinerary is otherwise independent of choices made in other slices. A set of PU-labels encodes all constraints that exist between itineraries in different slices. This leads to a relatively simple procedure for constructing the pricing-graph. Itineraries within each slice are indexed by the sets of multi-slice PU-labels they can be associated with. These indices are called slice-label-sets, and act as a logical OR over itineraries. The slice-label-sets from different slices are linked by matching PU-labels. Single-slice (one-way) priceable-unit-labels are treated somewhat differently than multi-slice priceable-unit-labels to enhance efficiency. In particular, there is no need to include single-slice PU-labels in slice-label-sets, because they do not need to be matched across slices. Rather, single-slice PU-labels are attached closely to itineraries in the pricing-graph. That is, within a slice-label-set, each itinerary is associated with a compact representation of the set of single-slice PU-labels that can be used with the itinerary, given that the multi-slice PU-labels found within the slice-label-set are also used. The linking process constructs slice-label-sets with each slice-label-set being a set of multi-slice PU-labels and associated itinerary divisions. Slice-label-sets group itineraries by multi-slice PU-labels. Each division has associated with it a set of single-slice PU-labels. In the pricing-graph, slice-label-sets act as ORs over itineraries. Multi-slice PU-labels encapsulate information concerning the itinerary to permit the linking process to operate over slice-label-sets rather than individual itineraries. This approval is computationally efficient and results in small pricing-graphs. In each slice-label-set, each itinerary (division) is paired with a set of single-slice PU-labels. During construction of the pricing graph, each slice-label-set is transformed into an OR over ANDs of itineraries and sets of PU-labels. The linking process 282 also connects or links slice-label-sets from different slices, as shown in FIG. 16. Connecting is accomplished by starting from the first slice and working forward to the last slice. Intermediate results are summarized in open-label-sets. Each open-label-set is a set of (multi-slice) PU-labels that project onto slices that have not been processed, along with a set of backward-links that are each a pair of a slice-label-set and an open-label-set from the previous slice. Processing starts retrieving slice 1 and matching with a single, empty slice-0 open-label-set 288. Slice-label-sets from slice 1 are "added" 290 to this open-label-set, resulting in new slice-1 open-label-sets. Then slice-label-sets from slice-2 are added to these, resulting in slice-2 open-label-sets, and so on. As this process continues, PU-labels that are complete 292 (i.e., that do not project to subsequent slices) are removed 293 from open-label-sets. The next slice is retrieved by incrementing 294. If any pricing-solutions exist, the process will terminate 297 in a single, empty, last-slice open-label-set. At that point, the backward-links serve as the top-level representation of the pricing-graph. Set forth below is an example of the linking process. This example assumes a three-slice circle-trip journey, from BOS to MSP to MIA. In the following discussion, PU-labels are identified by a unique letter followed by a sequence of digits that indicate which slices the PU-label projects onto. For example, A-23 is a two-component PU-label that projects onto the second and third slices. Each itinerary may have several divisions, and each division may have many possible collections of PU-labels (with each collection built by selecting one PU-label per faring-atom in the division). At this stage of processing in the faring process 18 divisions have been produced for each itinerary, each division comprising a set of faring-atoms. PU-labels have been constructed, and stored in each faring-atom. From this information it is possible to enumerate for every division, possible collections of PU-labels, by selecting one for each faring-atom. TABLE 30 below summarizes the result of this procedure, for the example journey. Each possible collection of PU-labels is partitioned into those that project onto only one slice (one-way priceable-units) and those that project onto more than one-slice. In this table, divisions are encoded using the endpoints of faring-atoms, to save space, and each itinerary and division are given numeric labels so that they can be referenced in the rest of the discussion.
TABLE 30
Multi-Slice Single-Slice
Slice Itinerary Division
PU-Labels PU-Labels
1 1.1 BOS.fwdarw.MSP UA123 1.1.1 BOS.fwdarw.MSP
{A-123} {}
{F-13}
{}
{}
{I-1}
1 1.2 BOS.fwdarw.CHI NW315 CHI_MSP UA739 1.2.1 BOS.fwdarw.MSP;
CHI.fwdarw.MSP {B-13 C-12} {}
{B-13}
{H-1}
{C-12}
{G-1}
{}
{G-1 H-1}
1 1.3 BOS.fwdarw.MSP CO450 1.3.1 BOS.fwdarw.MSP {}
{J-1}
2 2.1 MSP.fwdarw.MIA UA901 2.1.1 MSP.fwdarw.MIA
{A-123} {}
{}
{K-2}
2 2.2 MSP.fwdarw.CHI UA623 CHI_MIA UA841 2.2.1 MSP.fwdarw.MIA
{A-123} {}
{}
{K-2}
2.2.2 MSP.fwdarw.CHI;
CHI.fwdarw.MIA {C-12 D-23} {}
{C-12}
{M-2}
{D-23}
{L-2}
{}
{L-2 M-2}
2 2.3 MSP.fwdarw.MIA FL207 2.3.1 MSP.fwdarw.MIA {E-23}
{}
3 3.1 MIA.fwdarw.BOS UA112 3.1.1 MIA.fwdarw.BOS
{A-123} {}
3 3.2 MIA.fwdarw.CHI UA487 CHI.fwdarw.BOS NW316 3.2.1 MIA.fwdarw.CHI;
CHI.fwdarw.BOS {D-23 B-13} {}
{D-23}
{O-3}
{B-13}
{N-3}
{}
{N-3 O-3}
3 3.3 MIA.fwdarw.MSP FL208 MSP.fwdarw.BOS UA558 3.3.1 MIA.fwdarw.MSP;
MSP.fwdarw.BOS {E23 F13} {}
{E23}
{P-3}
As TABLE 30 above shows, there are three different itineraries for each slice. Each itinerary is split into one or two divisions of faring-atoms. Each division has one or several possible PU-label combinations. For example, for the second division of the second slice-2 itinerary (2.2.2) there are four different PU-label sets. This is because the division has two faring-atoms, and each faring-atom has two possible PU-labels. For reference, the table below lists each hypothetical PU-label along with its faring-markets.
TABLE 31
Name Faring-Markets Comment
A-123 1: UA BOS.fwdarw.MSP 2: UA MSP.fwdarw.MIA 3: UA MIA.fwdarw.BOS
3-Component Circle Trip
B-13 1: NW BOS.fwdarw.CHI 3: NW CHI.fwdarw.BOS Round
Trip
C-12 1: UA CHI.fwdarw.MSP 2: UA CHI.fwdarw.MSP Round
Trip
D-23 2: UA CHI.fwdarw.MIA 3: UA MIA.fwdarw.CHI Round
Trip
E-23 2: FL MSP.fwdarw.MIA 3: FL MIA.fwdarw.MSP Round
Trip
F-13 1: UA BOS.fwdarw.MSP 3: UA MSP.fwdarw.BOS Round
Trip
G-1 1: NW BOS_CHI One Way
H-1 1: UA CHI.fwdarw.MSP One Way
I-1 1: UA BOS.fwdarw.MSP One Way
J-1 1: CO BOS.fwdarw.MSP One Way
K-2 2: UA MSP.fwdarw.MIA One Way
L-2 2: UA MSP.fwdarw.CHI One Way
M-2 2: UA CHI.fwdarw.MIA One Way
N-3 3: UA MIA.fwdarw.CHI One Way
O-3 3: NW CHI.fwdarw.BOS One Way
P-3 3: UA MSP.fwdarw.BOS One Way
TABLE 32 below lists slice-label-sets that are produced in this example, and as with itineraries and itinerary divisions, the faring process assigns each a numerical label. Many itineraries may be grouped into the same slice-label-set. For example, there are three different itinerary divisions that are grouped into slice-label-set 1.3. TABLE 30 lists, for each slice-label-set, its backward-projection. This is the set of multi-slice PU-labels that project onto previous slices.
TABLE 32
Single-
Multi-Slice Itin- Divi- Slice Backward
Slice PU-Labels erary sion PU-Labels Projection
1 1.1 {A-123} 1.1 1.1.1 {} {}
1 1.2 {F-13} 1.1 1.1.1 {} {}
1 1.3 {} 1.1 1.1.1 {I-1} {}
1.2 1.2.1 {G-1 H-1}
1.3 1.3.1 {J-1}
1 1.4 {B-13 C-12} 1.2 1.2.1 {} {}
1 1.5 {B-13} 1.2 1.2.1 {H-1} {}
1 1.6 {C-12} 1.2 1.2.1 {G-1} {}
2 2.1 {A-123} 2.1 2.1.1 {} {A-123}
2.2 2.2.1 {}
2 2.2 {} 2.1 2.1.1 {K-2} {}
2.2 2.2.2 {L-2
M-2}
2 2.3 {C-12 D-23} 2.2 2.2.2 {} {C-12}
2 2.4 {C-12} 2.2 2.2.2 {M-2} {C-12}
2 2.5 {D-23} 2.2 2.2.2 {L-2} {}
2 2.6 {E-23} 2.3 2.3.1 {} {}
3 3.1 {A-123} 3.1 3.1.1 {} {A-123}
3 3.2 {D-23 B-13} 3.2 3.2.1 {} {D-23 B-13}
3 3.3 {D-23} 3.2 3.2.1 {O-3} {D-23}
3 3.4 {B-13} 3.2 3.2.1 {N-3} {B-13}
3 3.5 {} 3.2 3.2.1 {N-3 O-3} {}
3 3.6 {E23 F13} 3.3 3.3.1 {} {E-23 F-13}
3 3.7 {E23} 3.3 3.3.1 {P-3} {E-23}
Shown in the TABLE 33 below are lists for each slice of the open-label-sets, as well as their backward-links and their next-slice-projection. This last field is the subset of open PU-labels that project onto the subsequent slice. It is equal to the backward-projection of any slice-label-set that is part of a backward-link to the open-label-set.
TABLE 33
Backward-
Next-Slice Backward-Link Link Open-
Slice Open-Label-Set Projection Slice-Label-Set Label-Set
0 0.1 {} {}
1 1.1 {A-123} {A-123} 1.1 {A-123} 0.1 {}
1 1.2 {F-13} {} 1.2 {F-13} 0.1 {}
1 1.3 {} {} 1.3 {} 0.1 {}
1 1.4 {B-13 C-12} {C-12} 1.4 {B-13 C-12} 0.1 {}
1 1.5 {B-13} {} 1.5 {B-13} 0.1 {}
1 1.6 {C-12} {C-12} 1.6 {C-12} 0.1 {}
2 2.1 {A-123} {A-123} 2.1 {A-123} 1.1 {A-123}
2 2.2 {} {} 2.2 {} 1.1 {}
2 2.3 {D-23} {D-23} 2.3 {C-12 D-23} 1.6 {C-12}
2.5 {D-23} 1.3 {}
2 2.4 {E-23} {E-23} 2.6 {E-23} 1.3 {}
2 2.5 {D-23 F-13} {D-23 F-13} 2.5 {D-23} 1.2 {F-13}
2 2.6 {E-23 F-13} {E-23 F-13} 2.6 {E-23} 1.2 {F-13}
2 2.7 {F-13} {F-13} 2.2 {} 1.2 {F-13}
2 2.8 {D-23 B-13} {D-23 B-13} 2.3 {C-12 D-23} 1.4 {B-13
C-12}
2.5 {D-23} 1.5 {B-13}
2 2.9 {E-23 B-13} {E-23 B-13} 2.6 {E-23} 1.5 {B-13}
2 2.10 {B-13} {B-13} 2.4 {C-12} 1.4 {B-13
C-12}
2.2 {} 1.5 {B-13}
3 3.1 {} {} 3.1 {A-123} 2.1 {A-123}
3.5 {} 2.2 {}
3.3 {D-23} 2.3 {D-23}
3.7 {E-23} 2.4 {E-23}
3.6 {E-23 F-13} 2.6 {E-23
F-13}
3.2 {D-23 B-13} 2.8 {D-23
B-13}
3.4 {B-13} 2.10 {B-13}
Each open-label-set contains a set of PU-labels that are still "open", i.e., project onto a subsequent slice. For the PU-label C-12 does not appear in open-label-sets from slice 2 or slice 3. In the pricing-graph, each open-label-set will be translated into an OR over the backward-links. The backward-links represent paths that lead to the open-label-set. Each is a pair (an AND) of a slice-label-set with an open-label-set from the previous slice. Because TABLE 33 is consistent, the backward-projection of any slice-label-set in a link is equal to the next-slice-projection of the open-label-set in the link. Furthermore, the PU-labels in each open-label-set can be constructed by selecting any backward-link, taking the union of the PU-labels in the link's open-label-set and slice-label-set, and removing any PU-labels that do not project forward. If there is an empty open-label-set for the last slice, then pricing-solutions exist. This open-label-set provides the "root" of the pricing-graph, a node that has a child for every link. Each of these links will become an AND of the slice-label-set and the previous open-label-set. In this way open-label-sets and slice-label-sets are used to produce the pricing-graph. FARE-COMBINABILITY RESTRICTIONS The linking procedure described above assumes that there are no restrictions on the mixing of priceable-unit-labels other than those imposed by itineraries. This is not always the case. For example, although the various create-PUs-in-markets procedures described above apply fare-combinability checks, those checks include only restrictions on the fares that may coexist within a priceable-unit. These checks include ATPCO categories 101, 102 and 103, but not category 104. The category-10 record-2s that are stored on fare-components may also include so called "end-on-end" fare-combinability restrictions. These restrictions constrain the fares within other priceable-units. One example of such an end-on-end fare-combinability constraint is that all fares within an entire journey must be published by the same airline as the fare with the constraint. Cross-priceable-unit constraints such as end-on-end fare-combinability restrictions complicate the process of finding valid fares for itineraries. In general cross-priceable unit constrains can be very expensive to evaluate. These constraints can often be efficiently evaluated during the process that links the set of valid fares to the sets of flights to form a pricing solution. Below, an efficient approach for evaluating many common end-on-end fare-combinability restrictions is described. First, priceable-unit-labels are construct | ||||||
