Automatic transformation of XML namespaces/Implementation/Precedences/Old answer

From testwiki
Revision as of 12:57, 5 May 2019 by imported>Alextejthompson (added Category:Automatic transformation of XML namespaces using HotCat)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

DAG is an abbreviation of directed acyclic graph.

Precedences system U is a set of precedences where a precedence is a nonempty set (of transformations). A precedence A is higher that another precedence B (denoted A>B) if every element of A is higher than every element of B.

I will call axiomatic precedences system a pair of nonstrict partial order (generated by a given DAG) and the strict partial order > and conforming to the formula:

A>BXU,YU:(XAYBX>Y).

Proposition Axiomatic precedence system can be instead characterized by the formula (). (FIXME: in this formula has two different meanings.)

Proof Equivalently transforming, the formula we get:

A>BXU,YU:(XAYBX>Y)

A>BXU,YU:(¬(XAYB)X>Y)

A>BXU,YU:¬((XAYB)XY)

A>B¬XU,YU:(XAYBXY)

A>B¬A()B

>¬()

()

Proposition Every axiomatic precedences system is isomorphic to a set-valued precedences system. (The reverse is obvious.)

Proof https://math.stackexchange.com/a/2600852/4876

Proposition If a pair of DAGs does not generate a system of precedences, then adding new edges to these DAGs cannot make it to generate a system of precedences.

Proof ??

We need to find the minimal order > which contains a given (by the DAG) order >0 and constitute a precedences system together with a given partial order . (FIXME: I (yet) cannot rule out that there may be multiple minimal orders!)

The algorithm

An (edited) copy of a deleted https://cs.stackexchange.com answer by the user D.W.:

Let me first suggest what data structure to use to store these partial orders. I suggest you represent each partial order as a dag (directed acyclic graph), via its " Hasse diagram. In other words, you build a dag to represent the relationships that are given: if you're given ab, you add an edge ab.

The partial order represented by a dag is the transitive closure of that dag. You never need to explicitly build the transitive closure. Rather, given c,d, to test whether cd, you do a reachability query: you check whether d is reachable from c in the graph (e.g., with DFS or BFS). If you're given a new relationship ab, you add the edge ab to the dag; also, you check whether ab (i.e., whether a is reachable from b), as if so, then this is no longer a partial order and there doesn't exist any partial order consistent with the relationships you've been given.

That covers how to store and manage these relationships.

Now let's consider how to handle the condition connecting these two partial orders. Let represent the "is subclass of" relation, and represent the "is higher than" relation. Then your condition is: if A1A and B1B and A>B then A1>B1.

You can maintain the partial orders to ensure that condition holds. We'll represent the > partial order with one dag; I'll write its edges using . We'll represent the partial order with a second dag; I'll write its edges using . Any time we an edge AB (in the dag for >), we'll update it to represent all the other relationships implied by your condition. Naively, we could do this by iterating over all possible values of A1,B1 and adding more edges to the dag for > as required by the condition. However, that would be a bit slow. I'll describe a more efficient way to achieve the same result.

Let's triple the number of nodes in the dag for >, i.e., triple the number of elements. For each element A, we'll create two more artificial elements A* and A*, with extra relationships according to the following rules: if A1A, then A1A* and A*A1; and if A>B, then A*>B*. These encode the condition you want to enforce, as if A1A and B1B, then we'll have A1A*>B*B1 and thus A1>B1 will be implied.

So instead of enforcing your condition, we'll enforce my replacement rule. In particular, we enforce my rule as follows:

  • Any time a vertex A is added, add also edge A*A*.
  • Any time a vertex A is added, add also edge AA.
  • Any time you add an edge AB, also add the edge A*B*.
  • Any time you add an edge A1A, also add the edge A*A1.

You now get two dags that interact: whenever you add an edge to the dag for , you have to add some edges to the other dag as well. (Fortunately, the changes don't cascade: the two rules above only apply to unstarred elements, so when you add the edge A1A*, it doesn't trigger adding any more edges.)

First, we will prove A>CA>C. Let for example AB and BC (or we can have any number of steps). Then we have AB and BC and consequently A>C.

Let now prove A1AA1A. Let for example A1C and CA (or we can have any number of steps). Then we have AA, thus A1A.

Now this gives a clean solution to your problem. Any time you learn about a new relationship, add it to the dag and make any additional changes required by the above rules. Any time you add an edge to the dag, immediately check to make sure the dag remains a partial order. If you want to know whether two elements are related, do a reachability query in the appropriate dag.

Since you never have to build the transitive closure explicitly, this should be pretty space-efficient. Adding edges to the dag can be done in O(1) time. Reachability queries might take linear time, but perhaps that is OK.

If you want to make the reachability queries faster, then there are algorithms and data structures for that as well. You want algorithms for incremental reachability in a dag (also called dynamic reachability for dags). This has been studied in the literature. It's possible that one of those algorithms might be more efficient, but I'm not sure, and it will probably also be more complex to implement. See, e.g., https://cstheory.stackexchange.com/q/18787/5038, https://cstheory.stackexchange.com/q/25298/5038, Efficiently determine relative ordering between two elements in a PO-set, How to evaluate relations in a DAG?, https://cstheory.stackexchange.com/q/29/5038.