using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Runtime.Serialization;
using glue;
using glue.Extensions.String;
using glue.Extensions.String.Builder;
using glue.Debugging;
using glue.Extensions.Enumerable;
using glue.Collections.XSpinLock;
using glue.Collections.LockFreeDictionary;
#pragma warning disable 0649
namespace agree
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Trays are allocated globally, not per-grammar. The system supports a maximum of 64 trays. Each tray is a complete set
/// of ConstraintPools for some grammar. A grammar might use multiple trays in order to (a.) use a higher-performance
/// read-only tray for the invariant parts of the grammar (b.) for isolation or experimental purposes (c.) for parsing
/// or unification results, allowing the entire result to be instantly discarded and cleaned up.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static class TrayMgr
{
const int MaxTrays = 64;
static int next_tix = 0;
static public Tray[] all_trays = new Tray[MaxTrays];
static public Tray _most_recent_tray = null;
public static Tray Allocate<T>(TypeMgr tm, int next_mark, int next_id) where T : Tray
{
int tix = Interlocked.Increment(ref next_tix) - 1;
if (tix == MaxTrays)
throw new Exception(String.Format("The number of pool trays has exceeded the limit of {0}", MaxTrays));
Tray tr = null;
if (Nop.single_threaded)
{
tr = new SingleUserTray(tix, tm, next_mark, next_id);
}
else if (typeof(T) == typeof(ConcurrentTray))
{
tr = new ConcurrentTray(tix, tm, next_mark, next_id);
//tr = new SpinLockTray(tix, tm, next_mark, next_id);
//tr = new HybridSpinLockTray(tix, tm, next_mark, next_id);
//tr = new LockFreeTray(tix, tm, next_mark, next_id);
//tr = new HybridSpinLockRwTray(tix, tm, next_mark, next_id);
//tr = new HybridTray<ConcurrentDictionary<Int32, Edge>>(tix, tm, next_mark, next_id);
//tr = new HybridTray<SpinlockDictionary<Int32, Edge>>(tix, tm, next_mark, next_id);
//tr = new HybridTray<LockFreeDictionary<Int32, Edge>>(tix, tm, next_mark, next_id);
//tr = new HybridTray<ReaderWriterDictionary<Int32, Edge>>(tix, tm, next_mark, next_id);
//tr = new HybridTray<SpinlockRwDictionary<Int32, Edge>>(tix, tm, next_mark, next_id);
}
else
Debugger.Break();
if (Console.Out != null)
{
String s_tray_type = tr.GetType().Name;
if (tr.GetType().IsGenericType)
s_tray_type += "<" + tr.GetType().GetGenericArguments()[0].Name + ">";
Console.Out.WriteLine(s_tray_type);
}
all_trays[tix] = tr;
_most_recent_tray = tr;
return tr;
}
public static IEnumerable<Tray> GetTypeMgrTrays(TypeMgr tm)
{
foreach (Tray tr in all_trays)
if (tr != null && tr.tm == tm)
yield return tr;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// TRAY UTILITIES
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
abstract public partial class Tray
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CleanGarbage(HashSet<PoolMark> reachable)
{
HashSet<PoolMark> pool_pms = new HashSet<PoolMark>(Pools.SelectMany(cp => cp.Marks.Select(m => new PoolMark(cp, m))));
HashSet<PoolMark> garbage = new HashSet<PoolMark>(pool_pms.Except(reachable));
foreach (Edge gedge in TreeTops(garbage))
RudeTruncate(gedge);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public IEnumerable<Edge> TreeTops(IEnumerable<PoolMark> set)
{
HashSet<PoolMark> hs = new HashSet<PoolMark>(set);
foreach (PoolMark pm in set)
hs.ExceptWith(AllPoolMarks(pm.Constraint));
return hs._GroupBy(pm => pm.in_mark)
.Select(g =>
{
Type tx = tm.GetGlbOfMany(g.Select(pm => pm.Pool.IntroducedBy)) ?? tm.TopType;
return new Edge((Edge.Flag)tx.m_id, g.Key);
});
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool CanUnfill(ConstraintRef cr)
{
Edge e = cr.Constraint;
Type t0 = tm.GetEdgeType(e.FlagsId);
//if (t0.Name == "0-dlist" &&
// tm.GetEdgeType(Pools[tm.feat_map["list"].i_feat].GetEdge(e.Mark).FlagsId).Name == "0-1-list" &&
// tm.GetEdgeType(Pools[tm.feat_map["last"].i_feat].GetEdge(e.Mark).FlagsId).Name == "0-1-list")
// return true;
foreach (int fix in t0._deprec_feat_indexes)
{
ConstraintPool cp = Pools[fix];
Edge ne;
if (cp.TryGetEdge(e.Mark, out ne))
{
Edge ne2;
cp.TryGetEdge(t0.Expanded.Edge.Mark, out ne2);
Type t3 = tm.GetEdgeType(ne2.FlagsId);
if (ne.IsCoreferenced)
return false;
if (tm.GetEdgeType(ne.FlagsId) != t3)
return false;
if (ne.Mark != Edge.MarkBare && !CanUnfill(new ConstraintRef(e, cp)))
return false;
}
}
return true;
//!rgcr.Any(cr => cr.Constraint.IsConstrained) &&
//tr.tm.GetEdgeType(e.FlagsId).FeatureIndexes.SequenceEqual(rgcr.Select(cr => cr.FeatureIndex)))
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class MonospaceFormatter
{
Tray tr;
TypeMgr tm;
Dictionary<Edge, int> corefs = new Dictionary<Edge, int>();
bool f_uncons_top = true;
bool f_unfill = true;
int[] feature_order = null;
IDictionary<String, String> type_name_remapping = null;
public MonospaceFormatter(Tray tr)
{
this.tr = tr;
this.tm = tr.tm;
}
public int[] FeatureDisplayOrder
{
get { return feature_order; }
set { feature_order = value; }
}
public bool Unfill
{
get { return f_unfill; }
set { f_unfill = value; }
}
/// <summary>
/// Type names can be substituted to account for e.g. different glb number assignments in a comparison
/// system.
/// </summary>
public IDictionary<String, String> TypeNameRemapping
{
get { return type_name_remapping; }
set { type_name_remapping = value; }
}
/// <summary>
/// Note: Single-threaded (use of corefs)
/// </summary>
public String FormatEdge(Edge edge)
{
corefs.Clear();
String r = tm.GetEdgeType(edge.FlagsId).Name;
String s = _format_edge(0, edge);
if (s != String.Empty)
r += Environment.NewLine + s;
return r;
}
String _format_edge(int indent, Edge e)
{
var rgcr = (f_uncons_top ?
tr.AllConstraintRefs(e) :
tr.ConstrainedRefsOnly(e))
.ToArray();
if (rgcr.Length == 0)
return String.Empty;
if (feature_order != null)
rgcr = rgcr.OrderBy(cr => Array.IndexOf<int>(feature_order, cr.Pool.i_feat)).ToArray();
int feat_max = rgcr.Max(cr => cr.Pool.Feature.Length) + 1;
String s_indent = new String(' ', indent);
StringBuilder sb = new StringBuilder();
bool f_first = true;
foreach (ConstraintRef cr in rgcr)
{
Edge ne = cr.Constraint;
if (f_first)
{
sb.Append(s_indent + "[ ");
f_first = false;
}
else
sb.Append("," + Environment.NewLine + s_indent + " ");
sb.Append(cr.Pool.Feature.ToUpper().PadRight(feat_max));
bool f_old_coref = false;
String coref_text = String.Empty;
if (ne.IsCoreferenced)
{
int i_coref;
if (!corefs.TryGetValue(ne, out i_coref))
{
i_coref = corefs.Count + 1;
corefs.Add(ne, i_coref);
coref_text = String.Format("#{0}:", i_coref);
}
else
{
coref_text = "#" + i_coref.ToString();
f_old_coref = true;
}
sb.Append(coref_text);
}
if (!f_old_coref)
{
String s_type;
if (tm.IsStringValue(ne.FlagsId))
s_type = "\"" + tm.GetStringValue(ne.FlagsId) + "\"";
else
{
s_type = tm.GetEdgeType(ne.FlagsId).Name;
String s_tmp;
if (type_name_remapping != null && type_name_remapping.TryGetValue(s_type, out s_tmp))
s_type = s_tmp;
}
sb.Append(s_type);
if (!f_unfill || !tr.CanUnfill(cr))
{
String cons = _format_edge(indent + feat_max + 2 + coref_text.Length, ne);
if (cons.Length > 0)
sb.Append(Environment.NewLine + cons);
}
}
}
sb.Append(" ]");
return sb.ToString();
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class SubsumptionComparer : IComparer<Edge>, IEqualityComparer<Edge>
{
public SubsumptionComparer(Tray tr)
{
}
public int Compare(Edge x, Edge y)
{
throw new NotImplementedException();
}
public bool Equals(Edge x, Edge y)
{
return Compare(x, y) == 0;
}
public int GetHashCode(Edge obj)
{
throw new NotImplementedException();
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public IDictionary<Edge, CorefFinder.Entry> GetCoreferences(Edge e)
{
if ((e.FlagsId & Edge.Flag.EtmNonBareType) == 0)
return CorefFinder.NoCorefs;
return new CorefFinder(this, e).Result;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public sealed class CorefFinder
{
public readonly static IDictionary<Edge, Entry> NoCorefs = new Dictionary<Edge, Entry>();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class Entry : HashSet<ConstraintRef>
{
public Entry(ConstraintRef cref_first, int i_tag)
{
this.cref_display = cref_first;
this.i_tag = i_tag;
}
readonly public int i_tag;
public ConstraintRef cref_display;
public override String ToString() { return String.Format("#{0} in-edges: {1}", i_tag, this.Count); }
};
readonly Tray tr;
readonly TypeMgr tm;
readonly ConstraintPool[] Pools;
Dictionary<Edge, Entry> dict = null;
int coref_tag;
public CorefFinder(Tray tr, Edge e)
{
this.tr = tr;
this.tm = tr.tm;
this.Pools = tr.Pools;
this.coref_tag = 0;
_get_coreferences(e);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void _get_coreferences(Edge e)
{
/// this determines the order of coref tag numbering. it used to be specified here with
/// .OrderBy(cp => cp.IntroducedBy.m_level) but this is not needed so long as the feature index order
/// in the type is kept this way, as it is at this time.
foreach (int i_feat in tm.GetEdgeType(e.FlagsId)._deprec_feat_indexes)
{
ConstraintPool cp;
Edge next_edge;
bool f_descend = true;
if ((cp = Pools[i_feat]).TryGetEdge(e.Mark, out next_edge) && (next_edge.FlagsId & Edge.Flag.Coreference) > 0)
{
ConstraintRef cref = new ConstraintRef(e, cp);
Entry cre;
if (dict == null)
dict = new Dictionary<Edge, Entry> { { next_edge, cre = new Entry(cref, coref_tag++) } };
else if (!dict.TryGetValue(next_edge, out cre))
dict.Add(next_edge, cre = new Entry(cref, coref_tag++));
else
f_descend = false;
cre.Add(cref);
}
if (f_descend && (next_edge.FlagsId & Edge.Flag.EtmMask) == Edge.Flag.EtmNonBareType)
_get_coreferences(next_edge);
}
}
public IDictionary<Edge, Entry> Result { get { return dict ?? NoCorefs; } }
};
}