Exemple #1
0
        protected override bool IsFeatureMatch(Segment seg, VariableValues instantiatedVars, ModeType mode)
        {
            if (!base.IsFeatureMatch(seg, instantiatedVars, mode))
            {
                return(false);
            }

            if (m_alphaVars != null)
            {
                // only one possible binding during synthesis
                if (Owner.IsTarget)
                {
                    if (!m_alphaVars.GetBinding(m_variables, seg, instantiatedVars))
                    {
                        return(false);
                    }
                }
                else if (mode == ModeType.SYNTHESIS)
                {
                    if (!m_alphaVars.GetBinding(m_variables, seg, instantiatedVars))
                    {
                        // when a variable is specified in a target and environment for agreement, the environment
                        // must specify a feature for each variable
                        foreach (KeyValuePair <string, bool> varPolarity in m_variables)
                        {
                            // check each variable to see which one is not specified in the environment
                            if (!m_alphaVars.GetBinding(varPolarity.Key, varPolarity.Value, seg, new VariableValues(m_alphaVars)))
                            {
                                Feature        f  = m_alphaVars.GetFeature(varPolarity.Key);
                                MorphException me = new MorphException(MorphException.MorphErrorType.UNINSTANTIATED_FEATURE, m_natClass.Morpher,
                                                                       string.Format(HCStrings.kstidUninstEnv, f.ID));
                                me.Data["feature"] = f.ID;
                                throw me;
                            }
                        }
                        return(false);
                    }
                }
                else
                {
                    // during analysis, get all possible bindings, since a feature could
                    // be uninstantiated
                    if (!m_alphaVars.GetAllBindings(m_variables, seg, instantiatedVars))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemple #2
0
            void ApplyInsertion(Direction dir, IList <PhoneticShapeNode> match, VariableValues instantiatedVars)
            {
                PhoneticShapeNode cur = match[match.Count - 1];

                for (PhoneticPatternNode pseqNode = m_rhs.GetFirst(dir); pseqNode != null;
                     pseqNode = pseqNode.GetNext(dir))
                {
                    PhoneticShapeNode newNode = null;
                    switch (pseqNode.Type)
                    {
                    case PhoneticPatternNode.NodeType.SIMP_CTXT:
                        SimpleContext ctxt = pseqNode as SimpleContext;
                        newNode = ctxt.ApplyInsertion(instantiatedVars);
                        break;

                    case PhoneticPatternNode.NodeType.BDRY_CTXT:
                        newNode = new Boundary(pseqNode as BoundaryContext);
                        break;
                    }

                    if (newNode != null)
                    {
                        try
                        {
                            cur.Insert(newNode, dir);
                        }
                        catch (InvalidOperationException ioe)
                        {
                            MorphException me = new MorphException(MorphException.MorphErrorType.TOO_MANY_SEGS, m_rule.Morpher,
                                                                   string.Format(HCStrings.kstidTooManySegs, m_rule.ID), ioe);
                            me.Data["rule"] = m_rule.ID;
                            throw me;
                        }
                        cur = newNode;
                    }
                }
            }
Exemple #3
0
		public virtual void Write(MorphException me)
		{
			m_out.WriteLine("Morph Error: " + me.Message);
			m_out.WriteLine();
		}
			void ApplyInsertion(Direction dir, IList<PhoneticShapeNode> match, VariableValues instantiatedVars)
			{
				PhoneticShapeNode cur = match[match.Count - 1];
				for (PhoneticPatternNode pseqNode = m_rhs.GetFirst(dir); pseqNode != null;
					pseqNode = pseqNode.GetNext(dir))
				{
					PhoneticShapeNode newNode = null;
					switch (pseqNode.Type)
					{
						case PhoneticPatternNode.NodeType.SIMP_CTXT:
							SimpleContext ctxt = pseqNode as SimpleContext;
							newNode = ctxt.ApplyInsertion(instantiatedVars);
							break;

						case PhoneticPatternNode.NodeType.BDRY_CTXT:
							newNode = new Boundary(pseqNode as BoundaryContext);
							break;
					}

					if (newNode != null)
					{
						try
						{
							cur.Insert(newNode, dir);
						}
						catch (InvalidOperationException ioe)
						{
							MorphException me = new MorphException(MorphException.MorphErrorType.TOO_MANY_SEGS, m_rule.Morpher,
								string.Format(HCStrings.kstidTooManySegs, m_rule.ID), ioe);
							me.Data["rule"] = m_rule.ID;
							throw me;
						}
						cur = newNode;
					}
				}
			}
Exemple #5
0
        /// <summary>
        /// Does the real work of morphing the specified word.
        /// </summary>
        /// <param name="word">The word.</param>
        /// <param name="prev">The previous word.</param>
        /// <param name="next">The next word.</param>
        /// <param name="trace">The trace.</param>
        /// <returns>All valid word synthesis records.</returns>
        ICollection <WordSynthesis> MorphAndLookupToken(string word, string prev, string next, out WordAnalysisTrace trace, string[] selectTraceMorphs)
        {
            // convert the word to its phonetic shape
            PhoneticShape input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS);

            // if word contains invalid segments, the char def table will return null
            if (input == null)
            {
                MorphException me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this,
                                                       string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID));
                me.Data["shape"]        = word;
                me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID;
                throw me;
            }

            // create the root of the trace tree
            trace = new WordAnalysisTrace(word, input.Clone());

            Set <WordSynthesis> candidates  = new Set <WordSynthesis>();
            Set <WordAnalysis>  inAnalysis  = new Set <WordAnalysis>();
            Set <WordAnalysis>  outAnalysis = new Set <WordAnalysis>();

            inAnalysis.Add(new WordAnalysis(input, SurfaceStratum, trace));

            // Unapply rules
            for (int i = m_strata.Count - 1; i >= 0; i--)
            {
                outAnalysis.Clear();
                foreach (WordAnalysis wa in inAnalysis)
                {
                    if (m_traceStrataAnalysis)
                    {
                        // create the stratum analysis input trace record
                        StratumAnalysisTrace stratumTrace = new StratumAnalysisTrace(m_strata[i], true, wa.Clone());
                        wa.CurrentTrace.AddChild(stratumTrace);
                    }
                    foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, candidates, selectTraceMorphs))
                    {
                        // promote each analysis to the next stratum
                        if (i != 0)
                        {
                            outWa.Stratum = m_strata[i - 1];
                        }

                        if (m_traceStrataAnalysis)
                        {
                            // create the stratum analysis output trace record for the output word synthesis
                            outWa.CurrentTrace.AddChild(new StratumAnalysisTrace(m_strata[i], false, outWa.Clone()));
                        }

                        outAnalysis.Add(outWa);
                    }
                }

                inAnalysis.Clear();
                inAnalysis.AddMany(outAnalysis);
            }

            Set <WordSynthesis> allValidSyntheses = new Set <WordSynthesis>();

            // Apply rules for each candidate entry
            foreach (WordSynthesis candidate in candidates)
            {
                Set <WordSynthesis> inSynthesis  = new Set <WordSynthesis>();
                Set <WordSynthesis> outSynthesis = new Set <WordSynthesis>();
                for (int i = 0; i < m_strata.Count; i++)
                {
                    // start applying at the stratum that this lex entry belongs to
                    if (m_strata[i] == candidate.Root.Stratum)
                    {
                        inSynthesis.Add(candidate);
                    }

                    outSynthesis.Clear();
                    foreach (WordSynthesis cur in inSynthesis)
                    {
                        if (m_traceStrataSynthesis)
                        {
                            // create the stratum synthesis input trace record
                            StratumSynthesisTrace stratumTrace = new StratumSynthesisTrace(m_strata[i], true, cur.Clone());
                            cur.CurrentTrace.AddChild(stratumTrace);
                        }
                        foreach (WordSynthesis outWs in m_strata[i].Apply(cur))
                        {
                            // promote the word synthesis to the next stratum
                            if (i != m_strata.Count - 1)
                            {
                                outWs.Stratum = m_strata[i + 1];
                            }

                            if (m_traceStrataSynthesis)
                            {
                                // create the stratum synthesis output trace record for the output analysis
                                outWs.CurrentTrace.AddChild(new StratumSynthesisTrace(m_strata[i], false, outWs.Clone()));
                            }

                            outSynthesis.Add(outWs);
                        }
                    }

                    inSynthesis.Clear();
                    inSynthesis.AddMany(outSynthesis);
                }

                foreach (WordSynthesis ws in outSynthesis)
                {
                    if (ws.IsValid)
                    {
                        allValidSyntheses.Add(ws);
                    }
                }
            }

            Set <WordSynthesis> results = new Set <WordSynthesis>();
            // sort the resulting syntheses according to the order of precedence of each allomorph in
            // their respective morphemes
            List <WordSynthesis> sortedSyntheses = new List <WordSynthesis>(allValidSyntheses);

            sortedSyntheses.Sort();

            WordSynthesis prevValidSynthesis = null;

            foreach (WordSynthesis cur in sortedSyntheses)
            {
                // enforce the disjunctive property of allomorphs by ensuring that this word synthesis
                // has the highest order of precedence for its allomorphs while also allowing for free
                // fluctuation, also check that the phonetic shape matches the original input word
                if ((prevValidSynthesis == null || AreAllomorphsNondisjunctive(cur, prevValidSynthesis)) &&
                    SurfaceStratum.CharacterDefinitionTable.IsMatch(word, cur.Shape))
                {
                    if (m_traceSuccess)
                    {
                        // create the report a success output trace record for the output analysis
                        cur.CurrentTrace.AddChild(new ReportSuccessTrace(cur));
                    }
                    // do not add to the result if it has the same root, shape, and morphemes as another result
                    bool duplicate = false;
                    foreach (WordSynthesis ws in results)
                    {
                        if (cur.Duplicates(ws))
                        {
                            duplicate = true;
                            break;
                        }
                    }
                    if (!duplicate)
                    {
                        results.Add(cur);
                    }
                }
                prevValidSynthesis = cur;
            }
            return(results);
        }
Exemple #6
0
		public virtual void Write(MorphException me)
		{
			m_xmlWriter.WriteElementString("MorphError", me.Message);
		}
Exemple #7
0
		/// <summary>
		/// Does the real work of morphing the specified word.
		/// </summary>
		/// <param name="word">The word.</param>
		/// <param name="prev">The previous word.</param>
		/// <param name="next">The next word.</param>
		/// <param name="trace">The trace.</param>
		/// <param name="selectTraceMorphs"></param>
		/// <returns>All valid word synthesis records.</returns>
		ICollection<WordSynthesis> MorphAndLookupToken(string word, string prev, string next, TraceManager trace, string[] selectTraceMorphs)
		{
			PhoneticShape input;
			try
			{
				// convert the word to its phonetic shape; it could throw a missing phonetic shape exception
				input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS);
			}
			catch (MissingPhoneticShapeException mpse)
			{
				var me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this,
					string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID, mpse.Position+1,
									word.Substring(mpse.Position), mpse.PhonemesFoundSoFar));
				me.Data["shape"] = word;
				me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID;
				me.Data["position"] = mpse.Position;
				me.Data["phonemesFoundSoFar"] = mpse.PhonemesFoundSoFar;
				throw me;
			}

			var inputAnalysis = new WordAnalysis(input, SurfaceStratum);

			if (trace != null)
				trace.BeginAnalyzeWord(word, inputAnalysis);

			var candidates = new Set<WordSynthesis>();
			var inAnalysis = new Set<WordAnalysis>();
			var outAnalysis = new Set<WordAnalysis>();
			inAnalysis.Add(inputAnalysis);

			// Unapply rules
			for (int i = m_strata.Count - 1; i >= 0; i--)
			{
				outAnalysis.Clear();
				foreach (WordAnalysis wa in inAnalysis)
				{
					if (trace != null)
						trace.BeginUnapplyStratum(m_strata[i], wa);

					foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, trace, selectTraceMorphs, candidates))
					{
						// promote each analysis to the next stratum
						if (i != 0)
							outWa.Stratum = m_strata[i - 1];

						if (trace != null)
							trace.EndUnapplyStratum(m_strata[i], outWa);

						outAnalysis.Add(outWa);
					}
				}

				inAnalysis.Clear();
				inAnalysis.AddMany(outAnalysis);
			}

			var allValidSyntheses = new Set<WordSynthesis>();
			// Apply rules for each candidate entry
			foreach (WordSynthesis candidate in candidates)
			{
				var inSynthesis = new Set<WordSynthesis>();
				var outSynthesis = new Set<WordSynthesis>();
				for (int i = 0; i < m_strata.Count; i++)
				{
					// start applying at the stratum that this lex entry belongs to
					if (m_strata[i] == candidate.Root.Stratum)
						inSynthesis.Add(candidate);

					outSynthesis.Clear();
					foreach (WordSynthesis cur in inSynthesis)
					{
						if (trace != null)
							trace.BeginApplyStratum(m_strata[i], cur);

						foreach (WordSynthesis outWs in m_strata[i].Apply(cur, trace))
						{
							// promote the word synthesis to the next stratum
							if (i != m_strata.Count - 1)
								outWs.Stratum = m_strata[i + 1];

							if (trace != null)
								trace.EndApplyStratum(m_strata[i], outWs);

							outSynthesis.Add(outWs);
						}
					}

					inSynthesis.Clear();
					inSynthesis.AddMany(outSynthesis);
				}

				foreach (WordSynthesis ws in outSynthesis)
				{
					if (ws.IsValid(trace))
						allValidSyntheses.Add(ws);
				}
			}

			var results = new Set<WordSynthesis>();
			// sort the resulting syntheses according to the order of precedence of each allomorph in
			// their respective morphemes
			var sortedSyntheses = new List<WordSynthesis>(allValidSyntheses);
			sortedSyntheses.Sort();

			WordSynthesis prevValidSynthesis = null;
			bool allFreeFluctuation = true;
			foreach (WordSynthesis cur in sortedSyntheses)
			{
				// enforce the disjunctive property of allomorphs by ensuring that this word synthesis
				// has the highest order of precedence for its allomorphs while also allowing for free
				// fluctuation
				if (prevValidSynthesis == null || AreAllomorphsNondisjunctive(cur, prevValidSynthesis))
				{
					AddResult(word, results, cur, trace);
					allFreeFluctuation = true;
				}
				else if (allFreeFluctuation && CheckFreeFluctuation(cur, prevValidSynthesis))
				{
					AddResult(word, results, cur, trace);
				}
				else
				{
					allFreeFluctuation = false;
				}
				prevValidSynthesis = cur;
			}
			return results;
		} // end MorphAndLookupToken
Exemple #8
0
		protected override bool IsFeatureMatch(Segment seg, VariableValues instantiatedVars, ModeType mode)
		{
			if (!base.IsFeatureMatch(seg, instantiatedVars, mode))
				return false;

			if (m_alphaVars != null)
			{
				// only one possible binding during synthesis
				if (Owner.IsTarget)
				{
					if (!m_alphaVars.GetBinding(m_variables, seg, instantiatedVars))
						return false;
				}
				else if (mode == ModeType.SYNTHESIS)
				{
					if (!m_alphaVars.GetBinding(m_variables, seg, instantiatedVars))
					{
						// when a variable is specified in a target and environment for agreement, the environment
						// must specify a feature for each variable
						foreach (KeyValuePair<string, bool> varPolarity in m_variables)
						{
							// check each variable to see which one is not specified in the environment
							if (!m_alphaVars.GetBinding(varPolarity.Key, varPolarity.Value, seg, new VariableValues(m_alphaVars)))
							{
								Feature f = m_alphaVars.GetFeature(varPolarity.Key);
								MorphException me = new MorphException(MorphException.MorphErrorType.UNINSTANTIATED_FEATURE, m_natClass.Morpher,
									string.Format(HCStrings.kstidUninstEnv, f.ID));
								me.Data["feature"] = f.ID;
								throw me;
							}
						}
						return false;
					}
				}
				else
				{
					// during analysis, get all possible bindings, since a feature could
					// be uninstantiated
					if (!m_alphaVars.GetAllBindings(m_variables, seg, instantiatedVars))
						return false;
				}
			}
			return true;
		}
Exemple #9
0
			public override void Write(MorphException me)
			{
				m_xmlWriter.WriteStartElement("Error");
				switch (me.ErrorType)
				{
					case MorphException.MorphErrorType.INVALID_SHAPE:
						string shape = me.Data["shape"] as string;
						m_xmlWriter.WriteString(string.Format(ParserCoreStrings.ksHCInvalidWordform, shape));
						break;

					case MorphException.MorphErrorType.UNINSTANTIATED_FEATURE:
						string featId = me.Data["feature"] as string;
						Feature feat = me.Morpher.PhoneticFeatureSystem.GetFeature(featId);
						m_xmlWriter.WriteString(string.Format(ParserCoreStrings.ksHCUninstFeature, feat.Description));
						break;

					default:
						m_xmlWriter.WriteString(string.Format(ParserCoreStrings.ksHCDefaultErrorMsg, me.Message));
						break;
				}
				m_xmlWriter.WriteEndElement();
			}
 public virtual void Write(MorphException me)
 {
     m_xmlWriter.WriteElementString("MorphError", me.Message);
 }
Exemple #11
0
 public virtual void Write(MorphException me)
 {
     m_out.WriteLine("Morph Error: " + me.Message);
     m_out.WriteLine();
 }
Exemple #12
0
		private void Write(XmlWriter writer, MorphException me)
		{
			writer.WriteStartElement("Error");
			writer.WriteString(ProcessMorphException(me));
			writer.WriteEndElement();
		}
Exemple #13
0
		private string ProcessMorphException(MorphException me)
		{
			string errorMessage;
			switch (me.ErrorType)
			{
				case MorphException.MorphErrorType.INVALID_SHAPE:
					var shape = (string)me.Data["shape"];
					var position = (int)me.Data["position"];
					var phonemesFoundSoFar = (string)me.Data["phonemesFoundSoFar"];
					string rest = shape.Substring(position);
					string restToUse = rest;
					LgGeneralCharCategory cc = m_cache.ServiceLocator.UnicodeCharProps.get_GeneralCategory(rest[0]);
					if (cc == LgGeneralCharCategory.kccMn)
					{
						// the first character is a diacritic, combining type of character
						// insert a space so it does not show on top of a single quote in the message string
						restToUse = " " + rest;
					}
					errorMessage = String.Format(ParserCoreStrings.ksHCInvalidWordform, shape, position + 1, restToUse, phonemesFoundSoFar);
					break;

				case MorphException.MorphErrorType.UNINSTANTIATED_FEATURE:
					var featId = me.Data["feature"] as string;
					var feat = me.Morpher.PhoneticFeatureSystem.GetFeature(featId);
					errorMessage = String.Format(ParserCoreStrings.ksHCUninstFeature, feat.Description);
					break;

				default:
					errorMessage = String.Format(ParserCoreStrings.ksHCDefaultErrorMsg, me.Message);
					break;
			}
			return errorMessage;
		}
Exemple #14
0
		/// <summary>
		/// Does the real work of morphing the specified word.
		/// </summary>
		/// <param name="word">The word.</param>
		/// <param name="prev">The previous word.</param>
		/// <param name="next">The next word.</param>
		/// <param name="trace">The trace.</param>
		/// <returns>All valid word synthesis records.</returns>
		ICollection<WordSynthesis> MorphAndLookupToken(string word, string prev, string next, out WordAnalysisTrace trace)
		{
			// convert the word to its phonetic shape
			PhoneticShape input = SurfaceStratum.CharacterDefinitionTable.ToPhoneticShape(word, ModeType.ANALYSIS);
			// if word contains invalid segments, the char def table will return null
			if (input == null)
			{
				MorphException me = new MorphException(MorphException.MorphErrorType.INVALID_SHAPE, this,
					string.Format(HCStrings.kstidInvalidWord, word, SurfaceStratum.CharacterDefinitionTable.ID));
				me.Data["shape"] = word;
				me.Data["charDefTable"] = SurfaceStratum.CharacterDefinitionTable.ID;
				throw me;
			}

			// create the root of the trace tree
			trace = new WordAnalysisTrace(word, input.Clone());

			Set<WordSynthesis> candidates = new Set<WordSynthesis>();
			Set<WordAnalysis> inAnalysis = new Set<WordAnalysis>();
			Set<WordAnalysis> outAnalysis = new Set<WordAnalysis>();
			inAnalysis.Add(new WordAnalysis(input, SurfaceStratum, trace));

			// Unapply rules
			for (int i = m_strata.Count - 1; i >= 0; i--)
			{
				outAnalysis.Clear();
				foreach (WordAnalysis wa in inAnalysis)
				{
					if (m_traceStrataAnalysis)
					{
						// create the stratum analysis input trace record
						StratumAnalysisTrace stratumTrace = new StratumAnalysisTrace(m_strata[i], true, wa.Clone());
						wa.CurrentTrace.AddChild(stratumTrace);
					}
					foreach (WordAnalysis outWa in m_strata[i].Unapply(wa, candidates))
					{
						// promote each analysis to the next stratum
						if (i != 0)
							outWa.Stratum = m_strata[i - 1];

						if (m_traceStrataAnalysis)
							// create the stratum analysis output trace record for the output word synthesis
							outWa.CurrentTrace.AddChild(new StratumAnalysisTrace(m_strata[i], false, outWa.Clone()));

						outAnalysis.Add(outWa);
					}
				}

				inAnalysis.Clear();
				inAnalysis.AddMany(outAnalysis);
			}

			Set<WordSynthesis> allValidSyntheses = new Set<WordSynthesis>();
			// Apply rules for each candidate entry
			foreach (WordSynthesis candidate in candidates)
			{
				Set<WordSynthesis> inSynthesis = new Set<WordSynthesis>();
				Set<WordSynthesis> outSynthesis = new Set<WordSynthesis>();
				for (int i = 0; i < m_strata.Count; i++)
				{
					// start applying at the stratum that this lex entry belongs to
					if (m_strata[i] == candidate.Root.Stratum)
						inSynthesis.Add(candidate);

					outSynthesis.Clear();
					foreach (WordSynthesis cur in inSynthesis)
					{
						if (m_traceStrataSynthesis)
						{
							// create the stratum synthesis input trace record
							StratumSynthesisTrace stratumTrace = new StratumSynthesisTrace(m_strata[i], true, cur.Clone());
							cur.CurrentTrace.AddChild(stratumTrace);
						}
						foreach (WordSynthesis outWs in m_strata[i].Apply(cur))
						{
							// promote the word synthesis to the next stratum
							if (i != m_strata.Count - 1)
								outWs.Stratum = m_strata[i + 1];

							if (m_traceStrataSynthesis)
								// create the stratum synthesis output trace record for the output analysis
								outWs.CurrentTrace.AddChild(new StratumSynthesisTrace(m_strata[i], false, outWs.Clone()));

							outSynthesis.Add(outWs);
						}
					}

					inSynthesis.Clear();
					inSynthesis.AddMany(outSynthesis);
				}

				foreach (WordSynthesis ws in outSynthesis)
				{
					if (ws.IsValid)
						allValidSyntheses.Add(ws);
				}
			}

			Set<WordSynthesis> results = new Set<WordSynthesis>();
			// sort the resulting syntheses according to the order of precedence of each allomorph in
			// their respective morphemes
			List<WordSynthesis> sortedSyntheses = new List<WordSynthesis>(allValidSyntheses);
			sortedSyntheses.Sort();

			WordSynthesis prevValidSynthesis = null;
			foreach (WordSynthesis cur in sortedSyntheses)
			{
				// enforce the disjunctive property of allomorphs by ensuring that this word synthesis
				// has the highest order of precedence for its allomorphs, also check that the phonetic
				// shape matches the original input word
				if ((prevValidSynthesis == null || !cur.Morphs.SameMorphemes(prevValidSynthesis.Morphs))
					&& SurfaceStratum.CharacterDefinitionTable.IsMatch(word, cur.Shape))
				{
					if (m_traceSuccess)
						// create the report a success output trace record for the output analysis
						cur.CurrentTrace.AddChild(new ReportSuccessTrace(cur));
					// do not add to the result if it has the same root, shape, and morphemes as another result
					bool duplicate = false;
					foreach (WordSynthesis ws in results)
					{
						if (cur.Duplicates(ws))
						{
							duplicate = true;
							break;
						}
					}
					if (!duplicate)
					{
						results.Add(cur);
					}
				}
				prevValidSynthesis = cur;
			}
			return results;
		}